@lobehub/chat 0.1.6

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 (149) hide show
  1. package/.changelogrc.js +1 -0
  2. package/.commitlintrc.js +1 -0
  3. package/.editorconfig +16 -0
  4. package/.eslintignore +32 -0
  5. package/.eslintrc.js +6 -0
  6. package/.github/ISSUE_TEMPLATE/1_bug_report.yml +45 -0
  7. package/.github/ISSUE_TEMPLATE/2_feature_request.yml +21 -0
  8. package/.github/ISSUE_TEMPLATE/3_question.yml +15 -0
  9. package/.github/ISSUE_TEMPLATE/4_other.md +7 -0
  10. package/.github/PULL_REQUEST_TEMPLATE.md +17 -0
  11. package/.github/dependabot.yml +17 -0
  12. package/.github/workflows/auto-merge.yml +32 -0
  13. package/.github/workflows/contributor-help.yml +29 -0
  14. package/.github/workflows/issue-check-inactive.yml +22 -0
  15. package/.github/workflows/issue-close-require.yml +46 -0
  16. package/.github/workflows/issue-remove-inactive.yml +25 -0
  17. package/.github/workflows/release.yml +34 -0
  18. package/.github/workflows/test.yml +30 -0
  19. package/.gitpod.yml +3 -0
  20. package/.husky/commit-msg +4 -0
  21. package/.husky/pre-commit +5 -0
  22. package/.i18nrc.js +13 -0
  23. package/.prettierignore +63 -0
  24. package/.prettierrc.js +1 -0
  25. package/.releaserc.js +1 -0
  26. package/.remarkrc.js +1 -0
  27. package/.stylelintrc.js +8 -0
  28. package/CHANGELOG.md +20 -0
  29. package/README.md +147 -0
  30. package/locales/en_US/common.json +41 -0
  31. package/locales/en_US/setting.json +117 -0
  32. package/locales/zh_CN/common.json +41 -0
  33. package/locales/zh_CN/setting.json +117 -0
  34. package/next.config.mjs +32 -0
  35. package/package.json +140 -0
  36. package/public/next.svg +1 -0
  37. package/public/vercel.svg +1 -0
  38. package/scripts/genDefaultLocale.ts +18 -0
  39. package/scripts/genResources.ts +51 -0
  40. package/scripts/toc.ts +7 -0
  41. package/src/const/fetch.ts +1 -0
  42. package/src/const/modelTokens.ts +8 -0
  43. package/src/features/AvatarWithUpload/index.tsx +27 -0
  44. package/src/features/FolderPanel/index.tsx +55 -0
  45. package/src/features/SideBar/index.tsx +35 -0
  46. package/src/helpers/prompt.test.ts +36 -0
  47. package/src/helpers/prompt.ts +36 -0
  48. package/src/helpers/url.ts +17 -0
  49. package/src/layout/index.tsx +57 -0
  50. package/src/layout/style.ts +18 -0
  51. package/src/locales/create.ts +49 -0
  52. package/src/locales/default/common.ts +41 -0
  53. package/src/locales/default/setting.ts +117 -0
  54. package/src/locales/index.ts +5 -0
  55. package/src/locales/options.ts +19 -0
  56. package/src/locales/resources/en_US.ts +9 -0
  57. package/src/locales/resources/index.ts +13 -0
  58. package/src/locales/resources/zh_CN.ts +9 -0
  59. package/src/migrations/FromV0ToV1.ts +12 -0
  60. package/src/migrations/index.ts +13 -0
  61. package/src/pages/_app.page.tsx +13 -0
  62. package/src/pages/_document.page.tsx +70 -0
  63. package/src/pages/api/LangChainStream.ts +95 -0
  64. package/src/pages/api/chain.api.ts +17 -0
  65. package/src/pages/api/openai.api.ts +31 -0
  66. package/src/pages/chat/SessionList/Header.tsx +56 -0
  67. package/src/pages/chat/SessionList/List/SessionItem.tsx +90 -0
  68. package/src/pages/chat/SessionList/List/index.tsx +31 -0
  69. package/src/pages/chat/SessionList/List/style.ts +77 -0
  70. package/src/pages/chat/SessionList/index.tsx +18 -0
  71. package/src/pages/chat/[id]/Config/ConfigCell.tsx +68 -0
  72. package/src/pages/chat/[id]/Config/ReadMode.tsx +63 -0
  73. package/src/pages/chat/[id]/Config/index.tsx +79 -0
  74. package/src/pages/chat/[id]/Conversation/ChatList.tsx +36 -0
  75. package/src/pages/chat/[id]/Conversation/Input.tsx +61 -0
  76. package/src/pages/chat/[id]/Conversation/index.tsx +32 -0
  77. package/src/pages/chat/[id]/Header.tsx +86 -0
  78. package/src/pages/chat/[id]/edit/AgentConfig.tsx +95 -0
  79. package/src/pages/chat/[id]/edit/AgentMeta.tsx +117 -0
  80. package/src/pages/chat/[id]/edit/FormItem.tsx +26 -0
  81. package/src/pages/chat/[id]/edit/Prompt.tsx +68 -0
  82. package/src/pages/chat/[id]/edit/index.page.tsx +62 -0
  83. package/src/pages/chat/[id]/edit/style.ts +42 -0
  84. package/src/pages/chat/[id]/index.page.tsx +40 -0
  85. package/src/pages/chat/index.page.tsx +1 -0
  86. package/src/pages/chat/layout.tsx +51 -0
  87. package/src/pages/index.page.tsx +1 -0
  88. package/src/pages/setting/Header.tsx +27 -0
  89. package/src/pages/setting/SettingForm.tsx +299 -0
  90. package/src/pages/setting/SliderWithInput/index.tsx +40 -0
  91. package/src/pages/setting/ThemeSwatches/ThemeSwatchesNeutral.tsx +33 -0
  92. package/src/pages/setting/ThemeSwatches/ThemeSwatchesPrimary.tsx +33 -0
  93. package/src/pages/setting/ThemeSwatches/index.ts +2 -0
  94. package/src/pages/setting/index.page.tsx +41 -0
  95. package/src/prompts/agent.ts +65 -0
  96. package/src/services/chatModel.ts +34 -0
  97. package/src/services/langChain.ts +18 -0
  98. package/src/services/url.ts +8 -0
  99. package/src/store/middleware/createHashStorage.ts +49 -0
  100. package/src/store/session/index.ts +33 -0
  101. package/src/store/session/initialState.ts +11 -0
  102. package/src/store/session/selectors.ts +3 -0
  103. package/src/store/session/slices/agentConfig/action.ts +226 -0
  104. package/src/store/session/slices/agentConfig/index.ts +3 -0
  105. package/src/store/session/slices/agentConfig/initialState.ts +34 -0
  106. package/src/store/session/slices/agentConfig/selectors.ts +54 -0
  107. package/src/store/session/slices/chat/action.ts +210 -0
  108. package/src/store/session/slices/chat/index.ts +3 -0
  109. package/src/store/session/slices/chat/initialState.ts +12 -0
  110. package/src/store/session/slices/chat/messageReducer.test.ts +70 -0
  111. package/src/store/session/slices/chat/messageReducer.ts +84 -0
  112. package/src/store/session/slices/chat/selectors.ts +83 -0
  113. package/src/store/session/slices/session/action.ts +118 -0
  114. package/src/store/session/slices/session/index.ts +3 -0
  115. package/src/store/session/slices/session/initialState.ts +31 -0
  116. package/src/store/session/slices/session/reducers/session.test.ts +456 -0
  117. package/src/store/session/slices/session/reducers/session.ts +113 -0
  118. package/src/store/session/slices/session/selectors/chat.ts +4 -0
  119. package/src/store/session/slices/session/selectors/index.ts +20 -0
  120. package/src/store/session/slices/session/selectors/list.ts +65 -0
  121. package/src/store/session/store.ts +17 -0
  122. package/src/store/settings/action.ts +40 -0
  123. package/src/store/settings/index.ts +23 -0
  124. package/src/store/settings/initialState.ts +41 -0
  125. package/src/store/settings/selectors.ts +17 -0
  126. package/src/store/settings/store.ts +13 -0
  127. package/src/styles/antdOverride.ts +33 -0
  128. package/src/styles/global.ts +23 -0
  129. package/src/styles/index.ts +6 -0
  130. package/src/types/chatMessage.ts +46 -0
  131. package/src/types/exportConfig.ts +44 -0
  132. package/src/types/global.d.ts +14 -0
  133. package/src/types/i18next.d.ts +8 -0
  134. package/src/types/langchain.ts +34 -0
  135. package/src/types/llm.ts +49 -0
  136. package/src/types/locale.ts +1 -0
  137. package/src/types/meta.ts +26 -0
  138. package/src/types/openai.ts +62 -0
  139. package/src/types/session.ts +59 -0
  140. package/src/utils/VersionController.test.ts +90 -0
  141. package/src/utils/VersionController.ts +64 -0
  142. package/src/utils/compass.ts +94 -0
  143. package/src/utils/fetch.ts +132 -0
  144. package/src/utils/filter.test.ts +120 -0
  145. package/src/utils/filter.ts +29 -0
  146. package/src/utils/uploadFIle.ts +8 -0
  147. package/src/utils/uuid.ts +9 -0
  148. package/tsconfig.json +31 -0
  149. package/vitest.config.ts +11 -0
@@ -0,0 +1,79 @@
1
+ import { ActionIcon, DraggablePanel, DraggablePanelContainer } from '@lobehub/ui';
2
+ import { createStyles } from 'antd-style';
3
+ import { LucideEdit, LucideX } from 'lucide-react';
4
+ import Router from 'next/router';
5
+ import { useTranslation } from 'react-i18next';
6
+ import { Flexbox } from 'react-layout-kit';
7
+ import { shallow } from 'zustand/shallow';
8
+
9
+ import { useSessionStore } from '@/store/session';
10
+
11
+ import ReadMode from './ReadMode';
12
+
13
+ const WIDTH = 280;
14
+
15
+ const useStyles = createStyles(({ css, token }) => ({
16
+ drawer: css`
17
+ background: ${token.colorBgLayout};
18
+ `,
19
+ header: css`
20
+ border-bottom: 1px solid ${token.colorBorder};
21
+ `,
22
+ }));
23
+
24
+ const Config = () => {
25
+ const { t } = useTranslation('common');
26
+ const { styles } = useStyles();
27
+ const [showAgentSettings, toggleConfig, id] = useSessionStore(
28
+ (s) => [s.showAgentSettings, s.toggleConfig, s.activeId],
29
+ shallow,
30
+ );
31
+
32
+ return (
33
+ <DraggablePanel
34
+ className={styles.drawer}
35
+ expand={showAgentSettings}
36
+ expandable={false}
37
+ maxWidth={WIDTH}
38
+ minWidth={WIDTH}
39
+ mode={'float'}
40
+ pin
41
+ placement={'right'}
42
+ resize={{ left: false }}
43
+ >
44
+ <DraggablePanelContainer style={{ flex: 'none', minWidth: WIDTH }}>
45
+ <Flexbox
46
+ align={'center'}
47
+ className={styles.header}
48
+ distribution={'space-between'}
49
+ horizontal
50
+ padding={12}
51
+ paddingInline={16}
52
+ >
53
+ <Flexbox>{t('agentProfile')}</Flexbox>
54
+ <Flexbox gap={4} horizontal>
55
+ <ActionIcon
56
+ icon={LucideEdit}
57
+ onClick={() => {
58
+ Router.push(`/chat/${id}/edit`);
59
+ }}
60
+ size={{ blockSize: 32, fontSize: 20 }}
61
+ title={t('edit')}
62
+ />
63
+ <ActionIcon
64
+ icon={LucideX}
65
+ onClick={() => {
66
+ toggleConfig(false);
67
+ }}
68
+ size={{ blockSize: 32, fontSize: 20 }}
69
+ title={t('close')}
70
+ />
71
+ </Flexbox>
72
+ </Flexbox>
73
+ <ReadMode />
74
+ </DraggablePanelContainer>
75
+ </DraggablePanel>
76
+ );
77
+ };
78
+
79
+ export default Config;
@@ -0,0 +1,36 @@
1
+ import { ChatList } from '@lobehub/ui';
2
+ import isEqual from 'fast-deep-equal';
3
+ import { memo } from 'react';
4
+ import { shallow } from 'zustand/shallow';
5
+
6
+ import { chatSelectors, useSessionStore } from '@/store/session';
7
+
8
+ const List = () => {
9
+ const data = useSessionStore(chatSelectors.currentChats, isEqual);
10
+ const [deleteMessage, resendMessage] = useSessionStore(
11
+ (s) => [s.deleteMessage, s.resendMessage],
12
+ shallow,
13
+ );
14
+
15
+ return (
16
+ <ChatList
17
+ data={data}
18
+ onActionClick={(key, id) => {
19
+ switch (key) {
20
+ case 'delete': {
21
+ deleteMessage(id);
22
+ break;
23
+ }
24
+
25
+ case 'regenerate': {
26
+ resendMessage(id);
27
+ break;
28
+ }
29
+ }
30
+ }}
31
+ style={{ marginTop: 24 }}
32
+ />
33
+ );
34
+ };
35
+
36
+ export default memo(List);
@@ -0,0 +1,61 @@
1
+ import { ActionIcon, ChatInputArea, DraggablePanel, Icon, TokenTag } from '@lobehub/ui';
2
+ import { Button } from 'antd';
3
+ import { encode } from 'gpt-tokenizer';
4
+ import { Archive, Eraser, Languages } from 'lucide-react';
5
+ import { memo, useMemo, useState } from 'react';
6
+ import { shallow } from 'zustand/shallow';
7
+
8
+ import { ModelTokens } from '@/const/modelTokens';
9
+ import { agentSelectors, chatSelectors, useSessionStore } from '@/store/session';
10
+ import { useSettings } from '@/store/settings';
11
+
12
+ const ChatInput = () => {
13
+ const [expand, setExpand] = useState<boolean>(false);
14
+ const [text, setText] = useState('');
15
+ const textTokenCount = useMemo(() => encode(text).length, [text]);
16
+
17
+ const [inputHeight] = useSettings((s) => [s.inputHeight], shallow);
18
+ const [totalToken, model, sendMessage, clearMessage] = useSessionStore(
19
+ (s) => [
20
+ chatSelectors.totalTokenCount(s),
21
+ agentSelectors.currentAgentModel(s),
22
+ s.createOrSendMsg,
23
+ s.clearMessage,
24
+ ],
25
+ shallow,
26
+ );
27
+
28
+ return (
29
+ <DraggablePanel
30
+ expandable={false}
31
+ fullscreen={expand}
32
+ minHeight={200}
33
+ onSizeChange={(_, size) => {
34
+ if (!size) return;
35
+ useSettings.setState({
36
+ inputHeight: typeof size.height === 'string' ? Number.parseInt(size.height) : size.height,
37
+ });
38
+ }}
39
+ placement="bottom"
40
+ size={{ height: inputHeight, width: '100%' }}
41
+ >
42
+ <ChatInputArea
43
+ actions={
44
+ <>
45
+ <ActionIcon icon={Languages} />
46
+ <ActionIcon icon={Eraser} onClick={clearMessage} />
47
+ <TokenTag maxValue={ModelTokens[model]} value={totalToken + textTokenCount} />
48
+ </>
49
+ }
50
+ expand={expand}
51
+ footer={<Button icon={<Icon icon={Archive} />} />}
52
+ minHeight={200}
53
+ onExpandChange={setExpand}
54
+ onInputChange={setText}
55
+ onSend={sendMessage}
56
+ />
57
+ </DraggablePanel>
58
+ );
59
+ };
60
+
61
+ export default memo(ChatInput);
@@ -0,0 +1,32 @@
1
+ import { createStyles } from 'antd-style';
2
+ import { memo } from 'react';
3
+ import { Flexbox } from 'react-layout-kit';
4
+
5
+ import ChatInput from '@/pages/chat/[id]/Conversation/Input';
6
+
7
+ import ChatList from './ChatList';
8
+
9
+ const useStyles = createStyles(({ css, token }) => ({
10
+ input: css`
11
+ position: sticky;
12
+ z-index: 10;
13
+ bottom: 0;
14
+ background: ${token.colorBgLayout};
15
+ `,
16
+ }));
17
+
18
+ const Conversation = () => {
19
+ const { styles } = useStyles();
20
+ return (
21
+ <>
22
+ <div style={{ flex: 1, overflowY: 'scroll' }}>
23
+ <ChatList />
24
+ </div>
25
+ <Flexbox className={styles.input}>
26
+ <ChatInput />
27
+ </Flexbox>
28
+ </>
29
+ );
30
+ };
31
+
32
+ export default memo(Conversation);
@@ -0,0 +1,86 @@
1
+ import { ActionIcon, Avatar, ChatHeader } from '@lobehub/ui';
2
+ import { createStyles } from 'antd-style';
3
+ import { ArchiveIcon, LucideEdit, MoreVerticalIcon, Share2Icon } from 'lucide-react';
4
+ import Router from 'next/router';
5
+ import { memo } from 'react';
6
+ import { useTranslation } from 'react-i18next';
7
+ import { Flexbox } from 'react-layout-kit';
8
+ import { shallow } from 'zustand/shallow';
9
+
10
+ import { sessionSelectors, useSessionStore } from '@/store/session';
11
+
12
+ const useStyles = createStyles(({ css, token }) => ({
13
+ desc: css`
14
+ font-size: 12px;
15
+ color: ${token.colorTextTertiary};
16
+ `,
17
+ title: css`
18
+ font-weight: bold;
19
+ color: ${token.colorText};
20
+ `,
21
+ }));
22
+ const Header = memo(() => {
23
+ const { t } = useTranslation('common');
24
+ const [meta, id] = useSessionStore((s) => {
25
+ const chat = sessionSelectors.currentSession(s);
26
+ return [chat?.meta, s.activeId];
27
+ }, shallow);
28
+
29
+ const [
30
+ // genShareUrl,
31
+
32
+ toggleConfig,
33
+ ] = useSessionStore(
34
+ (s) => [
35
+ // s.genShareUrl,
36
+ s.toggleConfig,
37
+ ],
38
+ shallow,
39
+ );
40
+
41
+ const { styles } = useStyles();
42
+ return (
43
+ <ChatHeader
44
+ left={
45
+ <>
46
+ <Avatar avatar={meta && sessionSelectors.getAgentAvatar(meta)} size={40} title={'123'} />
47
+ <Flexbox>
48
+ <Flexbox className={styles.title}>{meta?.title || t('defaultAgent')}</Flexbox>
49
+ <Flexbox className={styles.desc}>{meta?.description || t('noDescription')}</Flexbox>
50
+ </Flexbox>
51
+ </>
52
+ }
53
+ right={
54
+ id && (
55
+ <>
56
+ <ActionIcon
57
+ icon={Share2Icon}
58
+ onClick={() => {
59
+ // genShareUrl();
60
+ }}
61
+ size={{ fontSize: 24 }}
62
+ title={t('share')}
63
+ />
64
+ <ActionIcon icon={ArchiveIcon} size={{ fontSize: 24 }} title={t('archive')} />
65
+ <ActionIcon
66
+ icon={LucideEdit}
67
+ onClick={() => {
68
+ Router.push(`/chat/${id}/edit`);
69
+ }}
70
+ size={{ blockSize: 32, fontSize: 20 }}
71
+ title={t('edit')}
72
+ />
73
+ <ActionIcon
74
+ icon={MoreVerticalIcon}
75
+ onClick={() => toggleConfig()}
76
+ size={{ fontSize: 24 }}
77
+ title={t('sessionSetting')}
78
+ />
79
+ </>
80
+ )
81
+ }
82
+ />
83
+ );
84
+ });
85
+
86
+ export default Header;
@@ -0,0 +1,95 @@
1
+ import { Collapse, InputNumber, Segmented, Slider } from 'antd';
2
+ import isEqual from 'fast-deep-equal';
3
+ import { useTranslation } from 'react-i18next';
4
+ import { Flexbox } from 'react-layout-kit';
5
+ import { shallow } from 'zustand/shallow';
6
+
7
+ import { agentSelectors, useSessionStore } from '@/store/session';
8
+ import { LanguageModel } from '@/types/llm';
9
+
10
+ import { FormItem } from './FormItem';
11
+ import Prompt from './Prompt';
12
+ import { useStyles } from './style';
13
+
14
+ const AgentConfig = () => {
15
+ const { t } = useTranslation('common');
16
+
17
+ const { styles, theme } = useStyles();
18
+
19
+ const config = useSessionStore(agentSelectors.currentAgentConfigSafe, isEqual);
20
+
21
+ const [updateAgentConfig] = useSessionStore((s) => [s.updateAgentConfig], shallow);
22
+
23
+ return (
24
+ <>
25
+ <Flexbox
26
+ align={'center'}
27
+ distribution={'space-between'}
28
+ horizontal
29
+ paddingBlock={12}
30
+ style={{
31
+ borderBottom: `1px solid ${theme.colorBorder}`,
32
+ }}
33
+ >
34
+ <Flexbox className={styles.profile}> {t('modelConfig')}</Flexbox>
35
+ </Flexbox>
36
+ <Flexbox gap={24}>
37
+ <FormItem label={t('agentModel')}>
38
+ <Segmented
39
+ block
40
+ onChange={(value) => {
41
+ updateAgentConfig({ model: value as LanguageModel });
42
+ }}
43
+ options={Object.values(LanguageModel).map((value) => ({
44
+ label: t(value),
45
+ value,
46
+ }))}
47
+ size={'large'}
48
+ value={config.model}
49
+ />
50
+ </FormItem>
51
+ <Prompt />
52
+ <Collapse
53
+ activeKey={['advanceSettings']}
54
+ bordered={false}
55
+ className={styles.title}
56
+ expandIconPosition={'end'}
57
+ items={[
58
+ {
59
+ children: (
60
+ <Flexbox paddingBlock={16}>
61
+ <FormItem label={t('modelTemperature')}>
62
+ <Flexbox gap={16} horizontal>
63
+ <Slider
64
+ max={1}
65
+ min={0}
66
+ onChange={(value) => {
67
+ updateAgentConfig({ params: { temperature: value } });
68
+ }}
69
+ step={0.1}
70
+ style={{ flex: 1 }}
71
+ value={Number(config.params.temperature)}
72
+ />
73
+ <InputNumber
74
+ max={1}
75
+ min={0}
76
+ onChange={(value) => {
77
+ if (value) updateAgentConfig({ params: { temperature: value } });
78
+ }}
79
+ value={config.params.temperature}
80
+ />
81
+ </Flexbox>
82
+ </FormItem>
83
+ </Flexbox>
84
+ ),
85
+ key: 'advanceSettings',
86
+ label: t('advanceSettings'),
87
+ },
88
+ ]}
89
+ />
90
+ </Flexbox>
91
+ </>
92
+ );
93
+ };
94
+
95
+ export default AgentConfig;
@@ -0,0 +1,117 @@
1
+ import { ActionIcon, Avatar, Input, Tooltip } from '@lobehub/ui';
2
+ import { Button, Collapse } from 'antd';
3
+ import isEqual from 'fast-deep-equal';
4
+ import { LucideSparkles } from 'lucide-react';
5
+ import { useTranslation } from 'react-i18next';
6
+ import { Flexbox } from 'react-layout-kit';
7
+ import { shallow } from 'zustand/shallow';
8
+
9
+ import { agentSelectors, useSessionStore } from '@/store/session';
10
+
11
+ import { FormItem } from './FormItem';
12
+ import { useStyles } from './style';
13
+
14
+ const AgentMeta = () => {
15
+ const { t } = useTranslation('common');
16
+
17
+ const { styles, theme } = useStyles();
18
+
19
+ const metaData = useSessionStore(agentSelectors.currentAgentMeta, isEqual);
20
+
21
+ const [
22
+ autocompleteMeta,
23
+ autocompleteSessionAgentMeta,
24
+ loading,
25
+ updateAgentMeta,
26
+ id,
27
+ hasSystemRole,
28
+ ] = useSessionStore(
29
+ (s) => [
30
+ s.autocompleteMeta,
31
+ s.autocompleteSessionAgentMeta,
32
+ s.autocompleteLoading,
33
+ s.updateAgentMeta,
34
+ s.activeId,
35
+ agentSelectors.hasSystemRole(s),
36
+ ],
37
+ shallow,
38
+ );
39
+
40
+ const basic = [
41
+ { key: 'title', label: t('agentName'), placeholder: t('agentNamePlaceholder') },
42
+ {
43
+ key: 'description',
44
+ label: t('agentDescription'),
45
+ placeholder: t('agentDescriptionPlaceholder'),
46
+ },
47
+ // { key: 'tag', label: t('agentTag'), placeholder: t('agentTagPlaceholder') },
48
+ ];
49
+
50
+ return (
51
+ <Collapse
52
+ defaultActiveKey={hasSystemRole ? ['meta'] : []}
53
+ items={[
54
+ {
55
+ children: (
56
+ <Flexbox gap={80} horizontal style={{ marginTop: 16 }}>
57
+ <Flexbox flex={1} gap={24}>
58
+ {basic.map((item) => (
59
+ <FormItem key={item.key} label={item.label}>
60
+ <Input
61
+ onChange={(e) => {
62
+ updateAgentMeta({ [item.key]: e.target.value });
63
+ }}
64
+ placeholder={item.placeholder}
65
+ suffix={
66
+ <ActionIcon
67
+ icon={LucideSparkles}
68
+ loading={loading[item.key as keyof typeof loading]}
69
+ onClick={() => {
70
+ autocompleteMeta(item.key as keyof typeof metaData);
71
+ }}
72
+ size={'small'}
73
+ style={{
74
+ color: theme.purple,
75
+ }}
76
+ title={t('autoGenerate')}
77
+ />
78
+ }
79
+ type={'block'}
80
+ value={metaData[item.key as keyof typeof metaData]}
81
+ />
82
+ </FormItem>
83
+ ))}
84
+ </Flexbox>
85
+ <FormItem label={t('agentAvatar')}>
86
+ <Avatar avatar={metaData.avatar} size={200} />
87
+ </FormItem>
88
+ </Flexbox>
89
+ ),
90
+ className: styles.collapseHeader,
91
+ extra: (
92
+ <Tooltip title={t('autoGenerateTooltip')}>
93
+ <Button
94
+ disabled={!hasSystemRole}
95
+ loading={Object.values(loading).some((i) => !!i)}
96
+ onClick={(e) => {
97
+ e.stopPropagation();
98
+ console.log(id);
99
+ if (!id) return;
100
+
101
+ autocompleteSessionAgentMeta(id, true);
102
+ }}
103
+ size={'large'}
104
+ >
105
+ {t('autoGenerate')}
106
+ </Button>
107
+ </Tooltip>
108
+ ),
109
+ key: 'meta',
110
+ label: <Flexbox className={styles.profile}>{t('profile')}</Flexbox>,
111
+ },
112
+ ]}
113
+ />
114
+ );
115
+ };
116
+
117
+ export default AgentMeta;
@@ -0,0 +1,26 @@
1
+ import { createStyles } from 'antd-style';
2
+ import { ReactNode, memo } from 'react';
3
+ import { Flexbox } from 'react-layout-kit';
4
+
5
+ const useStyles = createStyles(({ css, token }) => ({
6
+ header: css``,
7
+ title: css`
8
+ color: ${token.colorTextSecondary};
9
+ `,
10
+ }));
11
+
12
+ interface FormItemProps {
13
+ children: ReactNode;
14
+ label: string;
15
+ }
16
+
17
+ export const FormItem = memo<FormItemProps>(({ label, children }) => {
18
+ const { styles } = useStyles();
19
+
20
+ return (
21
+ <Flexbox className={styles.header} gap={12}>
22
+ <Flexbox className={styles.title}>{label}</Flexbox>
23
+ <Flexbox>{children}</Flexbox>
24
+ </Flexbox>
25
+ );
26
+ });
@@ -0,0 +1,68 @@
1
+ import { EditableMessage } from '@lobehub/ui';
2
+ import { Button } from 'antd';
3
+ import { createStyles } from 'antd-style';
4
+ import { useState } from 'react';
5
+ import { useTranslation } from 'react-i18next';
6
+ import { Flexbox } from 'react-layout-kit';
7
+ import { shallow } from 'zustand/shallow';
8
+
9
+ import { agentSelectors, useSessionStore } from '@/store/session';
10
+
11
+ import { FormItem } from './FormItem';
12
+
13
+ export const useStyles = createStyles(({ css, token }) => ({
14
+ input: css`
15
+ padding: 12px;
16
+ background: ${token.colorFillTertiary};
17
+ border: 1px solid ${token.colorPrimaryBorder};
18
+ border-radius: 8px;
19
+ `,
20
+ markdown: css`
21
+ padding: 12px;
22
+ background: ${token.colorFillTertiary};
23
+ `,
24
+ }));
25
+
26
+ const Prompt = () => {
27
+ const { t } = useTranslation('common');
28
+
29
+ const [editing, setEditing] = useState(false);
30
+ const { styles } = useStyles();
31
+
32
+ const systemRole = useSessionStore((s) => {
33
+ const config = agentSelectors.currentAgentConfigSafe(s);
34
+ return config.systemRole;
35
+ }, shallow);
36
+
37
+ const [updateAgentConfig] = useSessionStore((s) => [s.updateAgentConfig], shallow);
38
+
39
+ return (
40
+ <FormItem label={t('agentPrompt')}>
41
+ <Flexbox gap={16}>
42
+ <EditableMessage
43
+ classNames={styles}
44
+ editing={editing}
45
+ onChange={(e) => {
46
+ updateAgentConfig({ systemRole: e });
47
+ }}
48
+ onEditingChange={setEditing}
49
+ value={systemRole}
50
+ />
51
+ {!editing && (
52
+ <Flexbox direction={'horizontal-reverse'}>
53
+ <Button
54
+ onClick={() => {
55
+ setEditing(true);
56
+ }}
57
+ type={'primary'}
58
+ >
59
+ {t('edit')}
60
+ </Button>
61
+ </Flexbox>
62
+ )}
63
+ </Flexbox>
64
+ </FormItem>
65
+ );
66
+ };
67
+
68
+ export default Prompt;
@@ -0,0 +1,62 @@
1
+ import { ChatHeader } from '@lobehub/ui';
2
+ import { Button } from 'antd';
3
+ import { createStyles } from 'antd-style';
4
+ import Router from 'next/router';
5
+ import { memo } from 'react';
6
+ import { useTranslation } from 'react-i18next';
7
+ import { Flexbox } from 'react-layout-kit';
8
+
9
+ import ChatLayout from '../../layout';
10
+ import AgentConfig from './AgentConfig';
11
+ import AgentMeta from './AgentMeta';
12
+
13
+ const useStyles = createStyles(({ css, token }) => ({
14
+ footer: css`
15
+ position: sticky;
16
+ bottom: 0;
17
+ border-top: 1px solid ${token.colorBorder};
18
+ `,
19
+ form: css`
20
+ overflow-y: auto;
21
+ `,
22
+ header: css`
23
+ background: ${token.colorBgContainer};
24
+ border-bottom: 1px solid ${token.colorSplit};
25
+ `,
26
+ title: css`
27
+ font-size: 16px;
28
+ font-weight: 500;
29
+ `,
30
+ }));
31
+
32
+ const EditPage = memo(() => {
33
+ const { t } = useTranslation('common');
34
+
35
+ const { styles } = useStyles();
36
+
37
+ return (
38
+ <ChatLayout>
39
+ <Flexbox height={'100vh'} style={{ position: 'relative' }} width={'100%'}>
40
+ {/*header*/}
41
+ <ChatHeader
42
+ left={<div className={styles.title}>{t('editAgentProfile')}</div>}
43
+ onBackClick={() => Router.back()}
44
+ right={
45
+ <>
46
+ <Button>{t('share')}</Button>
47
+ <Button type={'primary'}>{t('export')}</Button>
48
+ </>
49
+ }
50
+ showBackButton
51
+ />
52
+ {/*form*/}
53
+ <Flexbox className={styles.form} flex={1} gap={10} padding={24}>
54
+ <AgentMeta />
55
+ <AgentConfig />
56
+ </Flexbox>
57
+ </Flexbox>
58
+ </ChatLayout>
59
+ );
60
+ });
61
+
62
+ export default EditPage;