@lobehub/chat 0.92.0 → 0.94.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 (48) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/docs/Deploy-with-Azure-OpenAI.md +3 -3
  3. package/locales/en_US/chat.json +10 -10
  4. package/locales/en_US/setting.json +7 -0
  5. package/locales/ja_JP/setting.json +7 -0
  6. package/locales/ko_KR/setting.json +7 -0
  7. package/locales/ru_RU/common.json +2 -1
  8. package/locales/ru_RU/setting.json +7 -0
  9. package/locales/zh_CN/setting.json +7 -0
  10. package/locales/zh_TW/setting.json +7 -0
  11. package/package.json +5 -4
  12. package/scripts/i18nWorkflow/utils.ts +4 -1
  13. package/src/app/chat/features/Conversation/ChatList/Actions/customAction.ts +6 -4
  14. package/src/app/chat/features/Conversation/ChatList/index.tsx +21 -14
  15. package/src/app/chat/features/TopicListContent/SystemRole/index.tsx +4 -1
  16. package/src/app/chat/settings/(desktop)/{Header/Desktop.tsx → features/Header.tsx} +4 -3
  17. package/src/app/chat/settings/(desktop)/layout.desktop.tsx +1 -1
  18. package/src/app/chat/settings/{components/Header/Mobile.tsx → (mobile)/features/Header.tsx} +4 -3
  19. package/src/app/chat/settings/(mobile)/layout.mobile.tsx +1 -1
  20. package/src/app/chat/settings/{components/Header/index.tsx → features/HeaderContent.tsx} +11 -3
  21. package/src/app/chat/settings/features/SubmitAgentButton/Inner.tsx +86 -0
  22. package/src/app/chat/settings/features/SubmitAgentButton/index.tsx +37 -0
  23. package/src/app/chat/settings/features/SubmitAgentButton/style.ts +46 -0
  24. package/src/app/market/features/AgentSearchBar/index.tsx +6 -3
  25. package/src/chains/langDetect.ts +31 -0
  26. package/src/chains/pickEmoji.ts +31 -0
  27. package/src/chains/summaryAgentName.ts +30 -0
  28. package/src/chains/summaryDescription.ts +26 -0
  29. package/src/chains/summaryTags.ts +27 -0
  30. package/src/chains/summaryTitle.ts +32 -0
  31. package/src/chains/translate.ts +17 -0
  32. package/src/components/HotKeys/index.tsx +2 -2
  33. package/src/components/ResponsiveIndex/index.tsx +4 -2
  34. package/src/const/url.ts +1 -0
  35. package/src/features/AgentInfo/index.tsx +69 -0
  36. package/src/features/AgentSetting/AgentMeta/AutoGenerateSelect.tsx +48 -0
  37. package/src/features/AgentSetting/AgentMeta/index.tsx +16 -5
  38. package/src/features/AgentSetting/store/action.ts +66 -12
  39. package/src/locales/default/chat.ts +0 -1
  40. package/src/locales/default/setting.ts +8 -0
  41. package/src/locales/resources/index.ts +0 -1
  42. package/src/store/session/slices/chat/actions/topic.ts +1 -1
  43. package/src/store/session/slices/chat/actions/translate.ts +2 -1
  44. package/src/store/session/slices/session/reducers/session.ts +1 -1
  45. package/src/app/chat/settings/(desktop)/Header/index.tsx +0 -13
  46. package/src/app/chat/settings/(mobile)/Header.tsx +0 -12
  47. package/src/chains/agent.ts +0 -76
  48. package/src/chains/chat.ts +0 -77
package/CHANGELOG.md CHANGED
@@ -2,6 +2,64 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ## [Version 0.94.0](https://github.com/lobehub/lobe-chat/compare/v0.93.0...v0.94.0)
6
+
7
+ <sup>Released on **2023-10-18**</sup>
8
+
9
+ #### ✨ Features
10
+
11
+ - **misc**: Add agent share.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### What's improved
19
+
20
+ - **misc**: Add agent share ([953d7c7](https://github.com/lobehub/lobe-chat/commit/953d7c7))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
30
+ ## [Version 0.93.0](https://github.com/lobehub/lobe-chat/compare/v0.92.0...v0.93.0)
31
+
32
+ <sup>Released on **2023-10-18**</sup>
33
+
34
+ #### ♻ Code Refactoring
35
+
36
+ - **misc**: Refactor chain.
37
+
38
+ #### ✨ Features
39
+
40
+ - **misc**: Support multi-language translate.
41
+
42
+ <br/>
43
+
44
+ <details>
45
+ <summary><kbd>Improvements and Fixes</kbd></summary>
46
+
47
+ #### Code refactoring
48
+
49
+ - **misc**: Refactor chain ([49c4863](https://github.com/lobehub/lobe-chat/commit/49c4863))
50
+
51
+ #### What's improved
52
+
53
+ - **misc**: Support multi-language translate ([548bc5d](https://github.com/lobehub/lobe-chat/commit/548bc5d))
54
+
55
+ </details>
56
+
57
+ <div align="right">
58
+
59
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
60
+
61
+ </div>
62
+
5
63
  ## [Version 0.92.0](https://github.com/lobehub/lobe-chat/compare/v0.91.0...v0.92.0)
6
64
 
7
65
  <sup>Released on **2023-10-18**</sup>
@@ -27,7 +27,7 @@ You can fill in the corresponding configuration items as needed:
27
27
 
28
28
  - **APIKey**: The API key you applied for on the Azure OpenAI account page, which can be found in the "Keys and Endpoints" section.
29
29
  - **API Address**: Azure API address, which can be found in the "Keys and Endpoints" section when checking resources from the Azure portal.
30
- - **Azure Api Version**: The API version of Azure, which follows the YYYY-MM-DD format, refer to the [latest version][azure-api-verion-url].
30
+ - **Azure Api Version**: The API version of Azure, which follows the YYYY-MM-DD format, refer to the [latest version][azure-api-version-url].
31
31
 
32
32
  After completing the above field configuration, click on "Check". If the prompt says "Check Passed", it means the configuration was successful.
33
33
 
@@ -42,12 +42,12 @@ If you want the deployed version to be directly configured with Azure OpenAI for
42
42
  | `USE_AZURE_OPENAI` | Yes | Set this value to `1` to enable Azure OpenAI configuration | - | `1` |
43
43
  | `AZURE_API_KEY` | Yes | This is the API key you applied for on the Azure OpenAI account page | - | `c55168be3874490ef0565d9779ecd5a6` |
44
44
  | `OPENAI_PROXY_URL` | Yes | Azure API address, can be found in the "Keys and Endpoints" section | - | `https://docs-test-001.openai.azure.com` |
45
- | `AZURE_API_VERSION` | No | Azure's API version, follows the YYYY-MM-DD format | 2023-08-01-preview | `2023-05-15`, refer to [latest version][azure-api-verion-url] |
45
+ | `AZURE_API_VERSION` | No | Azure's API version, follows the YYYY-MM-DD format | 2023-08-01-preview | `2023-05-15`, refer to [latest version][azure-api-version-url] |
46
46
  | `ACCESS_CODE` | No | Add a password to access this service, the password should be 6 digits or letters | - | `awCT74` or `e3@09!` |
47
47
 
48
48
  > **Note**\
49
49
  > When you enable `USE_AZURE_OPENAI` on the server side, users will not be able to modify and use the OpenAI key in the front-end configuration.
50
50
 
51
- [azure-api-verion-url]: https://learn.microsoft.com/zh-cn/azure/ai-services/openai/reference#chat-completions
51
+ [azure-api-version-url]: https://learn.microsoft.com/zh-cn/azure/ai-services/openai/reference#chat-completions
52
52
  [azure-openai-url]: https://learn.microsoft.com/zh-cn/azure/ai-services/openai/concepts/models
53
53
  [rfc]: https://github.com/lobehub/lobe-chat/discussions/178
@@ -1,23 +1,23 @@
1
1
  {
2
- "agentDefaultMessage": "Hello, I'm **{{name}}**. You can start chatting with me right away or go to [Assistant Settings](/chat/settings#session={{id}}) to improve my information.",
2
+ "agentDefaultMessage": "Hello, I'm **{{name}}**. You can start chatting with me right away or go to [Agent Settings](/chat/settings#session={{id}}) to improve my information.",
3
3
  "agentDefaultMessageWithSystemRole": "Hello, I'm **{{name}}**, {{systemRole}}. Let's start the conversation!",
4
4
  "backToBottom": "Go to Latest Messages",
5
5
  "clearCurrentMessages": "Clear Current Session Messages",
6
6
  "confirmClearCurrentMessages": "You are about to clear the current session messages. Once cleared, they cannot be recovered. Please confirm your operation.",
7
- "confirmRemoveSessionItemAlert": "You are about to delete this assistant. Once deleted, it cannot be recovered. Please confirm your operation.",
8
- "defaultAgent": "Custom Assistant",
9
- "defaultSession": "Custom Assistant",
7
+ "confirmRemoveSessionItemAlert": "You are about to delete this agent. Once deleted, it cannot be recovered. Please confirm your operation.",
8
+ "defaultAgent": "Custom Agent",
9
+ "defaultSession": "Custom Agent",
10
10
  "historyRange": "History Range",
11
11
  "inbox": {
12
- "defaultMessage": "Hello, I'm your intelligent assistant. You can ask me any questions, and I will do my best to answer you. If you need a more professional or customized assistant, you can click on `+` to create a custom assistant.",
13
- "desc": "Activate brain clusters and spark thinking. Your intelligent assistant is here to communicate with you about everything.",
12
+ "defaultMessage": "Hello, I'm your intelligent agent. You can ask me any questions, and I will do my best to answer you. If you need a more professional or customized agent, you can click on `+` to create a custom agent.",
13
+ "desc": "Activate brain clusters and spark thinking. Your intelligent agent is here to communicate with you about everything.",
14
14
  "title": "Chat Randomly"
15
15
  },
16
- "newAgent": "Create New Assistant",
16
+ "newAgent": "Create New Agent",
17
17
  "noDescription": "No description available",
18
18
  "regenerate": "Regenerate",
19
19
  "roleAndArchive": "Roles and Archives",
20
- "searchAgentPlaceholder": "Search assistants and conversations...",
20
+ "searchAgentPlaceholder": "Search agents and conversations...",
21
21
  "send": "Send",
22
22
  "sendPlaceholder": "Enter chat content...",
23
23
  "shareModal": {
@@ -29,7 +29,7 @@
29
29
  "withBackground": "Include Background Image",
30
30
  "withFooter": "Include Footer",
31
31
  "withPluginInfo": "Include Plugin Information",
32
- "withSystemRole": "Include Assistant Role Setting"
32
+ "withSystemRole": "Include Agent Role Setting"
33
33
  },
34
34
  "stop": "Stop",
35
35
  "temp": "Temporary",
@@ -50,6 +50,6 @@
50
50
  "clear": "Clear Translation"
51
51
  },
52
52
  "translateTo": "Translate",
53
- "updateAgent": "Update Assistant Information",
53
+ "updateAgent": "Update Agent Information",
54
54
  "warp": "Line Break"
55
55
  }
@@ -235,6 +235,13 @@
235
235
  },
236
236
  "title": "Theme Settings"
237
237
  },
238
+ "submitAgentModal": {
239
+ "tooltips": "Share to Assistant Market",
240
+ "button": "Submit Assistant",
241
+ "identifier": "Identifier",
242
+ "metaMiss": "Please complete the assistant information before submitting. It should include name, description, and tags.",
243
+ "placeholder": "Please enter a unique identifier for the assistant, such as web-development."
244
+ },
238
245
  "tab": {
239
246
  "agent": "Default Agent",
240
247
  "common": "Common Settings",
@@ -222,6 +222,13 @@
222
222
  },
223
223
  "title": "テーマ設定"
224
224
  },
225
+ "submitAgentModal": {
226
+ "tooltips": "アシスタントマーケットに共有する",
227
+ "button": "助手を提出する",
228
+ "identifier": "識別子 エージェントの識別子",
229
+ "metaMiss": "エージェント情報を入力してから提出してください。名前、説明、およびタグが必要です",
230
+ "placeholder": "エージェントの識別子を入力してください。一意である必要があります。例:web-development"
231
+ },
225
232
  "tab": {
226
233
  "agent": "デフォルトのアシスタント",
227
234
  "common": "一般設定",
@@ -222,6 +222,13 @@
222
222
  },
223
223
  "title": "테마 설정"
224
224
  },
225
+ "submitAgentModal": {
226
+ "tooltips": "도우미 마켓에 공유",
227
+ "button": "도우미 제출",
228
+ "identifier": "식별자 도우미 식별자",
229
+ "metaMiss": "도우미 정보를 입력한 후 제출하세요. 이름, 설명 및 태그를 포함해야 합니다.",
230
+ "placeholder": "도우미의 식별자를 입력하세요. 고유해야 하며, 예를 들어 web-development과 같은 형식이어야 합니다."
231
+ },
225
232
  "tab": {
226
233
  "agent": "기본 도우미",
227
234
  "common": "일반 설정",
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "about": "Наш Github",
3
3
  "advanceSettings": "Дополнительные настройки",
4
- "agentDefaultMessage": "Здравствуйте, я **{{name}}**. Вы можете начать общаться со мной прямо сейчас или перейти на [Assistant Settings](/chat/settings#session={{id}}) для моей настройки.",
4
+ "agentDefaultMessage": "Здравствуйте, я **{{name}}**. Вы можете начать общаться со мной прямо сейчас или перейти на [Agent Settings](/chat/settings#session={{id}}) для моей настройки.",
5
+ "agentMaxToken": "Максимальная длина сессии",
5
6
  "agentModel": "Модель",
6
7
  "agentProfile": "Информация о помощнике",
7
8
  "appInitializing": "LobeChat запускается, пожалуйста, подождите...",
@@ -235,6 +235,13 @@
235
235
  },
236
236
  "title": "Настройки темы"
237
237
  },
238
+ "submitAgentModal": {
239
+ "tooltips": "Поделиться на рынке помощников",
240
+ "button": "Отправить агента",
241
+ "identifier": "Идентификатор агента",
242
+ "metaMiss": "Пожалуйста, заполните информацию об агенте перед отправкой. Необходимо указать имя, описание и метки",
243
+ "placeholder": "Введите идентификатор агента, который должен быть уникальным, например, web-development"
244
+ },
238
245
  "tab": {
239
246
  "agent": "Помощник по умолчанию",
240
247
  "common": "Общие настройки",
@@ -222,6 +222,13 @@
222
222
  },
223
223
  "title": "主题设置"
224
224
  },
225
+ "submitAgentModal": {
226
+ "button": "提交助手",
227
+ "identifier": "identifier 助手标识符",
228
+ "metaMiss": "请补全助手信息后提交,需要包含名称、描述和标签",
229
+ "placeholder": "请输入助手的标识符,需要是唯一的,比如 web-development",
230
+ "tooltips": "分享到助手市场"
231
+ },
225
232
  "tab": {
226
233
  "agent": "默认助手",
227
234
  "common": "通用设置",
@@ -235,6 +235,13 @@
235
235
  },
236
236
  "title": "主題設定"
237
237
  },
238
+ "submitAgentModal": {
239
+ "tooltips": "分享到助手市場",
240
+ "button": "提交助手",
241
+ "identifier": "助手識別符",
242
+ "metaMiss": "請補全助手資訊後提交,需要包含名稱、描述和標籤",
243
+ "placeholder": "請輸入助手的識別符,需要是唯一的,例如 web-development"
244
+ },
238
245
  "tab": {
239
246
  "agent": "預設助理",
240
247
  "common": "通用設定",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "0.92.0",
3
+ "version": "0.94.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",
@@ -69,7 +69,7 @@
69
69
  "@emoji-mart/data": "^1",
70
70
  "@emoji-mart/react": "^1",
71
71
  "@icons-pack/react-simple-icons": "^9",
72
- "@lobehub/chat-plugin-sdk": "^1.17.8",
72
+ "@lobehub/chat-plugin-sdk": "latest",
73
73
  "@lobehub/chat-plugins-gateway": "latest",
74
74
  "@lobehub/ui": "latest",
75
75
  "@vercel/analytics": "^1",
@@ -79,7 +79,7 @@
79
79
  "antd-style": "^3.5",
80
80
  "brotli-wasm": "^1",
81
81
  "chroma-js": "^2",
82
- "copy-to-clipboard": "^3.3.3",
82
+ "copy-to-clipboard": "^3",
83
83
  "dayjs": "^1",
84
84
  "emoji-mart": "^5",
85
85
  "fast-deep-equal": "^3",
@@ -98,6 +98,7 @@
98
98
  "openai": "^4.10.0",
99
99
  "polished": "^4",
100
100
  "posthog-js": "^1",
101
+ "query-string": "^8",
101
102
  "react": "^18",
102
103
  "react-dom": "^18",
103
104
  "react-hotkeys-hook": "^4",
@@ -146,7 +147,7 @@
146
147
  "eslint": "^8",
147
148
  "husky": "^8",
148
149
  "jsdom": "^22",
149
- "lint-staged": "^15.0.0",
150
+ "lint-staged": "^15",
150
151
  "lodash": "^4",
151
152
  "next-pwa": "^5",
152
153
  "node-fetch": "^3",
@@ -13,9 +13,12 @@ export const readJSON = (filePath: string) => {
13
13
  return JSON.parse(data);
14
14
  };
15
15
 
16
+ export const replaceAssistantToAgent = (text: string) =>
17
+ text.replaceAll('assistant', 'agent').replaceAll('Assistant', 'Agent');
18
+
16
19
  export const writeJSON = (filePath: string, data: any) => {
17
20
  const jsonStr = JSON.stringify(data, null, 2);
18
- writeFileSync(filePath, jsonStr, 'utf8');
21
+ writeFileSync(filePath, replaceAssistantToAgent(jsonStr), 'utf8');
19
22
  };
20
23
 
21
24
  export const genResourcesContent = (locales: string[]) => {
@@ -2,14 +2,16 @@ import { ActionIconGroupItems } from '@lobehub/ui/es/ActionIconGroup';
2
2
  import { LanguagesIcon } from 'lucide-react';
3
3
  import { useTranslation } from 'react-i18next';
4
4
 
5
+ import { localeOptions } from '@/locales/options';
6
+
5
7
  export const useCustomActions = () => {
6
8
  const { t } = useTranslation('chat');
7
9
 
8
10
  const translate = {
9
- // children: localeOptions.map((i) => ({
10
- // key: i.value,
11
- // label: t(`lang.${i.value}`, { ns: 'common' }),
12
- // })),
11
+ children: localeOptions.map((i) => ({
12
+ key: i.value,
13
+ label: t(`lang.${i.value}`, { ns: 'common' }),
14
+ })),
13
15
  icon: LanguagesIcon,
14
16
  key: 'translate',
15
17
  label: t('translateTo'),
@@ -5,7 +5,6 @@ import { useHotkeys } from 'react-hotkeys-hook';
5
5
  import { useTranslation } from 'react-i18next';
6
6
 
7
7
  import { PREFIX_KEY, REGENERATE_KEY } from '@/const/hotkeys';
8
- import { settingsSelectors, useGlobalStore } from '@/store/global';
9
8
  import { useSessionChatInit, useSessionStore } from '@/store/session';
10
9
  import { agentSelectors, chatSelectors } from '@/store/session/selectors';
11
10
 
@@ -43,14 +42,11 @@ const List = memo(() => {
43
42
  ];
44
43
  });
45
44
 
46
- const targetLang = useGlobalStore(settingsSelectors.currentLanguage);
47
-
48
45
  const hotkeys = [PREFIX_KEY, REGENERATE_KEY].join('+');
49
46
 
50
47
  useHotkeys(
51
48
  hotkeys,
52
49
  () => {
53
- console.log(111);
54
50
  const lastMessage = data.at(-1);
55
51
  if (!lastMessage || lastMessage.id === 'default' || lastMessage.role === 'system') return;
56
52
  resendMessage(lastMessage.id);
@@ -68,17 +64,28 @@ const List = memo(() => {
68
64
  enableHistoryCount={enableHistoryCount}
69
65
  historyCount={historyCount}
70
66
  loadingId={chatLoadingId}
71
- onActionsClick={{
72
- del: ({ id }) => deleteMessage(id),
73
- regenerate: ({ id, error }) => {
74
- resendMessage(id);
67
+ onActionsClick={(action, { id, error }) => {
68
+ switch (action.key) {
69
+ case 'del': {
70
+ deleteMessage(id);
71
+ break;
72
+ }
73
+ case 'regenerate': {
74
+ resendMessage(id);
75
+
76
+ // if this message is an error message, we need to delete it
77
+ if (error) deleteMessage(id);
78
+ break;
79
+ }
80
+ }
75
81
 
76
- // if this message is an error message, we need to delete it
77
- if (error) deleteMessage(id);
78
- },
79
- translate: ({ id }) => {
80
- translateMessage(id, targetLang);
81
- },
82
+ // click the menu item with translate item, the result is:
83
+ // key: 'en-US'
84
+ // keyPath: ['en-US','translate']
85
+ if (action.keyPath.at(-1) === 'translate') {
86
+ const lang = action.keyPath[0];
87
+ translateMessage(id, lang);
88
+ }
82
89
  }}
83
90
  onMessageChange={(id, content) =>
84
91
  dispatchMessage({ id, key: 'content', type: 'updateMessage', value: content })
@@ -5,6 +5,7 @@ import { memo, useState } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
6
6
  import { Flexbox } from 'react-layout-kit';
7
7
 
8
+ import AgentInfo from '@/features/AgentInfo';
8
9
  import { useSessionChatInit, useSessionStore } from '@/store/session';
9
10
  import { agentSelectors } from '@/store/session/selectors';
10
11
 
@@ -15,8 +16,9 @@ const SystemRole = memo(() => {
15
16
  const [openModal, setOpenModal] = useState(false);
16
17
  const [editing, setEditing] = useState(false);
17
18
  const { styles } = useStyles();
18
- const [systemRole, updateAgentConfig] = useSessionStore((s) => [
19
+ const [systemRole, meta, updateAgentConfig] = useSessionStore((s) => [
19
20
  agentSelectors.currentAgentSystemRole(s),
21
+ agentSelectors.currentAgentMeta(s),
20
22
  s.updateAgentConfig,
21
23
  ]);
22
24
 
@@ -57,6 +59,7 @@ const SystemRole = memo(() => {
57
59
  <EditableMessage
58
60
  classNames={{ markdown: styles.prompt }}
59
61
  editing={editing}
62
+ model={{ extra: <AgentInfo meta={meta} style={{ marginBottom: 16 }} /> }}
60
63
  onChange={(e) => {
61
64
  updateAgentConfig({ systemRole: e });
62
65
  }}
@@ -1,11 +1,12 @@
1
1
  import { ChatHeader, ChatHeaderTitle } from '@lobehub/ui';
2
2
  import { useRouter } from 'next/navigation';
3
- import { ReactNode, memo } from 'react';
3
+ import { memo } from 'react';
4
4
  import { useTranslation } from 'react-i18next';
5
5
 
6
+ import HeaderContent from '@/app/chat/settings/features/HeaderContent';
6
7
  import { pathString } from '@/utils/url';
7
8
 
8
- const Header = memo<{ children: ReactNode }>(({ children }) => {
9
+ const Header = memo(() => {
9
10
  const { t } = useTranslation('setting');
10
11
  const router = useRouter();
11
12
 
@@ -13,7 +14,7 @@ const Header = memo<{ children: ReactNode }>(({ children }) => {
13
14
  <ChatHeader
14
15
  left={<ChatHeaderTitle title={t('header.session')} />}
15
16
  onBackClick={() => router.push(pathString('/chat', { hash: location.hash }))}
16
- right={children}
17
+ right={<HeaderContent />}
17
18
  showBackButton
18
19
  />
19
20
  );
@@ -5,7 +5,7 @@ import SafeSpacing from '@/components/SafeSpacing';
5
5
  import { HEADER_HEIGHT } from '@/const/layoutTokens';
6
6
 
7
7
  import Layout from '../../(desktop)/layout.desktop';
8
- import Header from './Header';
8
+ import Header from './features/Header';
9
9
 
10
10
  export default memo(({ children }: PropsWithChildren) => (
11
11
  <Layout>
@@ -1,11 +1,12 @@
1
1
  import { MobileNavBar, MobileNavBarTitle } from '@lobehub/ui';
2
2
  import { useRouter } from 'next/navigation';
3
- import { type ReactNode, memo } from 'react';
3
+ import { memo } from 'react';
4
4
  import { useTranslation } from 'react-i18next';
5
5
 
6
+ import HeaderContent from '@/app/chat/settings/features/HeaderContent';
6
7
  import { pathString } from '@/utils/url';
7
8
 
8
- const Header = memo<{ children: ReactNode }>(({ children }) => {
9
+ const Header = memo(() => {
9
10
  const { t } = useTranslation('setting');
10
11
  const router = useRouter();
11
12
 
@@ -13,7 +14,7 @@ const Header = memo<{ children: ReactNode }>(({ children }) => {
13
14
  <MobileNavBar
14
15
  center={<MobileNavBarTitle title={t('header.session')} />}
15
16
  onBackClick={() => router.push(pathString('/chat/mobile', { hash: location.hash }))}
16
- right={children}
17
+ right={<HeaderContent />}
17
18
  showBackButton
18
19
  />
19
20
  );
@@ -2,7 +2,7 @@ import { PropsWithChildren, memo } from 'react';
2
2
 
3
3
  import AppLayoutMobile from '@/layout/AppLayout.mobile';
4
4
 
5
- import Header from './Header';
5
+ import Header from './features/Header';
6
6
 
7
7
  export default memo(({ children }: PropsWithChildren) => (
8
8
  <AppLayoutMobile navBar={<Header />}>{children}</AppLayoutMobile>
@@ -9,9 +9,12 @@ import { MOBILE_HEADER_ICON_SIZE } from '@/const/layoutTokens';
9
9
  import { exportSingleAgent, exportSingleSession } from '@/helpers/export';
10
10
  import { useSessionStore } from '@/store/session';
11
11
 
12
+ import SubmitAgentButton from './SubmitAgentButton';
13
+
12
14
  export const HeaderContent = memo<{ mobile?: boolean }>(() => {
13
15
  const { t } = useTranslation('setting');
14
16
  const id = useSessionStore((s) => s.activeId);
17
+
15
18
  const { mobile } = useResponsive();
16
19
 
17
20
  const items = useMemo<MenuProps['items']>(
@@ -41,8 +44,13 @@ export const HeaderContent = memo<{ mobile?: boolean }>(() => {
41
44
  const size = mobile ? MOBILE_HEADER_ICON_SIZE : { fontSize: 24 };
42
45
 
43
46
  return (
44
- <Dropdown arrow={false} menu={{ items }} trigger={['click']}>
45
- <ActionIcon icon={HardDriveDownload} size={size} title={t('export', { ns: 'common' })} />
46
- </Dropdown>
47
+ <>
48
+ <SubmitAgentButton />
49
+ <Dropdown arrow={false} menu={{ items }} trigger={['click']}>
50
+ <ActionIcon icon={HardDriveDownload} size={size} title={t('export', { ns: 'common' })} />
51
+ </Dropdown>
52
+ </>
47
53
  );
48
54
  });
55
+
56
+ export default HeaderContent;
@@ -0,0 +1,86 @@
1
+ import { Alert, Button, Divider, Input } from 'antd';
2
+ import { useTheme } from 'antd-style';
3
+ import isEqual from 'fast-deep-equal';
4
+ import { kebabCase } from 'lodash-es';
5
+ import qs from 'query-string';
6
+ import { memo, useState } from 'react';
7
+ import { useTranslation } from 'react-i18next';
8
+ import { Flexbox } from 'react-layout-kit';
9
+
10
+ import MobilePadding from '@/components/MobilePadding';
11
+ import { AGENTS_INDEX_GITHUB_ISSUE } from '@/const/url';
12
+ import AgentInfo from '@/features/AgentInfo';
13
+ import { useGlobalStore } from '@/store/global';
14
+ import { useSessionStore } from '@/store/session';
15
+ import { agentSelectors } from '@/store/session/slices/agentConfig';
16
+
17
+ const Inner = memo(() => {
18
+ const { t } = useTranslation('setting');
19
+ const [identifier, setIdentifier] = useState('');
20
+ const systemRole = useSessionStore(agentSelectors.currentAgentSystemRole);
21
+ const theme = useTheme();
22
+ const meta = useSessionStore(agentSelectors.currentAgentMeta, isEqual);
23
+ const language = useGlobalStore((s) => s.settings.language);
24
+
25
+ const isMetaPass = Boolean(
26
+ meta && meta.title && meta.description && (meta.tags as string[])?.length > 0 && meta.avatar,
27
+ );
28
+
29
+ const handleSubmit = () => {
30
+ const body = [
31
+ '### systemRole',
32
+ systemRole,
33
+ '### identifier',
34
+ identifier,
35
+ '### avatar',
36
+ meta.avatar,
37
+ '### title',
38
+ meta.title,
39
+ '### description',
40
+ meta.description,
41
+ '### tags',
42
+ (meta.tags as string[]).join(', '),
43
+ '### locale',
44
+ language === 'auto' ? navigator.language : language,
45
+ ].join('\n\n');
46
+
47
+ const url = qs.stringifyUrl({
48
+ query: { body, labels: '🤖 Agent PR', title: `[Agent] ${meta.title}` },
49
+ url: AGENTS_INDEX_GITHUB_ISSUE,
50
+ });
51
+
52
+ window.open(url, '_blank');
53
+ };
54
+
55
+ return (
56
+ <Flexbox gap={16}>
57
+ <MobilePadding>
58
+ {!isMetaPass && (
59
+ <Alert message={t('submitAgentModal.metaMiss')} showIcon type={'warning'} />
60
+ )}
61
+ <AgentInfo meta={meta} systemRole={systemRole} />
62
+ <Divider style={{ margin: '8px 0' }} />
63
+ <strong>
64
+ <span style={{ color: theme.colorError, marginRight: 4 }}>*</span>
65
+ {t('submitAgentModal.identifier')}
66
+ </strong>
67
+ <Input
68
+ onChange={(e) => setIdentifier(kebabCase(e.target.value))}
69
+ placeholder={t('submitAgentModal.placeholder')}
70
+ value={identifier}
71
+ />
72
+ <Button
73
+ block
74
+ disabled={!isMetaPass || !identifier}
75
+ onClick={handleSubmit}
76
+ size={'large'}
77
+ type={'primary'}
78
+ >
79
+ {t('submitAgentModal.button')}
80
+ </Button>
81
+ </MobilePadding>
82
+ </Flexbox>
83
+ );
84
+ });
85
+
86
+ export default Inner;
@@ -0,0 +1,37 @@
1
+ import { ActionIcon, Modal } from '@lobehub/ui';
2
+ import { useResponsive } from 'antd-style';
3
+ import { Share2 } from 'lucide-react';
4
+ import { memo, useState } from 'react';
5
+ import { useTranslation } from 'react-i18next';
6
+
7
+ import { MOBILE_HEADER_ICON_SIZE } from '@/const/layoutTokens';
8
+
9
+ import Inner from './Inner';
10
+
11
+ const SubmitAgentButton = memo(() => {
12
+ const { t } = useTranslation('setting');
13
+ const { mobile } = useResponsive();
14
+ const [isModalOpen, setIsModalOpen] = useState(false);
15
+ const size = mobile ? MOBILE_HEADER_ICON_SIZE : { fontSize: 24 };
16
+ return (
17
+ <>
18
+ <ActionIcon
19
+ icon={Share2}
20
+ onClick={() => setIsModalOpen(true)}
21
+ size={size}
22
+ title={t('submitAgentModal.tooltips')}
23
+ />
24
+ <Modal
25
+ centered={false}
26
+ footer={null}
27
+ onCancel={() => setIsModalOpen(false)}
28
+ open={isModalOpen}
29
+ title={t('submitAgentModal.tooltips')}
30
+ >
31
+ <Inner />
32
+ </Modal>
33
+ </>
34
+ );
35
+ });
36
+
37
+ export default SubmitAgentButton;