@lobehub/chat 1.135.3 → 1.135.4

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 (116) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/changelog/v1.json +9 -0
  3. package/package.json +2 -2
  4. package/packages/const/src/index.ts +1 -0
  5. package/packages/const/src/settings/index.ts +1 -0
  6. package/packages/model-bank/src/aiModels/aihubmix.ts +25 -0
  7. package/packages/model-bank/src/aiModels/nvidia.ts +17 -1
  8. package/packages/model-bank/src/aiModels/openai.ts +80 -1
  9. package/packages/model-runtime/src/const/models.ts +2 -0
  10. package/packages/model-runtime/src/providers/openai/index.ts +15 -11
  11. package/packages/model-runtime/src/providers/openrouter/index.ts +7 -2
  12. package/packages/model-runtime/src/providers/openrouter/type.ts +4 -2
  13. package/packages/model-runtime/src/providers/vercelaigateway/index.ts +7 -0
  14. package/packages/model-runtime/src/utils/modelParse.ts +31 -3
  15. package/packages/types/src/aiProvider.ts +1 -2
  16. package/packages/types/src/discover/models.ts +3 -2
  17. package/packages/types/src/discover/providers.ts +3 -2
  18. package/packages/types/src/message/chat.ts +13 -0
  19. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatList/ChatItem/index.tsx +1 -5
  20. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatList/WelcomeChatItem/WelcomeMessage.tsx +1 -1
  21. package/src/app/[variants]/(main)/settings/provider/features/ModelList/CreateNewModelModal/Form.tsx +1 -2
  22. package/src/app/[variants]/(main)/settings/provider/features/ModelList/ModelItem.tsx +1 -4
  23. package/src/app/[variants]/(main)/settings/provider/features/ModelList/SortModelModal/ListItem.tsx +1 -2
  24. package/src/app/[variants]/(main)/settings/provider/features/ModelList/SortModelModal/index.tsx +1 -1
  25. package/src/{components → features}/ChatItem/ChatItem.tsx +5 -35
  26. package/src/{components → features}/ChatItem/components/MessageContent.tsx +27 -7
  27. package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/LobeArtifact/Render/index.tsx +1 -1
  28. package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/remarkPlugins/getNodeContent.test.ts +1 -1
  29. package/src/features/Conversation/{Actions → Messages/Assistant/Actions}/Error.tsx +1 -1
  30. package/src/features/Conversation/{components/ChatItem/ActionsBar.tsx → Messages/Assistant/Actions/index.tsx} +71 -44
  31. package/src/features/Conversation/Messages/Assistant/Block.tsx +63 -0
  32. package/src/features/Conversation/{Extras/Assistant.test.tsx → Messages/Assistant/Extra/index.test.tsx} +36 -31
  33. package/src/features/Conversation/{Extras/Assistant.tsx → Messages/Assistant/Extra/index.tsx} +13 -7
  34. package/src/features/Conversation/Messages/Assistant/MessageContent.tsx +102 -0
  35. package/src/features/Conversation/Messages/Assistant/index.tsx +235 -84
  36. package/src/features/Conversation/Messages/User/Actions.tsx +153 -0
  37. package/src/features/Conversation/Messages/User/BelowMessage.tsx +7 -2
  38. package/src/features/Conversation/{Extras/User.tsx → Messages/User/Extra.tsx} +9 -7
  39. package/src/features/Conversation/Messages/User/MessageContent.tsx +31 -0
  40. package/src/features/Conversation/Messages/User/index.tsx +127 -24
  41. package/src/features/Conversation/Messages/index.tsx +152 -0
  42. package/src/features/Conversation/{Extras → components/Extras}/Usage/UsageDetail/ModelCard.tsx +4 -3
  43. package/src/features/Conversation/{Extras → components/Extras}/Usage/UsageDetail/pricing.ts +3 -2
  44. package/src/features/Conversation/{Extras → components/Extras}/Usage/UsageDetail/tokens.test.ts +2 -3
  45. package/src/features/Conversation/components/{ChatItem/ShareMessageModal → ShareMessageModal}/ShareImage/Preview.tsx +1 -1
  46. package/src/features/Conversation/components/{ChatItem/ShareMessageModal → ShareMessageModal}/ShareText/index.tsx +1 -1
  47. package/src/features/Conversation/components/VirtualizedList/index.tsx +1 -0
  48. package/src/features/Conversation/hooks/useChatListActionsBar.tsx +29 -1
  49. package/src/features/Conversation/hooks/useDoubleClickEdit.ts +42 -0
  50. package/src/features/Conversation/index.ts +1 -1
  51. package/src/features/Conversation/types/{index.tsx → index.ts} +0 -7
  52. package/src/features/Portal/Thread/Chat/ChatItem.tsx +0 -7
  53. package/src/hooks/useUserAvatar.test.ts +129 -0
  54. package/src/hooks/useUserAvatar.ts +19 -0
  55. package/src/server/routers/lambda/aiModel.ts +7 -8
  56. package/src/store/user/slices/settings/selectors/settings.ts +6 -5
  57. package/src/features/ChatItem/index.tsx +0 -58
  58. package/src/features/Conversation/Actions/Assistant.tsx +0 -68
  59. package/src/features/Conversation/Actions/Fallback.tsx +0 -19
  60. package/src/features/Conversation/Actions/Tool.tsx +0 -33
  61. package/src/features/Conversation/Actions/User.tsx +0 -39
  62. package/src/features/Conversation/Actions/customAction.ts +0 -37
  63. package/src/features/Conversation/Actions/index.ts +0 -14
  64. package/src/features/Conversation/Extras/index.ts +0 -8
  65. package/src/features/Conversation/Extras/type.ts +0 -5
  66. package/src/features/Conversation/Messages/index.ts +0 -45
  67. package/src/features/Conversation/components/ChatItem/index.tsx +0 -358
  68. /package/src/{components → features}/ChatItem/components/Actions.tsx +0 -0
  69. /package/src/{components → features}/ChatItem/components/Avatar.tsx +0 -0
  70. /package/src/{components → features}/ChatItem/components/BorderSpacing.tsx +0 -0
  71. /package/src/{components → features}/ChatItem/components/ErrorContent.tsx +0 -0
  72. /package/src/{components → features}/ChatItem/components/Loading.tsx +0 -0
  73. /package/src/{components → features}/ChatItem/components/Title.tsx +0 -0
  74. /package/src/{components → features}/ChatItem/index.ts +0 -0
  75. /package/src/{components → features}/ChatItem/style.ts +0 -0
  76. /package/src/{components → features}/ChatItem/type.ts +0 -0
  77. /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/LobeArtifact/Render/Icon.tsx +0 -0
  78. /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/LobeArtifact/index.ts +0 -0
  79. /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/LobeArtifact/rehypePlugin.test.ts +0 -0
  80. /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/LobeArtifact/rehypePlugin.ts +0 -0
  81. /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/LobeThinking/Render.tsx +0 -0
  82. /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/LobeThinking/index.ts +0 -0
  83. /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/LocalFile/Render/index.tsx +0 -0
  84. /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/LocalFile/index.ts +0 -0
  85. /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/Thinking/Render.tsx +0 -0
  86. /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/Thinking/index.ts +0 -0
  87. /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/index.ts +0 -0
  88. /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/remarkPlugins/__snapshots__/createRemarkSelfClosingTagPlugin.test.ts.snap +0 -0
  89. /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/remarkPlugins/createRemarkCustomTagPlugin.ts +0 -0
  90. /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/remarkPlugins/createRemarkSelfClosingTagPlugin.test.ts +0 -0
  91. /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/remarkPlugins/createRemarkSelfClosingTagPlugin.ts +0 -0
  92. /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/remarkPlugins/getNodeContent.ts +0 -0
  93. /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/type.ts +0 -0
  94. /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/utils.ts +0 -0
  95. /package/src/features/Conversation/{Extras → components/Extras}/ExtraContainer.tsx +0 -0
  96. /package/src/features/Conversation/{Extras → components/Extras}/TTS/FilePlayer.tsx +0 -0
  97. /package/src/features/Conversation/{Extras → components/Extras}/TTS/InitPlayer.tsx +0 -0
  98. /package/src/features/Conversation/{Extras → components/Extras}/TTS/Player.tsx +0 -0
  99. /package/src/features/Conversation/{Extras → components/Extras}/TTS/index.tsx +0 -0
  100. /package/src/features/Conversation/{Extras → components/Extras}/Translate.tsx +0 -0
  101. /package/src/features/Conversation/{Extras → components/Extras}/Usage/UsageDetail/TokenProgress.tsx +0 -0
  102. /package/src/features/Conversation/{Extras → components/Extras}/Usage/UsageDetail/index.tsx +0 -0
  103. /package/src/features/Conversation/{Extras → components/Extras}/Usage/UsageDetail/tokens.ts +0 -0
  104. /package/src/features/Conversation/{Extras → components/Extras}/Usage/index.tsx +0 -0
  105. /package/src/features/Conversation/components/{ChatItem/ShareMessageModal → ShareMessageModal}/ShareImage/index.tsx +0 -0
  106. /package/src/features/Conversation/components/{ChatItem/ShareMessageModal → ShareMessageModal}/ShareImage/style.ts +0 -0
  107. /package/src/features/Conversation/components/{ChatItem/ShareMessageModal → ShareMessageModal}/ShareImage/type.ts +0 -0
  108. /package/src/features/Conversation/components/{ChatItem/ShareMessageModal → ShareMessageModal}/ShareText/Preview.tsx +0 -0
  109. /package/src/features/Conversation/components/{ChatItem/ShareMessageModal → ShareMessageModal}/ShareText/template.test.ts +0 -0
  110. /package/src/features/Conversation/components/{ChatItem/ShareMessageModal → ShareMessageModal}/ShareText/template.ts +0 -0
  111. /package/src/features/Conversation/components/{ChatItem/ShareMessageModal → ShareMessageModal}/ShareText/type.ts +0 -0
  112. /package/src/features/Conversation/components/{ChatItem/ShareMessageModal → ShareMessageModal}/index.tsx +0 -0
  113. /package/src/features/Conversation/components/{ChatItem/ShareMessageModal → ShareMessageModal}/style.ts +0 -0
  114. /package/src/features/Conversation/{components/ChatItem → context}/InPortalThreadContext.ts +0 -0
  115. /package/src/features/Conversation/{components/ChatItem/utils.test.ts → utils.test.ts} +0 -0
  116. /package/src/features/Conversation/{components/ChatItem/utils.ts → utils.ts} +0 -0
@@ -0,0 +1,129 @@
1
+ import { act, renderHook } from '@testing-library/react';
2
+ import { describe, expect, it, vi } from 'vitest';
3
+
4
+ import { useElectronStore } from '@/store/electron';
5
+ import { useUserStore } from '@/store/user';
6
+
7
+ import { useUserAvatar } from './useUserAvatar';
8
+
9
+ vi.mock('zustand/traditional');
10
+
11
+ // Mock @lobechat/const
12
+ let mockIsDesktop = false;
13
+
14
+ vi.mock('@lobechat/const', async (importOriginal) => {
15
+ const actual = await importOriginal<typeof import('@lobechat/const')>();
16
+ return {
17
+ ...actual,
18
+ get isDesktop() {
19
+ return mockIsDesktop;
20
+ },
21
+ DEFAULT_USER_AVATAR: 'default-avatar.png',
22
+ };
23
+ });
24
+
25
+ describe('useUserAvatar', () => {
26
+ it('should return default avatar when user has no avatar', () => {
27
+ act(() => {
28
+ useUserStore.setState({ user: { avatar: undefined } as any });
29
+ });
30
+
31
+ const { result } = renderHook(() => useUserAvatar());
32
+
33
+ expect(result.current).toBe('default-avatar.png');
34
+ });
35
+
36
+ it('should return user avatar when available', () => {
37
+ const mockAvatar = 'https://example.com/avatar.png';
38
+
39
+ act(() => {
40
+ useUserStore.setState({ user: { avatar: mockAvatar } as any });
41
+ });
42
+
43
+ const { result } = renderHook(() => useUserAvatar());
44
+
45
+ expect(result.current).toBe(mockAvatar);
46
+ });
47
+
48
+ it('should return original avatar in non-desktop environment', () => {
49
+ mockIsDesktop = false;
50
+ const mockAvatar = '/api/avatar.png';
51
+
52
+ act(() => {
53
+ useUserStore.setState({ user: { avatar: mockAvatar } as any });
54
+ useElectronStore.setState({
55
+ dataSyncConfig: { remoteServerUrl: 'https://server.com', storageMode: 'cloud' },
56
+ });
57
+ });
58
+
59
+ const { result } = renderHook(() => useUserAvatar());
60
+
61
+ expect(result.current).toBe(mockAvatar);
62
+ });
63
+
64
+ it('should return original avatar when no remote server URL in desktop environment', () => {
65
+ mockIsDesktop = true;
66
+ const mockAvatar = '/api/avatar.png';
67
+
68
+ act(() => {
69
+ useUserStore.setState({ user: { avatar: mockAvatar } as any });
70
+ useElectronStore.setState({
71
+ dataSyncConfig: { remoteServerUrl: undefined, storageMode: 'local' },
72
+ });
73
+ });
74
+
75
+ const { result } = renderHook(() => useUserAvatar());
76
+
77
+ expect(result.current).toBe(mockAvatar);
78
+ });
79
+
80
+ it('should prepend remote server URL when avatar starts with / in desktop environment', () => {
81
+ mockIsDesktop = true;
82
+ const mockAvatar = '/api/avatar.png';
83
+ const mockServerUrl = 'https://server.com';
84
+
85
+ act(() => {
86
+ useUserStore.setState({ user: { avatar: mockAvatar } as any });
87
+ useElectronStore.setState({
88
+ dataSyncConfig: { remoteServerUrl: mockServerUrl, storageMode: 'cloud' },
89
+ });
90
+ });
91
+
92
+ const { result } = renderHook(() => useUserAvatar());
93
+
94
+ expect(result.current).toBe('https://server.com/api/avatar.png');
95
+ });
96
+
97
+ it('should not prepend remote server URL when avatar does not start with / in desktop environment', () => {
98
+ mockIsDesktop = true;
99
+ const mockAvatar = 'https://example.com/avatar.png';
100
+ const mockServerUrl = 'https://server.com';
101
+
102
+ act(() => {
103
+ useUserStore.setState({ user: { avatar: mockAvatar } as any });
104
+ useElectronStore.setState({
105
+ dataSyncConfig: { remoteServerUrl: mockServerUrl, storageMode: 'cloud' },
106
+ });
107
+ });
108
+
109
+ const { result } = renderHook(() => useUserAvatar());
110
+
111
+ expect(result.current).toBe(mockAvatar);
112
+ });
113
+
114
+ it('should handle empty remote server URL in desktop environment', () => {
115
+ mockIsDesktop = true;
116
+ const mockAvatar = '/api/avatar.png';
117
+
118
+ act(() => {
119
+ useUserStore.setState({ user: { avatar: mockAvatar } as any });
120
+ useElectronStore.setState({
121
+ dataSyncConfig: { remoteServerUrl: '', storageMode: 'cloud' },
122
+ });
123
+ });
124
+
125
+ const { result } = renderHook(() => useUserAvatar());
126
+
127
+ expect(result.current).toBe(mockAvatar);
128
+ });
129
+ });
@@ -0,0 +1,19 @@
1
+ import { DEFAULT_USER_AVATAR, isDesktop } from '@lobechat/const';
2
+ import { useMemo } from 'react';
3
+
4
+ import { useElectronStore } from '@/store/electron';
5
+ import { electronSyncSelectors } from '@/store/electron/selectors';
6
+ import { useUserStore } from '@/store/user';
7
+ import { userProfileSelectors } from '@/store/user/selectors';
8
+
9
+ export const useUserAvatar = () => {
10
+ const avatar = useUserStore(userProfileSelectors.userAvatar) || DEFAULT_USER_AVATAR;
11
+ const remoteServerUrl = useElectronStore(electronSyncSelectors.remoteServerUrl);
12
+
13
+ return useMemo(() => {
14
+ // only process avatar in desktop environment and when avatar url starts with /
15
+ if (!isDesktop || !remoteServerUrl || !avatar || !avatar.startsWith('/')) return avatar;
16
+
17
+ return remoteServerUrl + avatar;
18
+ }, [avatar, remoteServerUrl]);
19
+ };
@@ -1,3 +1,10 @@
1
+ import {
2
+ AiModelTypeSchema,
3
+ AiProviderModelListItem,
4
+ CreateAiModelSchema,
5
+ ToggleAiModelEnableSchema,
6
+ UpdateAiModelSchema,
7
+ } from 'model-bank';
1
8
  import { z } from 'zod';
2
9
 
3
10
  import { AiModelModel } from '@/database/models/aiModel';
@@ -9,14 +16,6 @@ import { getServerGlobalConfig } from '@/server/globalConfig';
9
16
  import { KeyVaultsGateKeeper } from '@/server/modules/KeyVaultsEncrypt';
10
17
  import { ProviderConfig } from '@/types/user/settings';
11
18
 
12
- import {
13
- AiModelTypeSchema,
14
- AiProviderModelListItem,
15
- CreateAiModelSchema,
16
- ToggleAiModelEnableSchema,
17
- UpdateAiModelSchema,
18
- } from '../../../../packages/model-bank/src/types/aiModel';
19
-
20
19
  const aiModelProcedure = authedProcedure.use(serverDatabase).use(async (opts) => {
21
20
  const { ctx } = opts;
22
21
 
@@ -1,19 +1,20 @@
1
- import { DEFAULT_AGENT_META } from '@/const/meta';
2
1
  import {
3
2
  DEFAULT_AGENT,
4
3
  DEFAULT_AGENT_CONFIG,
4
+ DEFAULT_AGENT_META,
5
5
  DEFAULT_HOTKEY_CONFIG,
6
6
  DEFAULT_SYSTEM_AGENT_CONFIG,
7
7
  DEFAULT_TTS_CONFIG,
8
- } from '@/const/settings';
9
- import type { UserStore } from '@/store/user';
10
- import { HotkeyId } from '@/types/hotkey';
8
+ } from '@lobechat/const';
11
9
  import {
12
10
  GlobalLLMProviderKey,
11
+ HotkeyId,
13
12
  ProviderConfig,
14
13
  UserModelProviderConfig,
15
14
  UserSettings,
16
- } from '@/types/user/settings';
15
+ } from '@lobechat/types';
16
+
17
+ import type { UserStore } from '@/store/user';
17
18
  import { merge } from '@/utils/merge';
18
19
 
19
20
  export const currentSettings = (s: UserStore): UserSettings => merge(s.defaultSettings, s.settings);
@@ -1,58 +0,0 @@
1
- 'use client';
2
-
3
- import isEqual from 'fast-deep-equal';
4
- import { memo, useMemo } from 'react';
5
-
6
- import { ChatItemProps, ChatItem as ChatItemRaw } from '@/components/ChatItem';
7
- import { isDesktop } from '@/const/version';
8
- import { useElectronStore } from '@/store/electron';
9
- import { electronSyncSelectors } from '@/store/electron/selectors';
10
- import { useUserStore } from '@/store/user';
11
- import { settingsSelectors } from '@/store/user/selectors';
12
-
13
- const ChatItem = memo<ChatItemProps>(({ markdownProps = {}, avatar, ...rest }) => {
14
- const { componentProps, ...restMarkdown } = markdownProps;
15
- const { general } = useUserStore(settingsSelectors.currentSettings, isEqual);
16
-
17
- const remoteServerUrl = useElectronStore(electronSyncSelectors.remoteServerUrl);
18
- const processedAvatar = useMemo(() => {
19
- // only process avatar in desktop environment and when avatar url starts with /
20
- if (
21
- !isDesktop ||
22
- !remoteServerUrl ||
23
- !avatar.avatar ||
24
- typeof avatar.avatar !== 'string' ||
25
- !avatar.avatar.startsWith('/')
26
- )
27
- return avatar;
28
-
29
- return {
30
- ...avatar,
31
- avatar: remoteServerUrl + avatar.avatar, // prepend the remote server URL
32
- };
33
- }, [avatar, remoteServerUrl]);
34
-
35
- return (
36
- <ChatItemRaw
37
- avatar={processedAvatar}
38
- fontSize={general.fontSize}
39
- markdownProps={{
40
- ...restMarkdown,
41
- componentProps: {
42
- ...componentProps,
43
- highlight: {
44
- theme: general.highlighterTheme,
45
- ...componentProps?.highlight,
46
- },
47
- mermaid: {
48
- theme: general.mermaidTheme,
49
- ...componentProps?.mermaid,
50
- },
51
- },
52
- }}
53
- {...rest}
54
- />
55
- );
56
- });
57
-
58
- export default ChatItem;
@@ -1,68 +0,0 @@
1
- import { ActionIconGroup } from '@lobehub/ui';
2
- import type { ActionIconGroupItemType } from '@lobehub/ui';
3
- import { memo, useContext, useMemo } from 'react';
4
-
5
- import { useChatStore } from '@/store/chat';
6
- import { threadSelectors } from '@/store/chat/selectors';
7
-
8
- import { InPortalThreadContext } from '../components/ChatItem/InPortalThreadContext';
9
- import { useChatListActionsBar } from '../hooks/useChatListActionsBar';
10
- import { RenderAction } from '../types';
11
- import { ErrorActionsBar } from './Error';
12
- import { useCustomActions } from './customAction';
13
-
14
- export const AssistantActionsBar: RenderAction = memo(({ onActionClick, error, tools, id }) => {
15
- const [isThreadMode, hasThread] = useChatStore((s) => [
16
- !!s.activeThreadId,
17
- threadSelectors.hasThreadBySourceMsgId(id)(s),
18
- ]);
19
-
20
- const {
21
- regenerate,
22
- edit,
23
- delAndRegenerate,
24
- copy,
25
- divider,
26
- del,
27
- branching,
28
- // export: exportPDF,
29
- share,
30
- } = useChatListActionsBar({ hasThread });
31
-
32
- const { translate, tts } = useCustomActions();
33
- const hasTools = !!tools;
34
-
35
- const inPortalThread = useContext(InPortalThreadContext);
36
- const inThread = isThreadMode || inPortalThread;
37
-
38
- const items = useMemo(() => {
39
- if (hasTools) return [delAndRegenerate, copy];
40
-
41
- return [edit, copy, inThread ? null : branching].filter(Boolean) as ActionIconGroupItemType[];
42
- }, [inThread, hasTools]);
43
-
44
- if (error) return <ErrorActionsBar onActionClick={onActionClick} />;
45
-
46
- return (
47
- <ActionIconGroup
48
- items={items}
49
- menu={{
50
- items: [
51
- edit,
52
- copy,
53
- divider,
54
- tts,
55
- translate,
56
- divider,
57
- share,
58
- // exportPDF,
59
- divider,
60
- regenerate,
61
- delAndRegenerate,
62
- del,
63
- ],
64
- }}
65
- onActionClick={onActionClick}
66
- />
67
- );
68
- });
@@ -1,19 +0,0 @@
1
- import { ActionIconGroup } from '@lobehub/ui';
2
- import { memo } from 'react';
3
-
4
- import { useChatListActionsBar } from '../hooks/useChatListActionsBar';
5
- import type { RenderAction } from '../types';
6
-
7
- export const DefaultActionsBar: RenderAction = memo(({ onActionClick }) => {
8
- const { del } = useChatListActionsBar();
9
-
10
- return (
11
- <ActionIconGroup
12
- items={[]}
13
- menu={{
14
- items: [del],
15
- }}
16
- onActionClick={onActionClick}
17
- />
18
- );
19
- });
@@ -1,33 +0,0 @@
1
- import { ActionIconGroup } from '@lobehub/ui';
2
- import { memo } from 'react';
3
-
4
- import { useChatStore } from '@/store/chat';
5
-
6
- import { useChatListActionsBar } from '../hooks/useChatListActionsBar';
7
- import { RenderAction } from '../types';
8
-
9
- export const ToolActionsBar: RenderAction = memo(({ id }) => {
10
- const { regenerate, del } = useChatListActionsBar();
11
- const [reInvokeToolMessage, deleteToolMessage] = useChatStore((s) => [
12
- s.reInvokeToolMessage,
13
- s.deleteToolMessage,
14
- ]);
15
-
16
- return (
17
- <ActionIconGroup
18
- items={[regenerate, del]}
19
- onActionClick={async (event) => {
20
- switch (event.key) {
21
- case 'regenerate': {
22
- await reInvokeToolMessage(id);
23
- break;
24
- }
25
-
26
- case 'del': {
27
- await deleteToolMessage(id);
28
- }
29
- }
30
- }}
31
- />
32
- );
33
- });
@@ -1,39 +0,0 @@
1
- import { ActionIconGroup } from '@lobehub/ui';
2
- import { ActionIconGroupItemType } from '@lobehub/ui/es/ActionIconGroup';
3
- import { memo, useContext, useMemo } from 'react';
4
-
5
- import { useChatStore } from '@/store/chat';
6
- import { threadSelectors } from '@/store/chat/slices/thread/selectors';
7
-
8
- import { InPortalThreadContext } from '../components/ChatItem/InPortalThreadContext';
9
- import { useChatListActionsBar } from '../hooks/useChatListActionsBar';
10
- import { RenderAction } from '../types';
11
- import { useCustomActions } from './customAction';
12
-
13
- export const UserActionsBar: RenderAction = memo(({ onActionClick, id }) => {
14
- const [isThreadMode, hasThread] = useChatStore((s) => [
15
- !!s.activeThreadId,
16
- threadSelectors.hasThreadBySourceMsgId(id)(s),
17
- ]);
18
- const { regenerate, edit, copy, divider, del, branching } = useChatListActionsBar({ hasThread });
19
- const { translate, tts } = useCustomActions();
20
-
21
- const inPortalThread = useContext(InPortalThreadContext);
22
- const inThread = isThreadMode || inPortalThread;
23
-
24
- const items = useMemo(
25
- () =>
26
- [regenerate, edit, inThread ? null : branching].filter(Boolean) as ActionIconGroupItemType[],
27
- [inThread],
28
- );
29
-
30
- return (
31
- <ActionIconGroup
32
- items={items}
33
- menu={{
34
- items: [edit, copy, divider, tts, translate, divider, regenerate, del],
35
- }}
36
- onActionClick={onActionClick}
37
- />
38
- );
39
- });
@@ -1,37 +0,0 @@
1
- import type { ActionIconGroupItemType } from '@lobehub/ui';
2
- import { css, cx } from 'antd-style';
3
- import { LanguagesIcon, Play } from 'lucide-react';
4
- import { useMemo } from 'react';
5
- import { useTranslation } from 'react-i18next';
6
-
7
- import { localeOptions } from '@/locales/resources';
8
-
9
- const translateStyle = css`
10
- .ant-dropdown-menu-sub {
11
- overflow-y: scroll;
12
- max-height: 400px;
13
- }
14
- `;
15
-
16
- export const useCustomActions = () => {
17
- const { t } = useTranslation('chat');
18
-
19
- const translate = {
20
- children: localeOptions.map((i) => ({
21
- key: i.value,
22
- label: t(`lang.${i.value}`, { ns: 'common' }),
23
- })),
24
- icon: LanguagesIcon,
25
- key: 'translate',
26
- label: t('translate.action'),
27
- popupClassName: cx(translateStyle),
28
- } as ActionIconGroupItemType;
29
-
30
- const tts = {
31
- icon: Play,
32
- key: 'tts',
33
- label: t('tts.action'),
34
- } as ActionIconGroupItemType;
35
-
36
- return useMemo(() => ({ translate, tts }), []);
37
- };
@@ -1,14 +0,0 @@
1
- import { MessageRoleType } from '@/types/message';
2
-
3
- import { RenderAction } from '../types';
4
- import { AssistantActionsBar } from './Assistant';
5
- import { DefaultActionsBar } from './Fallback';
6
- import { ToolActionsBar } from './Tool';
7
- import { UserActionsBar } from './User';
8
-
9
- export const renderActions: Record<MessageRoleType, RenderAction> = {
10
- assistant: AssistantActionsBar,
11
- system: DefaultActionsBar,
12
- tool: ToolActionsBar,
13
- user: UserActionsBar,
14
- };
@@ -1,8 +0,0 @@
1
- import { RenderMessageExtra } from '../types';
2
- import { AssistantMessageExtra } from './Assistant';
3
- import { UserMessageExtra } from './User';
4
-
5
- export const renderMessagesExtra: Record<string, RenderMessageExtra> = {
6
- assistant: AssistantMessageExtra,
7
- user: UserMessageExtra,
8
- };
@@ -1,5 +0,0 @@
1
- import { FC } from 'react';
2
-
3
- import { ChatMessage } from '@/types/message';
4
-
5
- export type RenderMessageExtra = FC<ChatMessage>;
@@ -1,45 +0,0 @@
1
- import { useCallback } from 'react';
2
-
3
- import { useOpenChatSettings } from '@/hooks/useInterceptingRoutes';
4
- import { useGlobalStore } from '@/store/global';
5
- import { useSessionStore } from '@/store/session';
6
- import { sessionSelectors } from '@/store/session/selectors';
7
-
8
- import { MarkdownCustomRender, RenderBelowMessage, RenderMessage } from '../types';
9
- import { AssistantMessage } from './Assistant';
10
- import { DefaultBelowMessage, DefaultMessage } from './Default';
11
- import { UserBelowMessage, UserMarkdownRender, UserMessage } from './User';
12
-
13
- export const renderMessages: Record<string, RenderMessage> = {
14
- assistant: AssistantMessage,
15
- default: DefaultMessage,
16
- function: DefaultMessage,
17
- user: UserMessage,
18
- };
19
-
20
- export const renderBelowMessages: Record<string, RenderBelowMessage> = {
21
- default: DefaultBelowMessage,
22
- user: UserBelowMessage,
23
- };
24
-
25
- export const markdownCustomRenders: Record<string, MarkdownCustomRender> = {
26
- user: UserMarkdownRender,
27
- };
28
-
29
- export const useAvatarsClick = (role?: string) => {
30
- const [isInbox] = useSessionStore((s) => [sessionSelectors.isInboxSession(s)]);
31
- const [toggleSystemRole] = useGlobalStore((s) => [s.toggleSystemRole]);
32
- const openChatSettings = useOpenChatSettings();
33
-
34
- return useCallback(() => {
35
- switch (role) {
36
- case 'assistant': {
37
- if (!isInbox) {
38
- toggleSystemRole(true);
39
- } else {
40
- openChatSettings();
41
- }
42
- }
43
- }
44
- }, [isInbox, role]);
45
- };