@lobehub/chat 0.118.5 → 0.118.7

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 (84) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/next.config.mjs +0 -1
  3. package/package.json +1 -1
  4. package/src/app/api/openai/chat/createChatCompletion.test.ts +37 -0
  5. package/src/app/api/openai/chat/createChatCompletion.ts +10 -2
  6. package/src/app/api/openai/chat/desensitizeUrl.test.ts +47 -0
  7. package/src/app/api/openai/chat/desensitizeUrl.ts +34 -0
  8. package/src/app/chat/features/ChatHeader/ShareButton/Preview.tsx +1 -1
  9. package/src/features/Conversation/{ChatList/Actions → Actions}/Assistant.tsx +3 -1
  10. package/src/features/Conversation/{ChatList/Actions → Actions}/Error.tsx +3 -1
  11. package/src/features/Conversation/{ChatList/Actions → Actions}/Fallback.tsx +4 -1
  12. package/src/features/Conversation/{ChatList/Actions → Actions}/Function.tsx +4 -1
  13. package/src/features/Conversation/{ChatList/Actions → Actions}/User.tsx +3 -1
  14. package/src/features/Conversation/{ChatList/Actions → Actions}/index.ts +1 -2
  15. package/src/features/Conversation/{ChatList/Error → Error}/InvalidAccess.tsx +2 -1
  16. package/src/features/Conversation/{ChatList/Error → Error}/OpenAPIKey.tsx +1 -1
  17. package/src/features/Conversation/{ChatList/Error → Error}/OpenAiBizError.tsx +2 -1
  18. package/src/features/Conversation/{ChatList/Error → Error}/Plugin/PluginError.tsx +3 -1
  19. package/src/features/Conversation/{ChatList/Error → Error}/Plugin/PluginSettings.tsx +2 -1
  20. package/src/features/Conversation/{ChatList/Error → Error}/index.tsx +1 -1
  21. package/src/features/Conversation/{ChatList/Extras → Extras}/Translate.tsx +1 -1
  22. package/src/features/Conversation/{ChatList/Extras → Extras}/index.ts +1 -2
  23. package/src/features/Conversation/{ChatList/Messages → Messages}/Default.tsx +1 -1
  24. package/src/features/Conversation/{ChatList/Messages → Messages}/User.tsx +1 -1
  25. package/src/features/Conversation/{ChatList/Messages → Messages}/index.ts +5 -5
  26. package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/Loading.tsx +10 -11
  27. package/src/features/Conversation/components/ChatList/ActionsBar.tsx +27 -0
  28. package/src/features/Conversation/components/ChatList/HistoryDivider.tsx +23 -0
  29. package/src/features/Conversation/components/ChatList/Item.tsx +236 -0
  30. package/src/features/Conversation/components/ChatList/index.tsx +88 -0
  31. package/src/features/Conversation/components/ChatList/style.ts +10 -0
  32. package/src/features/Conversation/{ChatList → container}/index.tsx +6 -7
  33. package/src/features/Conversation/hooks/useChatListActionsBar.tsx +43 -0
  34. package/src/features/Conversation/index.tsx +3 -3
  35. package/src/store/middleware/createHyperStorage/index.test.ts +341 -0
  36. package/src/store/middleware/createHyperStorage/indexedDB.test.ts +64 -0
  37. package/src/store/middleware/createHyperStorage/urlStorage.test.ts +84 -0
  38. package/src/store/middleware/createHyperStorage/urlStorage.ts +25 -8
  39. /package/src/features/Conversation/{ChatList/Actions → Actions}/customAction.ts +0 -0
  40. /package/src/features/Conversation/{ChatList/Error → Error}/ApiKeyForm.tsx +0 -0
  41. /package/src/features/Conversation/{ChatList/Error → Error}/ErrorActionContainer.tsx +0 -0
  42. /package/src/features/Conversation/{ChatList/Error → Error}/style.tsx +0 -0
  43. /package/src/features/Conversation/{ChatList/Extras → Extras}/Assistant.test.tsx +0 -0
  44. /package/src/features/Conversation/{ChatList/Extras → Extras}/Assistant.tsx +0 -0
  45. /package/src/features/Conversation/{ChatList/Extras → Extras}/ExtraContainer.tsx +0 -0
  46. /package/src/features/Conversation/{ChatList/Extras → Extras}/TTS/FilePlayer.tsx +0 -0
  47. /package/src/features/Conversation/{ChatList/Extras → Extras}/TTS/InitPlayer.tsx +0 -0
  48. /package/src/features/Conversation/{ChatList/Extras → Extras}/TTS/Player.tsx +0 -0
  49. /package/src/features/Conversation/{ChatList/Extras → Extras}/TTS/index.tsx +0 -0
  50. /package/src/features/Conversation/{ChatList/Extras → Extras}/User.tsx +0 -0
  51. /package/src/features/Conversation/{ChatList/Extras → Extras}/type.ts +0 -0
  52. /package/src/features/Conversation/{ChatList/Messages → Messages}/Assistant.tsx +0 -0
  53. /package/src/features/Conversation/{ChatList/Messages → Messages}/Function.tsx +0 -0
  54. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Inspector/PluginResultJSON.tsx +0 -0
  55. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Inspector/Settings.tsx +0 -0
  56. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Inspector/index.tsx +0 -0
  57. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Inspector/style.ts +0 -0
  58. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/BuiltinType/index.test.tsx +0 -0
  59. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/BuiltinType/index.tsx +0 -0
  60. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/DefaultType/IFrameRender/index.tsx +0 -0
  61. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/DefaultType/SystemJsRender/index.tsx +0 -0
  62. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/DefaultType/SystemJsRender/utils.ts +0 -0
  63. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/DefaultType/index.tsx +0 -0
  64. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/MarkdownType/index.tsx +0 -0
  65. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/StandaloneType/Iframe.tsx +0 -0
  66. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/StandaloneType/index.tsx +0 -0
  67. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/index.tsx +0 -0
  68. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/useParseContent.ts +0 -0
  69. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/utils/iframeOnReady.test.ts +0 -0
  70. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/utils/iframeOnReady.ts +0 -0
  71. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/utils/listenToPlugin.test.ts +0 -0
  72. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/utils/listenToPlugin.ts +0 -0
  73. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/utils/pluginSettings.test.ts +0 -0
  74. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/utils/pluginSettings.ts +0 -0
  75. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/utils/pluginState.test.ts +0 -0
  76. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/utils/pluginState.ts +0 -0
  77. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/utils/postMessage.test.ts +0 -0
  78. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/utils/postMessage.ts +0 -0
  79. /package/src/features/Conversation/{ChatList/Loading.tsx → components/BubblesLoading.tsx} +0 -0
  80. /package/src/features/Conversation/{ChatList → components}/OTPInput.tsx +0 -0
  81. /package/src/features/Conversation/{ScrollAnchor → components/ScrollAnchor}/index.tsx +0 -0
  82. /package/src/features/Conversation/{ScrollAnchor → components/ScrollAnchor}/useAtBottom.ts +0 -0
  83. /package/src/features/Conversation/{ChatList → components}/SkeletonList.tsx +0 -0
  84. /package/src/features/Conversation/{useInitConversation.ts → hooks/useInitConversation.ts} +0 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,56 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 0.118.7](https://github.com/lobehub/lobe-chat/compare/v0.118.6...v0.118.7)
6
+
7
+ <sup>Released on **2024-01-03**</sup>
8
+
9
+ #### 🐛 Bug Fixes
10
+
11
+ - **misc**: Desensitize openai base url in the error response.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### What's fixed
19
+
20
+ - **misc**: Desensitize openai base url in the error response, closes [#918](https://github.com/lobehub/lobe-chat/issues/918) ([ab0aeb7](https://github.com/lobehub/lobe-chat/commit/ab0aeb7))
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.118.6](https://github.com/lobehub/lobe-chat/compare/v0.118.5...v0.118.6)
31
+
32
+ <sup>Released on **2024-01-03**</sup>
33
+
34
+ #### ♻ Code Refactoring
35
+
36
+ - **misc**: Migration the ChatList into Conversation.
37
+
38
+ <br/>
39
+
40
+ <details>
41
+ <summary><kbd>Improvements and Fixes</kbd></summary>
42
+
43
+ #### Code refactoring
44
+
45
+ - **misc**: Migration the ChatList into Conversation, closes [#916](https://github.com/lobehub/lobe-chat/issues/916) ([6ee3795](https://github.com/lobehub/lobe-chat/commit/6ee3795))
46
+
47
+ </details>
48
+
49
+ <div align="right">
50
+
51
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
52
+
53
+ </div>
54
+
5
55
  ### [Version 0.118.5](https://github.com/lobehub/lobe-chat/compare/v0.118.4...v0.118.5)
6
56
 
7
57
  <sup>Released on **2024-01-02**</sup>
package/next.config.mjs CHANGED
@@ -20,7 +20,6 @@ const withPWA = nextPWA({
20
20
  const nextConfig = {
21
21
  compress: isProd,
22
22
  experimental: {
23
- forceSwcTransforms: true,
24
23
  optimizePackageImports: [
25
24
  'modern-screenshot',
26
25
  'emoji-mart',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "0.118.5",
3
+ "version": "0.118.7",
4
4
  "description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
5
5
  "keywords": [
6
6
  "framework",
@@ -73,6 +73,7 @@ describe('createChatCompletion', () => {
73
73
  expect(result).toBeInstanceOf(Response);
74
74
  expect(result.status).toBe(577); // Your custom error status code
75
75
  });
76
+
76
77
  it('should return an cause response when OpenAI.APIError is thrown with cause', async () => {
77
78
  // Arrange
78
79
  const errorInfo = {
@@ -101,6 +102,42 @@ describe('createChatCompletion', () => {
101
102
 
102
103
  const content = await result.json();
103
104
  expect(content.body).toHaveProperty('endpoint');
105
+ expect(content.body.endpoint).toEqual('https://api.openai.com/v1');
106
+ expect(content.body.error).toEqual(errorInfo);
107
+ });
108
+
109
+ it('should return an cause response with desensitize Url', async () => {
110
+ // Arrange
111
+ const errorInfo = {
112
+ stack: 'abc',
113
+ cause: { message: 'api is undefined' },
114
+ };
115
+ const apiError = new OpenAI.APIError(400, errorInfo, 'module error', {});
116
+
117
+ openaiInstance = new OpenAI({
118
+ apiKey: 'test',
119
+ dangerouslyAllowBrowser: true,
120
+ baseURL: 'https://api.abc.com/v1',
121
+ });
122
+
123
+ vi.spyOn(openaiInstance.chat.completions, 'create').mockRejectedValue(apiError);
124
+
125
+ // Act
126
+ const result = await createChatCompletion({
127
+ openai: openaiInstance,
128
+ payload: {
129
+ messages: [{ content: 'Hello', role: 'user' }],
130
+ model: 'gpt-3.5-turbo',
131
+ temperature: 0,
132
+ },
133
+ });
134
+
135
+ // Assert
136
+ expect(result).toBeInstanceOf(Response);
137
+ expect(result.status).toBe(577); // Your custom error status code
138
+
139
+ const content = await result.json();
140
+ expect(content.body.endpoint).toEqual('https://api.***.com/v1');
104
141
  expect(content.body.error).toEqual(errorInfo);
105
142
  });
106
143
 
@@ -5,6 +5,7 @@ import { ChatErrorType } from '@/types/fetch';
5
5
  import { OpenAIChatStreamPayload } from '@/types/openai/chat';
6
6
 
7
7
  import { createErrorResponse } from '../errorResponse';
8
+ import { desensitizeUrl } from './desensitizeUrl';
8
9
 
9
10
  interface CreateChatCompletionOptions {
10
11
  openai: OpenAI;
@@ -29,6 +30,13 @@ export const createChatCompletion = async ({ payload, openai }: CreateChatComple
29
30
  const stream = OpenAIStream(response);
30
31
  return new StreamingTextResponse(stream);
31
32
  } catch (error) {
33
+ let desensitizedEndpoint = openai.baseURL;
34
+
35
+ // refs: https://github.com/lobehub/lobe-chat/issues/842
36
+ if (openai.baseURL !== 'https://api.openai.com/v1') {
37
+ desensitizedEndpoint = desensitizeUrl(openai.baseURL);
38
+ }
39
+
32
40
  // Check if the error is an OpenAI APIError
33
41
  if (error instanceof OpenAI.APIError) {
34
42
  let errorResult: any;
@@ -51,7 +59,7 @@ export const createChatCompletion = async ({ payload, openai }: CreateChatComple
51
59
  console.error(errorResult);
52
60
 
53
61
  return createErrorResponse(ChatErrorType.OpenAIBizError, {
54
- endpoint: openai.baseURL,
62
+ endpoint: desensitizedEndpoint,
55
63
  error: errorResult,
56
64
  });
57
65
  }
@@ -61,7 +69,7 @@ export const createChatCompletion = async ({ payload, openai }: CreateChatComple
61
69
 
62
70
  // return as a GatewayTimeout error
63
71
  return createErrorResponse(ChatErrorType.InternalServerError, {
64
- endpoint: openai.baseURL,
72
+ endpoint: desensitizedEndpoint,
65
73
  error: JSON.stringify(error),
66
74
  });
67
75
  }
@@ -0,0 +1,47 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { desensitizeUrl } from './desensitizeUrl';
4
+
5
+ describe('desensitizeUrl', () => {
6
+ it('should desensitize a URL with a subdomain', () => {
7
+ const originalUrl = 'https://api.example.com/v1';
8
+ const result = desensitizeUrl(originalUrl);
9
+ expect(result).toBe('https://api.ex****le.com/v1');
10
+ });
11
+
12
+ it('should desensitize a URL without a subdomain', () => {
13
+ const originalUrl = 'https://example.com/v1';
14
+ const result = desensitizeUrl(originalUrl);
15
+ expect(result).toBe('https://ex****le.com/v1');
16
+ });
17
+
18
+ it('should desensitize a URL without a subdomain less then 5 chartarters', () => {
19
+ const originalUrl = 'https://abc.com/v1';
20
+ const result = desensitizeUrl(originalUrl);
21
+ expect(result).toBe('https://***.com/v1');
22
+ });
23
+
24
+ it('should desensitize a URL with multiple subdomains', () => {
25
+ const originalUrl = 'https://sub.api.example.com/v1';
26
+ const result = desensitizeUrl(originalUrl);
27
+ expect(result).toBe('https://sub.api.ex****le.com/v1');
28
+ });
29
+
30
+ it('should desensitize a URL with path and query parameters', () => {
31
+ const originalUrl = 'https://api.example.com/v1?query=123';
32
+ const result = desensitizeUrl(originalUrl);
33
+ expect(result).toBe('https://api.ex****le.com/v1?query=123');
34
+ });
35
+
36
+ it('should return the original URL if it is invalid', () => {
37
+ const originalUrl = 'invalidurl';
38
+ const result = desensitizeUrl(originalUrl);
39
+ expect(result).toBe(originalUrl);
40
+ });
41
+
42
+ it('should desensitize a URL with a port number', () => {
43
+ const originalUrl = 'https://api.example.com:8080/v1';
44
+ const result = desensitizeUrl(originalUrl);
45
+ expect(result).toBe('https://api.ex****le.com:****/v1');
46
+ });
47
+ });
@@ -0,0 +1,34 @@
1
+ export const desensitizeUrl = (url: string) => {
2
+ try {
3
+ const urlObj = new URL(url);
4
+ const hostnameParts = urlObj.hostname.split('.');
5
+ const port = urlObj.port;
6
+
7
+ // Desensitize domain only if there are at least two parts (example.com)
8
+ if (hostnameParts.length > 1) {
9
+ // Desensitize the second level domain (second part from the right)
10
+ // Special case for short domain names
11
+ const secondLevelDomainIndex = hostnameParts.length - 2;
12
+ if (hostnameParts[secondLevelDomainIndex].length < 5) {
13
+ hostnameParts[secondLevelDomainIndex] = '***';
14
+ } else {
15
+ hostnameParts[secondLevelDomainIndex] = hostnameParts[secondLevelDomainIndex].replace(
16
+ /^(.*?)(\w{2})(\w+)(\w{2})$/,
17
+ (_, prefix, start, middle, end) => `${prefix}${start}****${end}`,
18
+ );
19
+ }
20
+ }
21
+
22
+ // Join the hostname parts back together
23
+ const desensitizedHostname = hostnameParts.join('.');
24
+
25
+ // Desensitize port if present
26
+ const desensitizedPort = port ? ':****' : '';
27
+
28
+ // Reconstruct the URL with the desensitized parts
29
+ return `${urlObj.protocol}//${desensitizedHostname}${desensitizedPort}${urlObj.pathname}${urlObj.search}`;
30
+ } catch {
31
+ // If the URL is invalid, return the original URL
32
+ return url;
33
+ }
34
+ };
@@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next';
5
5
  import { Flexbox } from 'react-layout-kit';
6
6
 
7
7
  import pkg from '@/../package.json';
8
- import ChatList from '@/features/Conversation/ChatList';
8
+ import ChatList from '@/features/Conversation/container';
9
9
  import { useSessionStore } from '@/store/session';
10
10
  import { agentSelectors, sessionSelectors } from '@/store/session/selectors';
11
11
 
@@ -1,6 +1,8 @@
1
- import { ActionIconGroup, RenderAction, useChatListActionsBar } from '@lobehub/ui';
1
+ import { ActionIconGroup } from '@lobehub/ui';
2
2
  import { memo } from 'react';
3
3
 
4
+ import { RenderAction } from '../components/ChatList';
5
+ import { useChatListActionsBar } from '../hooks/useChatListActionsBar';
4
6
  import { ErrorActionsBar } from './Error';
5
7
  import { useCustomActions } from './customAction';
6
8
 
@@ -1,7 +1,9 @@
1
- import { ActionIconGroup, useChatListActionsBar } from '@lobehub/ui';
1
+ import { ActionIconGroup } from '@lobehub/ui';
2
2
  import { ActionsBarProps } from '@lobehub/ui/es/ChatList/ActionsBar';
3
3
  import { memo } from 'react';
4
4
 
5
+ import { useChatListActionsBar } from '../hooks/useChatListActionsBar';
6
+
5
7
  export const ErrorActionsBar = memo<ActionsBarProps>(({ text, onActionClick }) => {
6
8
  const { regenerate, del } = useChatListActionsBar(text);
7
9
 
@@ -1,6 +1,9 @@
1
- import { ActionIconGroup, RenderAction, useChatListActionsBar } from '@lobehub/ui';
1
+ import { ActionIconGroup } from '@lobehub/ui';
2
2
  import { memo } from 'react';
3
3
 
4
+ import { RenderAction } from '../components/ChatList';
5
+ import { useChatListActionsBar } from '../hooks/useChatListActionsBar';
6
+
4
7
  export const DefaultActionsBar: RenderAction = memo(({ text, onActionClick }) => {
5
8
  const { del } = useChatListActionsBar(text);
6
9
  return (
@@ -1,6 +1,9 @@
1
- import { ActionIconGroup, RenderAction, useChatListActionsBar } from '@lobehub/ui';
1
+ import { ActionIconGroup } from '@lobehub/ui';
2
2
  import { memo } from 'react';
3
3
 
4
+ import { RenderAction } from '../components/ChatList';
5
+ import { useChatListActionsBar } from '../hooks/useChatListActionsBar';
6
+
4
7
  export const FunctionActionsBar: RenderAction = memo(({ text, onActionClick }) => {
5
8
  const { regenerate, divider, del } = useChatListActionsBar(text);
6
9
  return (
@@ -1,6 +1,8 @@
1
- import { ActionIconGroup, RenderAction, useChatListActionsBar } from '@lobehub/ui';
1
+ import { ActionIconGroup } from '@lobehub/ui';
2
2
  import { memo } from 'react';
3
3
 
4
+ import { RenderAction } from '../components/ChatList';
5
+ import { useChatListActionsBar } from '../hooks/useChatListActionsBar';
4
6
  import { useCustomActions } from './customAction';
5
7
 
6
8
  export const UserActionsBar: RenderAction = memo(({ text, onActionClick }) => {
@@ -1,7 +1,6 @@
1
- import { ChatListProps } from '@lobehub/ui';
2
-
3
1
  import { useChatStore } from '@/store/chat';
4
2
 
3
+ import { ChatListProps } from '../components/ChatList';
5
4
  import { AssistantActionsBar } from './Assistant';
6
5
  import { DefaultActionsBar } from './Fallback';
7
6
  import { FunctionActionsBar } from './Function';
@@ -1,4 +1,4 @@
1
- import { Icon, RenderErrorMessage } from '@lobehub/ui';
1
+ import { Icon } from '@lobehub/ui';
2
2
  import { Button, Input, Segmented } from 'antd';
3
3
  import { KeySquare, SquareAsterisk } from 'lucide-react';
4
4
  import { memo, useState } from 'react';
@@ -8,6 +8,7 @@ import { Flexbox } from 'react-layout-kit';
8
8
  import { useChatStore } from '@/store/chat';
9
9
  import { useGlobalStore } from '@/store/global';
10
10
 
11
+ import { RenderErrorMessage } from '../components/ChatList';
11
12
  import APIKeyForm from './ApiKeyForm';
12
13
  import { ErrorActionContainer, FormAction } from './style';
13
14
 
@@ -1,6 +1,6 @@
1
- import { RenderErrorMessage } from '@lobehub/ui';
2
1
  import { memo } from 'react';
3
2
 
3
+ import { RenderErrorMessage } from '../components/ChatList';
4
4
  import APIKeyForm from './ApiKeyForm';
5
5
  import { ErrorActionContainer } from './style';
6
6
 
@@ -1,7 +1,8 @@
1
- import { Highlighter, RenderErrorMessage } from '@lobehub/ui';
1
+ import { Highlighter } from '@lobehub/ui';
2
2
  import { memo } from 'react';
3
3
  import { Flexbox } from 'react-layout-kit';
4
4
 
5
+ import { RenderErrorMessage } from '../components/ChatList';
5
6
  import OpenAPIKey from './OpenAPIKey';
6
7
 
7
8
  interface OpenAIError {
@@ -1,7 +1,9 @@
1
- import { Highlighter, RenderErrorMessage } from '@lobehub/ui';
1
+ import { Highlighter } from '@lobehub/ui';
2
2
  import { memo } from 'react';
3
3
  import { Flexbox } from 'react-layout-kit';
4
4
 
5
+ import { RenderErrorMessage } from '../../components/ChatList';
6
+
5
7
  interface OpenAIError {
6
8
  code: 'invalid_api_key' | string;
7
9
  message: string;
@@ -1,4 +1,4 @@
1
- import { Avatar, RenderErrorMessage } from '@lobehub/ui';
1
+ import { Avatar } from '@lobehub/ui';
2
2
  import { Button, Divider } from 'antd';
3
3
  import { useTheme } from 'antd-style';
4
4
  import isEqual from 'fast-deep-equal';
@@ -11,6 +11,7 @@ import { useChatStore } from '@/store/chat';
11
11
  import { pluginHelpers, useToolStore } from '@/store/tool';
12
12
  import { pluginSelectors } from '@/store/tool/selectors';
13
13
 
14
+ import { RenderErrorMessage } from '../../components/ChatList';
14
15
  import { ErrorActionContainer, useStyles } from '../style';
15
16
 
16
17
  const PluginSettings: RenderErrorMessage['Render'] = memo(({ id, plugin }) => {
@@ -1,8 +1,8 @@
1
1
  import { PluginErrorType } from '@lobehub/chat-plugin-sdk';
2
- import { ChatListProps } from '@lobehub/ui';
3
2
 
4
3
  import { ChatErrorType } from '@/types/fetch';
5
4
 
5
+ import { ChatListProps } from '../components/ChatList';
6
6
  import InvalidAccess from './InvalidAccess';
7
7
  import OpenAPIKey from './OpenAPIKey';
8
8
  import OpenAiBizError from './OpenAiBizError';
@@ -10,7 +10,7 @@ import { Flexbox } from 'react-layout-kit';
10
10
  import { useChatStore } from '@/store/chat';
11
11
  import { ChatTranslate } from '@/types/message';
12
12
 
13
- import BubblesLoading from '../Loading';
13
+ import BubblesLoading from '../components/BubblesLoading';
14
14
 
15
15
  const useStyles = createStyles(({ stylish }) => ({
16
16
  markdown: stylish.markdownInChat,
@@ -1,5 +1,4 @@
1
- import { ChatListProps, RenderMessageExtra } from '@lobehub/ui';
2
-
1
+ import { ChatListProps, RenderMessageExtra } from '../components/ChatList';
3
2
  import { AssistantMessageExtra } from './Assistant';
4
3
  import { UserMessageExtra } from './User';
5
4
 
@@ -3,7 +3,7 @@ import { ReactNode, memo } from 'react';
3
3
  import { LOADING_FLAT } from '@/const/message';
4
4
  import { ChatMessage } from '@/types/message';
5
5
 
6
- import BubblesLoading from '../Loading';
6
+ import BubblesLoading from '../components/BubblesLoading';
7
7
 
8
8
  export const DefaultMessage = memo<
9
9
  ChatMessage & {
@@ -5,7 +5,7 @@ import FileList from '@/components/FileList';
5
5
  import { LOADING_FLAT } from '@/const/message';
6
6
  import { ChatMessage } from '@/types/message';
7
7
 
8
- import BubblesLoading from '../Loading';
8
+ import BubblesLoading from '../components/BubblesLoading';
9
9
 
10
10
  export const UserMessage = memo<
11
11
  ChatMessage & {
@@ -1,4 +1,3 @@
1
- import { ChatListProps } from '@lobehub/ui';
2
1
  import { useResponsive } from 'antd-style';
3
2
  import { useRouter } from 'next/navigation';
4
3
 
@@ -7,16 +6,17 @@ import { useSessionStore } from '@/store/session';
7
6
  import { sessionSelectors } from '@/store/session/selectors';
8
7
  import { pathString } from '@/utils/url';
9
8
 
9
+ import { ChatListProps } from '../components/ChatList';
10
10
  import { AssistantMessage } from './Assistant';
11
11
  import { DefaultMessage } from './Default';
12
12
  import { FunctionMessage } from './Function';
13
13
  import { UserMessage } from './User';
14
14
 
15
15
  export const renderMessages: ChatListProps['renderMessages'] = {
16
- assistant: AssistantMessage as any,
17
- default: DefaultMessage as any,
18
- function: FunctionMessage as any,
19
- user: UserMessage as any,
16
+ assistant: AssistantMessage,
17
+ default: DefaultMessage,
18
+ function: FunctionMessage,
19
+ user: UserMessage,
20
20
  };
21
21
 
22
22
  export const useAvatarsClick = (): ChatListProps['onAvatarsClick'] => {
@@ -1,11 +1,10 @@
1
- import {createStyles} from 'antd-style';
2
- import {useTranslation} from 'react-i18next';
3
- import {Flexbox} from 'react-layout-kit';
4
- import {memo} from "react";
5
-
1
+ import { createStyles } from 'antd-style';
2
+ import { memo } from 'react';
3
+ import { useTranslation } from 'react-i18next';
4
+ import { Flexbox } from 'react-layout-kit';
6
5
 
7
6
  const useStyles = createStyles(
8
- ({css, token}) => css`
7
+ ({ css, token }) => css`
9
8
  position: relative;
10
9
 
11
10
  overflow: hidden;
@@ -46,16 +45,16 @@ const useStyles = createStyles(
46
45
  }
47
46
  `,
48
47
  );
49
- const Loading = memo(() => {
50
- const {t} = useTranslation('plugin');
51
- const {styles} = useStyles();
48
+ const Loading = memo(() => {
49
+ const { t } = useTranslation('plugin');
50
+ const { styles } = useStyles();
52
51
 
53
52
  return (
54
53
  <Flexbox align={'center'} gap={8} padding={16}>
55
- <span className={styles}/>
54
+ <span className={styles} />
56
55
  {t('loading.content')}
57
56
  </Flexbox>
58
57
  );
59
58
  });
60
59
 
61
- export default Loading
60
+ export default Loading;
@@ -0,0 +1,27 @@
1
+ import { ActionIconGroup, type ActionIconGroupProps } from '@lobehub/ui';
2
+ import { memo } from 'react';
3
+
4
+ import { useChatListActionsBar } from '../../hooks/useChatListActionsBar';
5
+
6
+ export interface ActionsBarProps extends ActionIconGroupProps {
7
+ text?: {
8
+ copy?: string;
9
+ delete?: string;
10
+ edit?: string;
11
+ regenerate?: string;
12
+ };
13
+ }
14
+
15
+ const ActionsBar = memo<ActionsBarProps>(({ text, ...rest }) => {
16
+ const { regenerate, edit, copy, divider, del } = useChatListActionsBar(text);
17
+ return (
18
+ <ActionIconGroup
19
+ dropdownMenu={[edit, copy, regenerate, divider, del]}
20
+ items={[regenerate, edit]}
21
+ type="ghost"
22
+ {...rest}
23
+ />
24
+ );
25
+ });
26
+
27
+ export default ActionsBar;
@@ -0,0 +1,23 @@
1
+ import { Icon, Tag } from '@lobehub/ui';
2
+ import { Divider } from 'antd';
3
+ import { Timer } from 'lucide-react';
4
+ import { memo } from 'react';
5
+
6
+ interface HistoryDividerProps {
7
+ enable?: boolean;
8
+ text?: string;
9
+ }
10
+
11
+ const HistoryDivider = memo<HistoryDividerProps>(({ enable, text }) => {
12
+ if (!enable) return null;
13
+
14
+ return (
15
+ <div style={{ padding: '0 20px' }}>
16
+ <Divider>
17
+ <Tag icon={<Icon icon={Timer} />}>{text || 'History Message'}</Tag>
18
+ </Divider>
19
+ </div>
20
+ );
21
+ });
22
+
23
+ export default HistoryDivider;