@lobehub/chat 1.31.9 → 1.31.11

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 (57) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/locales/ar/error.json +1 -0
  3. package/locales/ar/models.json +3 -9
  4. package/locales/bg-BG/error.json +1 -0
  5. package/locales/bg-BG/models.json +3 -9
  6. package/locales/de-DE/error.json +1 -0
  7. package/locales/de-DE/models.json +3 -9
  8. package/locales/en-US/error.json +1 -0
  9. package/locales/en-US/models.json +3 -9
  10. package/locales/es-ES/error.json +1 -0
  11. package/locales/es-ES/models.json +4 -10
  12. package/locales/fa-IR/error.json +1 -0
  13. package/locales/fa-IR/models.json +3 -9
  14. package/locales/fr-FR/error.json +1 -0
  15. package/locales/fr-FR/models.json +4 -10
  16. package/locales/it-IT/error.json +1 -0
  17. package/locales/it-IT/models.json +3 -9
  18. package/locales/ja-JP/error.json +1 -0
  19. package/locales/ja-JP/models.json +3 -9
  20. package/locales/ko-KR/error.json +1 -0
  21. package/locales/ko-KR/models.json +3 -9
  22. package/locales/nl-NL/error.json +1 -0
  23. package/locales/nl-NL/models.json +3 -9
  24. package/locales/pl-PL/error.json +1 -0
  25. package/locales/pl-PL/models.json +4 -10
  26. package/locales/pt-BR/error.json +1 -0
  27. package/locales/pt-BR/models.json +3 -9
  28. package/locales/ru-RU/error.json +1 -0
  29. package/locales/ru-RU/models.json +3 -9
  30. package/locales/tr-TR/error.json +1 -0
  31. package/locales/tr-TR/models.json +3 -9
  32. package/locales/vi-VN/error.json +1 -0
  33. package/locales/vi-VN/models.json +3 -9
  34. package/locales/zh-CN/error.json +2 -1
  35. package/locales/zh-CN/models.json +3 -9
  36. package/locales/zh-TW/error.json +1 -0
  37. package/locales/zh-TW/models.json +3 -9
  38. package/package.json +3 -3
  39. package/src/{features → app/(main)/chat/(workspace)/@conversation/features}/ChatInput/Desktop/TextArea.test.tsx +13 -13
  40. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/TextArea.tsx +29 -0
  41. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/index.tsx +46 -0
  42. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/index.tsx +2 -1
  43. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatList/Content.tsx +13 -11
  44. package/src/app/(main)/settings/llm/components/Checker.tsx +9 -2
  45. package/src/const/message.ts +4 -0
  46. package/src/features/ChatInput/Desktop/Footer/ShortcutHint.tsx +61 -0
  47. package/src/features/ChatInput/Desktop/Footer/index.tsx +11 -46
  48. package/src/features/ChatInput/Desktop/{TextArea.tsx → InputArea/index.tsx} +11 -20
  49. package/src/features/ChatInput/Desktop/index.tsx +23 -32
  50. package/src/features/Conversation/Messages/index.ts +11 -11
  51. package/src/features/Conversation/components/ChatItem/index.tsx +83 -44
  52. package/src/features/Conversation/components/VirtualizedList/index.tsx +90 -92
  53. package/src/features/Conversation/index.ts +2 -0
  54. package/src/libs/agent-runtime/error.ts +2 -0
  55. package/src/locales/default/error.ts +1 -0
  56. package/src/types/topic/index.ts +1 -0
  57. /package/src/types/{topic.ts → topic/topic.ts} +0 -0
@@ -1,23 +1,20 @@
1
- import { Icon } from '@lobehub/ui';
2
- import { Button, Skeleton, Space } from 'antd';
1
+ import { Button, Space } from 'antd';
3
2
  import { createStyles } from 'antd-style';
4
- import { ChevronUp, CornerDownLeft, LucideCommand } from 'lucide-react';
5
3
  import { rgba } from 'polished';
6
4
  import { memo, useEffect, useState } from 'react';
7
5
  import { useTranslation } from 'react-i18next';
8
- import { Center, Flexbox } from 'react-layout-kit';
6
+ import { Flexbox } from 'react-layout-kit';
9
7
 
10
8
  import StopLoadingIcon from '@/components/StopLoading';
11
- import SaveTopic from '@/features/ChatInput/Topic';
12
9
  import { useSendMessage } from '@/features/ChatInput/useSend';
13
10
  import { useChatStore } from '@/store/chat';
14
11
  import { chatSelectors } from '@/store/chat/selectors';
15
- import { useUserStore } from '@/store/user';
16
- import { preferenceSelectors } from '@/store/user/selectors';
17
12
  import { isMacOS } from '@/utils/platform';
18
13
 
14
+ import SaveTopic from '../../Topic';
19
15
  import LocalFiles from '../FilePreview';
20
16
  import SendMore from './SendMore';
17
+ import ShortcutHint from './ShortcutHint';
21
18
 
22
19
  const useStyles = createStyles(({ css, prefixCls, token }) => {
23
20
  return {
@@ -48,51 +45,29 @@ const useStyles = createStyles(({ css, prefixCls, token }) => {
48
45
 
49
46
  interface FooterProps {
50
47
  expand: boolean;
48
+ saveTopic?: boolean;
51
49
  setExpand?: (expand: boolean) => void;
50
+ shortcutHint?: boolean;
52
51
  }
53
52
 
54
- const Footer = memo<FooterProps>(({ setExpand, expand }) => {
53
+ const Footer = memo<FooterProps>(({ setExpand, expand, shortcutHint = true, saveTopic = true }) => {
55
54
  const { t } = useTranslation('chat');
56
55
 
57
- const { theme, styles } = useStyles();
56
+ const { styles } = useStyles();
58
57
 
59
58
  const [isAIGenerating, stopGenerateMessage] = useChatStore((s) => [
60
59
  chatSelectors.isAIGenerating(s),
61
60
  s.stopGenerateMessage,
62
61
  ]);
63
62
 
64
- const [useCmdEnterToSend] = useUserStore((s) => [preferenceSelectors.useCmdEnterToSend(s)]);
65
-
66
63
  const { send: sendMessage, canSend } = useSendMessage();
67
64
 
68
65
  const [isMac, setIsMac] = useState<boolean>();
66
+
69
67
  useEffect(() => {
70
68
  setIsMac(isMacOS());
71
69
  }, [setIsMac]);
72
70
 
73
- const cmdEnter = (
74
- <Flexbox gap={2} horizontal>
75
- {typeof isMac === 'boolean' ? (
76
- <Icon icon={isMac ? LucideCommand : ChevronUp} />
77
- ) : (
78
- <Skeleton.Node active style={{ height: '100%', width: 12 }}>
79
- {' '}
80
- </Skeleton.Node>
81
- )}
82
- <Icon icon={CornerDownLeft} />
83
- </Flexbox>
84
- );
85
-
86
- const enter = (
87
- <Center>
88
- <Icon icon={CornerDownLeft} />
89
- </Center>
90
- );
91
-
92
- const sendShortcut = useCmdEnterToSend ? cmdEnter : enter;
93
-
94
- const wrapperShortcut = useCmdEnterToSend ? enter : cmdEnter;
95
-
96
71
  return (
97
72
  <Flexbox
98
73
  align={'end'}
@@ -107,18 +82,8 @@ const Footer = memo<FooterProps>(({ setExpand, expand }) => {
107
82
  {expand && <LocalFiles />}
108
83
  </Flexbox>
109
84
  <Flexbox align={'center'} flex={'none'} gap={8} horizontal>
110
- <Flexbox
111
- gap={4}
112
- horizontal
113
- style={{ color: theme.colorTextDescription, fontSize: 12, marginRight: 12 }}
114
- >
115
- {sendShortcut}
116
- <span>{t('input.send')}</span>
117
- <span>/</span>
118
- {wrapperShortcut}
119
- <span>{t('input.warp')}</span>
120
- </Flexbox>
121
- <SaveTopic />
85
+ {shortcutHint && <ShortcutHint />}
86
+ {saveTopic && <SaveTopic />}
122
87
  <Flexbox style={{ minWidth: 92 }}>
123
88
  {isAIGenerating ? (
124
89
  <Button
@@ -4,14 +4,11 @@ import { TextAreaRef } from 'antd/es/input/TextArea';
4
4
  import { memo, useEffect, useRef } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
6
6
 
7
- import { useSendMessage } from '@/features/ChatInput/useSend';
8
- import { useChatStore } from '@/store/chat';
9
- import { chatSelectors } from '@/store/chat/selectors';
10
7
  import { useUserStore } from '@/store/user';
11
8
  import { preferenceSelectors } from '@/store/user/selectors';
12
9
  import { isCommandPressed } from '@/utils/keyboard';
13
10
 
14
- import { useAutoFocus } from './useAutoFocus';
11
+ import { useAutoFocus } from '../useAutoFocus';
15
12
 
16
13
  const useStyles = createStyles(({ css }) => {
17
14
  return {
@@ -34,25 +31,20 @@ const useStyles = createStyles(({ css }) => {
34
31
  });
35
32
 
36
33
  interface InputAreaProps {
37
- setExpand?: (expand: boolean) => void;
34
+ loading?: boolean;
35
+ onChange: (string: string) => void;
36
+ onSend: () => void;
37
+ value: string;
38
38
  }
39
39
 
40
- const InputArea = memo<InputAreaProps>(({ setExpand }) => {
40
+ const InputArea = memo<InputAreaProps>(({ onSend, value, loading, onChange }) => {
41
41
  const { t } = useTranslation('chat');
42
42
  const { styles } = useStyles();
43
43
  const ref = useRef<TextAreaRef>(null);
44
44
  const isChineseInput = useRef(false);
45
45
 
46
- const [loading, value, updateInputMessage] = useChatStore((s) => [
47
- chatSelectors.isAIGenerating(s),
48
- s.inputMessage,
49
- s.updateInputMessage,
50
- ]);
51
-
52
46
  const useCmdEnterToSend = useUserStore(preferenceSelectors.useCmdEnterToSend);
53
47
 
54
- const { send: sendMessage } = useSendMessage();
55
-
56
48
  useAutoFocus(ref);
57
49
 
58
50
  const hasValue = !!value;
@@ -78,10 +70,10 @@ const InputArea = memo<InputAreaProps>(({ setExpand }) => {
78
70
  autoFocus
79
71
  className={styles.textarea}
80
72
  onBlur={(e) => {
81
- updateInputMessage?.(e.target.value);
73
+ onChange?.(e.target.value);
82
74
  }}
83
75
  onChange={(e) => {
84
- updateInputMessage?.(e.target.value);
76
+ onChange?.(e.target.value);
85
77
  }}
86
78
  onCompositionEnd={() => {
87
79
  isChineseInput.current = false;
@@ -98,8 +90,7 @@ const InputArea = memo<InputAreaProps>(({ setExpand }) => {
98
90
  // refs: https://github.com/lobehub/lobe-chat/pull/989
99
91
  e.preventDefault();
100
92
 
101
- sendMessage();
102
- setExpand?.(false);
93
+ onSend();
103
94
  };
104
95
  const commandKey = isCommandPressed(e);
105
96
 
@@ -109,7 +100,7 @@ const InputArea = memo<InputAreaProps>(({ setExpand }) => {
109
100
  } else {
110
101
  // cmd + enter to wrap
111
102
  if (commandKey) {
112
- updateInputMessage?.((e.target as any).value + '\n');
103
+ onChange?.((e.target as any).value + '\n');
113
104
  return;
114
105
  }
115
106
 
@@ -125,6 +116,6 @@ const InputArea = memo<InputAreaProps>(({ setExpand }) => {
125
116
  );
126
117
  });
127
118
 
128
- InputArea.displayName = 'InputArea';
119
+ InputArea.displayName = 'DesktopInputArea';
129
120
 
130
121
  export default InputArea;
@@ -1,59 +1,50 @@
1
1
  'use client';
2
2
 
3
3
  import { DraggablePanel } from '@lobehub/ui';
4
- import { memo, useState } from 'react';
4
+ import { ReactNode, memo, useCallback, useState } from 'react';
5
5
  import { Flexbox } from 'react-layout-kit';
6
6
 
7
7
  import { CHAT_TEXTAREA_HEIGHT, CHAT_TEXTAREA_MAX_HEIGHT } from '@/const/layoutTokens';
8
- import { ActionKeys } from '@/features/ChatInput/ActionBar/config';
9
- import { useGlobalStore } from '@/store/global';
10
- import { systemStatusSelectors } from '@/store/global/selectors';
11
8
 
9
+ import { ActionKeys } from '../ActionBar/config';
12
10
  import LocalFiles from './FilePreview';
13
11
  import Footer from './Footer';
14
12
  import Head from './Header';
15
- import TextArea from './TextArea';
16
-
17
- const defaultLeftActions = [
18
- 'model',
19
- 'fileUpload',
20
- 'knowledgeBase',
21
- 'temperature',
22
- 'history',
23
- 'stt',
24
- 'tools',
25
- 'token',
26
- ] as ActionKeys[];
27
-
28
- const defaultRightActions = ['clear'] as ActionKeys[];
29
13
 
30
14
  interface DesktopChatInputProps {
31
- leftActions?: ActionKeys[];
32
- rightActions?: ActionKeys[];
15
+ footer?: {
16
+ saveTopic?: boolean;
17
+ shortcutHint?: boolean;
18
+ };
19
+ inputHeight: number;
20
+ leftActions: ActionKeys[];
21
+ onInputHeightChange?: (height: number) => void;
22
+ renderTextArea: (onSend: () => void) => ReactNode;
23
+ rightActions: ActionKeys[];
33
24
  }
25
+
34
26
  const DesktopChatInput = memo<DesktopChatInputProps>(
35
- ({ leftActions = defaultLeftActions, rightActions = defaultRightActions }) => {
27
+ ({ leftActions, rightActions, footer, renderTextArea, inputHeight, onInputHeightChange }) => {
36
28
  const [expand, setExpand] = useState<boolean>(false);
37
29
 
38
- const [inputHeight, updatePreference] = useGlobalStore((s) => [
39
- systemStatusSelectors.inputHeight(s),
40
- s.updateSystemStatus,
41
- ]);
30
+ const onSend = useCallback(() => {
31
+ setExpand(false);
32
+ }, []);
42
33
 
43
34
  return (
44
35
  <>
45
- {!expand && <LocalFiles />}
36
+ {!expand && leftActions.includes('fileUpload') && <LocalFiles />}
46
37
  <DraggablePanel
47
38
  fullscreen={expand}
48
39
  maxHeight={CHAT_TEXTAREA_MAX_HEIGHT}
49
40
  minHeight={CHAT_TEXTAREA_HEIGHT}
50
41
  onSizeChange={(_, size) => {
51
42
  if (!size) return;
43
+ const height =
44
+ typeof size.height === 'string' ? Number.parseInt(size.height) : size.height;
45
+ if (!height) return;
52
46
 
53
- updatePreference({
54
- inputHeight:
55
- typeof size.height === 'string' ? Number.parseInt(size.height) : size.height,
56
- });
47
+ onInputHeightChange?.(height);
57
48
  }}
58
49
  placement="bottom"
59
50
  size={{ height: inputHeight, width: '100%' }}
@@ -71,8 +62,8 @@ const DesktopChatInput = memo<DesktopChatInputProps>(
71
62
  rightActions={rightActions}
72
63
  setExpand={setExpand}
73
64
  />
74
- <TextArea setExpand={setExpand} />
75
- <Footer expand={expand} setExpand={setExpand} />
65
+ {renderTextArea(onSend)}
66
+ <Footer expand={expand} setExpand={setExpand} {...footer} />
76
67
  </Flexbox>
77
68
  </DraggablePanel>
78
69
  </>
@@ -1,9 +1,11 @@
1
+ import { useCallback } from 'react';
2
+
1
3
  import { useOpenChatSettings } from '@/hooks/useInterceptingRoutes';
2
4
  import { useGlobalStore } from '@/store/global';
3
5
  import { useSessionStore } from '@/store/session';
4
6
  import { sessionSelectors } from '@/store/session/selectors';
5
7
 
6
- import { MarkdownCustomRender, OnAvatarsClick, RenderBelowMessage, RenderMessage } from '../types';
8
+ import { MarkdownCustomRender, RenderBelowMessage, RenderMessage } from '../types';
7
9
  import { AssistantMessage } from './Assistant';
8
10
  import { DefaultBelowMessage, DefaultMessage } from './Default';
9
11
  import { ToolMessage } from './Tool';
@@ -26,22 +28,20 @@ export const markdownCustomRenders: Record<string, MarkdownCustomRender> = {
26
28
  user: UserMarkdownRender,
27
29
  };
28
30
 
29
- export const useAvatarsClick = (): OnAvatarsClick => {
31
+ export const useAvatarsClick = (role?: string) => {
30
32
  const [isInbox] = useSessionStore((s) => [sessionSelectors.isInboxSession(s)]);
31
33
  const [toggleSystemRole] = useGlobalStore((s) => [s.toggleSystemRole]);
32
34
  const openChatSettings = useOpenChatSettings();
33
35
 
34
- return (role) => {
36
+ return useCallback(() => {
35
37
  switch (role) {
36
38
  case 'assistant': {
37
- return () => {
38
- if (!isInbox) {
39
- toggleSystemRole(true);
40
- } else {
41
- openChatSettings();
42
- }
43
- };
39
+ if (!isInbox) {
40
+ toggleSystemRole(true);
41
+ } else {
42
+ openChatSettings();
43
+ }
44
44
  }
45
45
  }
46
- };
46
+ }, [isInbox, role]);
47
47
  };
@@ -1,7 +1,9 @@
1
+ 'use client';
2
+
1
3
  import { ChatItem } from '@lobehub/ui';
2
4
  import { createStyles } from 'antd-style';
3
5
  import isEqual from 'fast-deep-equal';
4
- import { ReactNode, memo, useCallback, useMemo } from 'react';
6
+ import { MouseEventHandler, ReactNode, memo, useCallback, useMemo } from 'react';
5
7
  import { useTranslation } from 'react-i18next';
6
8
 
7
9
  import { useAgentStore } from '@/store/agent';
@@ -42,11 +44,13 @@ const useStyles = createStyles(({ css, prefixCls }) => ({
42
44
  }));
43
45
 
44
46
  export interface ChatListItemProps {
47
+ hideActionBar?: boolean;
45
48
  id: string;
46
49
  index: number;
50
+ showThreadDivider?: boolean;
47
51
  }
48
52
 
49
- const Item = memo<ChatListItemProps>(({ index, id }) => {
53
+ const Item = memo<ChatListItemProps>(({ index, id, hideActionBar }) => {
50
54
  const fontSize = useUserStore(userGeneralSettingsSelectors.fontSize);
51
55
  const { t } = useTranslation('common');
52
56
  const { styles, cx } = useStyles();
@@ -61,7 +65,7 @@ const Item = memo<ChatListItemProps>(({ index, id }) => {
61
65
 
62
66
  if (index >= chats.length) return;
63
67
 
64
- return chats[index];
68
+ return chats.find((s) => s.id === id);
65
69
  }, isEqual);
66
70
 
67
71
  const [
@@ -83,18 +87,18 @@ const Item = memo<ChatListItemProps>(({ index, id }) => {
83
87
  // when the message is in RAG flow or the AI generating, it should be in loading state
84
88
  const isProcessing = isInRAGFlow || generating;
85
89
 
86
- const onAvatarsClick = useAvatarsClick();
90
+ const onAvatarsClick = useAvatarsClick(item?.role);
87
91
 
88
- const RenderMessage = useCallback(
89
- ({ editableContent, data }: { data: ChatMessage; editableContent: ReactNode }) => {
92
+ const renderMessage = useCallback(
93
+ (editableContent: ReactNode) => {
90
94
  if (!item?.role) return;
91
95
  const RenderFunction = renderMessages[item.role] ?? renderMessages['default'];
92
96
 
93
97
  if (!RenderFunction) return;
94
98
 
95
- return <RenderFunction {...data} editableContent={editableContent} />;
99
+ return <RenderFunction {...item} editableContent={editableContent} />;
96
100
  },
97
- [item?.role],
101
+ [item],
98
102
  );
99
103
 
100
104
  const BelowMessage = useCallback(
@@ -136,7 +140,7 @@ const Item = memo<ChatListItemProps>(({ index, id }) => {
136
140
 
137
141
  const error = useErrorContent(item?.error);
138
142
 
139
- const historyLength = useChatStore((s) => chatSelectors.currentChats(s).length);
143
+ const [historyLength] = useChatStore((s) => [chatSelectors.currentChats(s).length]);
140
144
 
141
145
  const enableHistoryDivider = useAgentStore((s) => {
142
146
  const config = agentSelectors.currentAgentChatConfig(s);
@@ -151,6 +155,11 @@ const Item = memo<ChatListItemProps>(({ index, id }) => {
151
155
  const message =
152
156
  !editing && item?.role === 'assistant' ? processWithArtifact(item?.content) : item?.content;
153
157
 
158
+ // ======================= Performance Optimization ======================= //
159
+ // these useMemo/useCallback are all for the performance optimization
160
+ // maybe we can remove it in React 19
161
+ // ======================================================================== //
162
+
154
163
  const components = useMemo(
155
164
  () =>
156
165
  Object.fromEntries(
@@ -163,55 +172,83 @@ const Item = memo<ChatListItemProps>(({ index, id }) => {
163
172
  [id],
164
173
  );
165
174
 
175
+ const markdownProps = useMemo(
176
+ () => ({
177
+ components,
178
+ customRender: markdownCustomRender,
179
+ rehypePlugins,
180
+ }),
181
+ [components, markdownCustomRender],
182
+ );
183
+
184
+ const onChange = useCallback((value: string) => updateMessageContent(id, value), [id]);
185
+
186
+ const onDoubleClick = useCallback<MouseEventHandler<HTMLDivElement>>(
187
+ (e) => {
188
+ if (!item) return;
189
+ if (item.id === 'default' || item.error) return;
190
+ if (item.role && ['assistant', 'user'].includes(item.role) && e.altKey) {
191
+ toggleMessageEditing(id, true);
192
+ }
193
+ },
194
+ [item],
195
+ );
196
+
197
+ const text = useMemo(
198
+ () => ({
199
+ cancel: t('cancel'),
200
+ confirm: t('ok'),
201
+ edit: t('edit'),
202
+ }),
203
+ [t],
204
+ );
205
+
206
+ const onEditingChange = useCallback((edit: boolean) => {
207
+ toggleMessageEditing(id, edit);
208
+ }, []);
209
+
210
+ const actions = useMemo(
211
+ () =>
212
+ !hideActionBar && (
213
+ <ActionsBar
214
+ index={index}
215
+ setEditing={(edit) => {
216
+ toggleMessageEditing(id, edit);
217
+ }}
218
+ />
219
+ ),
220
+ [hideActionBar, index, id],
221
+ );
222
+
223
+ const belowMessage = useMemo(() => item && <BelowMessage data={item} />, [item]);
224
+ const errorMessage = useMemo(() => item && <ErrorMessageExtra data={item} />, [item]);
225
+ const messageExtra = useMemo(() => item && <MessageExtra data={item} />, [item]);
226
+
166
227
  return (
167
228
  item && (
168
229
  <>
169
230
  {enableHistoryDivider && <History />}
170
231
  <ChatItem
171
- actions={
172
- <ActionsBar
173
- index={index}
174
- setEditing={(edit) => {
175
- toggleMessageEditing(id, edit);
176
- }}
177
- />
178
- }
232
+ actions={actions}
179
233
  avatar={item.meta}
180
- belowMessage={<BelowMessage data={item} />}
234
+ belowMessage={belowMessage}
181
235
  className={cx(styles.message, isMessageLoading && styles.loading)}
182
236
  editing={editing}
183
237
  error={error}
184
- errorMessage={<ErrorMessageExtra data={item} />}
238
+ errorMessage={errorMessage}
185
239
  fontSize={fontSize}
186
240
  loading={isProcessing}
187
- markdownProps={{
188
- components,
189
- customRender: markdownCustomRender,
190
- rehypePlugins,
191
- }}
241
+ markdownProps={markdownProps}
192
242
  message={message}
193
- messageExtra={<MessageExtra data={item} />}
194
- onAvatarClick={onAvatarsClick?.(item.role)}
195
- onChange={(value) => updateMessageContent(item.id, value)}
196
- onDoubleClick={(e) => {
197
- if (item.id === 'default' || item.error) return;
198
- if (item.role && ['assistant', 'user'].includes(item.role) && e.altKey) {
199
- toggleMessageEditing(id, true);
200
- }
201
- }}
202
- onEditingChange={(edit) => {
203
- toggleMessageEditing(id, edit);
204
- }}
243
+ messageExtra={messageExtra}
244
+ onAvatarClick={onAvatarsClick}
245
+ onChange={onChange}
246
+ onDoubleClick={onDoubleClick}
247
+ onEditingChange={onEditingChange}
205
248
  placement={type === 'chat' ? (item.role === 'user' ? 'right' : 'left') : 'left'}
206
249
  primary={item.role === 'user'}
207
- renderMessage={(editableContent) => (
208
- <RenderMessage data={item} editableContent={editableContent} />
209
- )}
210
- text={{
211
- cancel: t('cancel'),
212
- confirm: t('ok'),
213
- edit: t('edit'),
214
- }}
250
+ renderMessage={renderMessage}
251
+ text={text}
215
252
  time={item.updatedAt || item.createdAt}
216
253
  type={type === 'chat' ? 'block' : 'pure'}
217
254
  />
@@ -220,4 +257,6 @@ const Item = memo<ChatListItemProps>(({ index, id }) => {
220
257
  );
221
258
  });
222
259
 
260
+ Item.displayName = 'ChatItem';
261
+
223
262
  export default Item;