@lobehub/chat 0.120.0 → 0.120.2

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 (29) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +24 -26
  3. package/README.zh-CN.md +24 -26
  4. package/docs/Deployment/Common-Error.md +18 -1
  5. package/docs/Deployment/Common-Error.zh-CN.md +18 -0
  6. package/docs/Deployment/Environment-Variable.md +14 -3
  7. package/docs/Deployment/Environment-Variable.zh-CN.md +14 -3
  8. package/docs/Development/Contributing-Guidelines.zh-CN.md +72 -0
  9. package/docs/Development/Internationalization-Implementation.zh-CN.md +117 -0
  10. package/docs/Development/State-Management/Selectors.zh-CN.md +49 -0
  11. package/docs/Development/State-Management/index.zh-CN.md +219 -0
  12. package/docs/Development/index.zh-CN.md +66 -1
  13. package/docs/Home.md +3 -3
  14. package/docs/_Sidebar.md +4 -4
  15. package/package.json +7 -3
  16. package/src/features/Conversation/Plugins/Render/StandaloneType/Iframe.tsx +2 -2
  17. package/src/features/Conversation/Plugins/Render/utils/listenToPlugin.test.ts +2 -2
  18. package/src/features/Conversation/Plugins/Render/utils/listenToPlugin.ts +5 -2
  19. package/src/features/Conversation/components/ChatItem/index.tsx +12 -1
  20. package/src/features/Conversation/components/VirtualizedList/index.tsx +4 -1
  21. package/src/store/chat/slices/tool/action.test.ts +167 -7
  22. package/src/store/chat/slices/tool/action.ts +36 -4
  23. package/src/store/tool/slices/plugin/__snapshots__/action.test.ts.snap +15 -0
  24. package/src/store/tool/slices/plugin/action.test.ts +122 -0
  25. package/src/store/tool/slices/plugin/action.ts +18 -1
  26. package/docs/Development/Data-Store-Selectors.zh-CN.md +0 -68
  27. /package/docs/{Add-New-Locale.md → Development/Add-New-Locale.md} +0 -0
  28. /package/docs/{Add-New-Locale.zh-CN.md → Development/Add-New-Locale.zh-CN.md} +0 -0
  29. /package/docs/Development/{Data-Store-Selectors.md → State-Management/Selectors.md} +0 -0
@@ -0,0 +1,219 @@
1
+ # 状态管理最佳实践
2
+
3
+ LobeChat 不同于传统 CRUD 的网页,存在大量的富交互能力,如何设计一个易于开发与易于维护的数据流架构非常重要。本篇文档将介绍 LobeChat 中的数据流管理最佳实践。
4
+
5
+ ## 概念要素
6
+
7
+ | 概念名词 | 解释 |
8
+ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
9
+ | store | 状态库 (store),包含存储应用的状态、动作。允许在应用渲染中访问和修改状态。 |
10
+ | state | 状态 (state) 是指应用程序的数据,存储了应用程序的当前状态,状态的变化**一定会触发应用的重新渲染**,以反映新的状态。 |
11
+ | action | 动作 (action) 是一个操作函数,它描述了应用程序中发生的交互事件。动作通常是由用户交互、网络请求或定时器等触发。 action 可以是**同步**的,也可以是**异步**的。 |
12
+ | reducer | 归约器 (reducer) 是一个纯函数,它接收当前状态和动作作为参数,并返回一个新的状态。它用于根据动作类型来更新应用程序的状态。Reducer 是一个纯函数,不存在副作用,因此一定是 **同步** 函数。 |
13
+ | selector | 选择器 (selector) 是一个函数,用于从应用程序的状态中获取特定的数据。它接收应用程序的状态作为参数,并返回经过计算或转换后的数据。Selector 可以将状态的一部分或多个状态组合起来,以生成派生的数据。Selector 通常用于将应用程序的状态映射到组件的 props,以供组件使用。 |
14
+ | slice | 切片 (slice) 是一个概念,用于表达数据模型状态的一部分。它指定了一个状态切片(slice),以及与该切片相关的 state、action、reducer 和 selector。使用 Slice 可以将大型的 Store 拆分为更小的、可维护的子类型。 |
15
+
16
+ ## 结构分层
17
+
18
+ 在不同的复杂度下,我们可以将 Store 的结构组织可以由很大的不同:
19
+
20
+ - **较低复杂度**:一般包含 2\~5 个 state 、3 \~ 4 个 action。此时的结构一般直接一个 `store.ts` + 一个 `initialState.ts` 即可。
21
+
22
+ ```bash
23
+ DataFill/store
24
+ ├── index.ts
25
+ └── initialState.ts
26
+ ```
27
+
28
+ - **一般复杂度** :一般复杂度存在 5 \~ 15 个 state、 5 \~ 10 个 action,可能会存在 selector 实现派生状态,也有可能存在 reducer 简化部分数据变更的复杂度。此时的结构一般为一个 `store.ts` + 一个 `initialState.ts` + 一个 `selectors.ts`/`reducer.ts`。
29
+
30
+ ```bash
31
+ IconPicker/store
32
+ ├── index.ts
33
+ ├── initialState.ts
34
+ ├── selectors.ts
35
+ └── store.ts
36
+ ```
37
+
38
+ ```bash
39
+ SortableList/store
40
+ ├── index.ts
41
+ ├── initialState.ts
42
+ ├── listDataReducer.ts
43
+ └── store.ts
44
+ ```
45
+
46
+ - **中等复杂度** : 中等复杂度存在 15 \~ 30 个 state、 10 \~ 20 个 action,大概率会存在 selector 来聚合派生状态,大概率存在 reducer 简化部分数据变更的复杂度。
47
+
48
+ 此时结构,用单一的 action store 已经较难维护,往往会拆解出来多个 slice 用于管理不同的 action。 下方的代码代表了 `SortableTree` 组件的内部数据流:
49
+
50
+ ```bash
51
+ SortableTree/store
52
+ ├── index.ts
53
+ ├── initialState.ts
54
+ ├── selectors.ts
55
+ ├── slices
56
+ ├── crudSlice.ts
57
+ ├── dndSlice.ts
58
+ └── selectionSlice.ts
59
+ ├── store.ts
60
+ └── treeDataReducer.ts
61
+ ```
62
+
63
+ - 高等复杂度:高等复杂度存在 30 个以上的 state、 20 个以上的 action。必然需要 slice 做模块化内聚。在每个 slice 中都各自声明了各自的 initState、 action、reducer 与 selector。
64
+
65
+ 下述这个数据流的目录结构是之前一版 SessionStore,具有很高的复杂度,实现了大量的业务逻辑。但借助于 slice 的模块化和分形架构的心智,我们可以很容易地找到对应的模块,新增功能与迭代都很易于维护。
66
+
67
+ ```bash
68
+ LobeChat SessionStore
69
+ ├── index.ts
70
+ ├── initialState.ts
71
+ ├── selectors.ts
72
+ ├── slices
73
+ │ ├── agentConfig
74
+ │ │ ├── action.ts
75
+ │ │ ├── index.ts
76
+ │ │ ├── initialState.ts
77
+ │ │ └── selectors.ts
78
+ │ ├── chat
79
+ │ │ ├── actions
80
+ │ │ │ ├── index.ts
81
+ │ │ │ ├── message.ts
82
+ │ │ │ └── topic.ts
83
+ │ │ ├── index.ts
84
+ │ │ ├── initialState.ts
85
+ │ │ ├── reducers
86
+ │ │ │ ├── message.ts
87
+ │ │ │ └── topic.ts
88
+ │ │ ├── selectors
89
+ │ │ │ ├── chat.ts
90
+ │ │ │ ├── index.ts
91
+ │ │ │ ├── token.ts
92
+ │ │ │ ├── topic.ts
93
+ │ │ │ └── utils.ts
94
+ │ │ └── utils.ts
95
+ │ └── session
96
+ │ ├── action.ts
97
+ │ ├── index.ts
98
+ │ ├── initialState.ts
99
+ │ ├── reducers
100
+ │ │ └── session.ts
101
+ │ └── selectors
102
+ │ ├── export.ts
103
+ │ ├── index.ts
104
+ │ └── list.ts
105
+ └── store.ts
106
+ ```
107
+
108
+ 根据您提供的 LobeChat SessionStore 的目录结构,我们可以更新前面的文档,并将示例转换为 LobeChat 的 SessionStore 的实现案例。以下是转换后的文档部分:
109
+
110
+ ### LobeChat SessionStore 目录结构最佳实践
111
+
112
+ 在 LobeChat 应用中,由于会话管理是一个复杂的功能模块,因此我们采用了 Slice 模式来组织数据流。下面是 LobeChat SessionStore 的目录结构,其中每个目录和文件都有其特定的用途:
113
+
114
+ ```bash
115
+ src/store/session
116
+ ├── helpers.ts # 辅助函数
117
+ ├── hooks # 自定义 React 钩子
118
+ │   ├── index.ts # 钩子的出口文件
119
+ │   ├── useEffectAfterHydrated.ts # 会话加载后的效果钩子
120
+ │   ├── useOnFinishHydrationSession.ts # 会话水合完成钩子
121
+ │   ├── useSessionChatInit.ts # 会话聊天初始化钩子
122
+ │   └── useSessionHydrated.ts # 会话水合状态钩子
123
+ ├── index.ts # SessionStore 的聚合导出文件
124
+ ├── initialState.ts # 聚合了所有 slice 的 initialState
125
+ ├── selectors.ts # 从各个 slices 导出的 selector
126
+ ├── slices # 分离的功能模块
127
+ │   ├── agent # 代理相关的状态和操作
128
+ │   │   ├── action.ts # 代理相关的 action 定义
129
+ │   │   ├── index.ts # 代理 slice 的入口文件
130
+ │   │   ├── selectors.test.ts # 代理相关 selector 的测试
131
+ │   │   └── selectors.ts # 代理相关的 selector 定义
132
+ │   └── session # 会话相关的状态和操作
133
+ │   ├── action.test.ts # 会话相关 action 的测试
134
+ │   ├── action.ts # 会话相关的 action 定义
135
+ │   ├── helpers.ts # 会话相关的辅助函数
136
+ │   ├── initialState.ts # 会话 slice 的 initialState
137
+ │   └── selectors # 会话相关的 selector 与其测试
138
+ │   ├── export.ts # 会话 selector 的聚合导出
139
+ │   ├── index.ts # 会话 selector 的入口文件
140
+ │   ├── list.test.ts # 列表 selector 的测试
141
+ │   └── list.ts # 列表相关的 selector 定义
142
+ └── store.ts # SessionStore 的创建和使用
143
+ ```
144
+
145
+ ## SessionStore 的实现
146
+
147
+ 在 LobeChat 中,SessionStore 被设计为管理会话状态和逻辑的核心模块。它由多个 Slices 组成,每个 Slice 管理一部分相关的状态和逻辑。下面是一个简化的 SessionStore 的实现示例:
148
+
149
+ #### store.ts
150
+
151
+ ```ts
152
+ import { PersistOptions, devtools, persist, subscribeWithSelector } from 'zustand/middleware';
153
+ import { shallow } from 'zustand/shallow';
154
+ import { devtools } from 'zustand/middleware';
155
+ import { createWithEqualityFn } from 'zustand/traditional';
156
+
157
+ import { SessionStoreState, initialState } from './initialState';
158
+ import { AgentAction, createAgentSlice } from './slices/agent/action';
159
+ import { SessionAction, createSessionSlice } from './slices/session/action';
160
+
161
+ // =============== 聚合 createStoreFn ============ //
162
+
163
+ export type SessionStore = SessionAction & AgentAction & SessionStoreState;
164
+ const createStore: StateCreator<SessionStore, [['zustand/devtools', never]]> = (...parameters) => ({
165
+ ...initialState,
166
+ ...createAgentSlice(...parameters),
167
+ ...createSessionSlice(...parameters),
168
+ });
169
+
170
+
171
+
172
+ // =============== 实装 useStore ============ //
173
+
174
+ export const useSessionStore = createWithEqualityFn<SessionStore>()(
175
+ persist(
176
+ subscribeWithSelector(
177
+ devtools(createStore, {
178
+ name: 'LobeChat_Session' + (isDev ? '_DEV' : ''),
179
+ }),
180
+ ),
181
+ persistOptions,
182
+ ),
183
+ shallow,
184
+ );
185
+
186
+ ```
187
+
188
+ 在这个 `store.ts` 文件中,我们创建了一个 `useSessionStore` 钩子,它使用 `zustand` 库来创建一个全局状态管理器。我们将 initialState 和每个 Slice 的状态和动作合并,以创建完整的 SessionStore。
189
+
190
+ #### slices/session/action.ts
191
+
192
+ ```ts
193
+ import { StateCreator } from 'zustand';
194
+
195
+ import { SessionStore } from '@/store/session';
196
+
197
+ export interface SessionActions {
198
+ /**
199
+ * A custom hook that uses SWR to fetch sessions data.
200
+ */
201
+ useFetchSessions: () => SWRResponse<any>;
202
+ }
203
+
204
+ export const createSessionSlice: StateCreator<
205
+ SessionStore,
206
+ [['zustand/devtools', never]],
207
+ [],
208
+ SessionAction
209
+ > = (set, get) => ({
210
+ useFetchSessions: () => {
211
+ // ...初始化会话的逻辑
212
+ },
213
+ // ...其他动作的实现
214
+ });
215
+ ```
216
+
217
+ 在 `action.ts` 文件中,我们定义了一个 `SessionActions` 接口来描述会话相关的动作,并且实现了一个 `useFetchSessions` 函数来创建这些动作。然后,我们将这些动作与初始状态合并,以形成会话相关的 Slice。
218
+
219
+ 通过这种结构分层和模块化的方法,我们可以确保 LobeChat 的 SessionStore 是清晰、可维护的,同时也便于扩展和测试。
@@ -6,6 +6,10 @@
6
6
 
7
7
  - [基础技术栈](#基础技术栈)
8
8
  - [文件夹目录架构](#文件夹目录架构)
9
+ - [本地开发环境设置](#本地开发环境设置)
10
+ - [代码风格与贡献指南](#代码风格与贡献指南)
11
+ - [国际化实现指南](#国际化实现指南)
12
+ - [附录:资源与参考](#附录资源与参考)
9
13
 
10
14
  ## 基础技术栈
11
15
 
@@ -40,4 +44,65 @@ src
40
44
  └── utils # 通用的工具函数
41
45
  ```
42
46
 
43
- 有关目录架构的详细介绍,详见: [文件夹目录架构](Folder-Structure.zh-CN.md)
47
+ 有关目录架构的详细介绍,详见: [文件夹目录架构](Folder-Structure.zh-CN)
48
+
49
+ ## 本地开发环境设置
50
+
51
+ 本节将概述搭建开发环境并进行本地开发。 在开始之前,请确保你的本地环境中已安装 Node.js、Git 以及你选择的包管理器(Bun 或 PNPM)。
52
+
53
+ 我们推荐使用 WebStorm 作为你的集成开发环境(IDE)。
54
+
55
+ 1. **获取代码**:克隆 LobeChat 的代码库到本地:
56
+
57
+ ```bash
58
+ git clone https://github.com/lobehub/lobe-chat.git
59
+ ```
60
+
61
+ 2. **安装依赖**:进入项目目录,并安装所需依赖:
62
+
63
+ ```bash
64
+ cd lobe-chat
65
+ # 如果你使用 Bun
66
+ bun install
67
+ # 如果你使用 PNPM
68
+ pnpm install
69
+ ```
70
+
71
+ 3. **运行与调试**:启动本地开发服务器,开始你的开发之旅:
72
+
73
+ ```bash
74
+ # 使用 Bun 启动开发服务器
75
+ bun run dev
76
+ # 访问 http://localhost:3010 查看应用
77
+ ```
78
+
79
+ 现在,你应该可以在浏览器中看到 LobeChat 的欢迎页面。详细的环境配置指南,请参考 [开发环境设置指南](Setup-Development.zh-CN)。
80
+
81
+ ## 代码风格与贡献指南
82
+
83
+ 在 LobeChat 项目中,我们十分重视代码的质量和一致性。为此,我们制定了一系列的代码风格规范和贡献流程,以确保每位开发者都能顺利地参与到项目中。以下是你作为开发者需要遵守的代码风格和贡献准则。
84
+
85
+ - **代码风格**:我们使用 `@lobehub/lint` 统一代码风格,包括 ESLint、Prettier、remarklint 和 stylelint 配置。请遵守我们的代码规范,以保持代码的一致性和可读性。
86
+ - **贡献流程**:我们采用 gitmoji 和 semantic release 作为代码提交和发布流程。请使用 gitmoji 标注您的提交信息,并确保遵循 semantic release 的规范,以便我们的自动化系统能够正确处理版本控制和发布。
87
+
88
+ 所有的贡献都将经过代码审查。维护者可能会提出修改建议或要求。请积极响应审查意见,并及时做出调整,我们期待你的参与和贡献。
89
+
90
+ 详细的代码风格和贡献指南,请参考 [代码风格与贡献指南](Contributing-Guidelines.zh-CN)。
91
+
92
+ ## 国际化实现指南
93
+
94
+ LobeChat 采用 `i18next` 和 `lobe-i18n` 实现多语言支持,确保用户全球化体验。
95
+
96
+ 国际化文件位于 `src/locales`,包含默认语言(中文)。 我们会通过 `lobe-i18n` 自动生成其他的语言 JSON 文件。
97
+
98
+ 如果要添加新语种,需遵循特定步骤,详见 [新语种添加指南](Add-New-Locale.zh-CN)。 我们鼓励你参与我们的国际化努力,共同为全球用户提供更好的服务。
99
+
100
+ 详细的国际化实现指南指南,请参考 [国际化实现指南](Internationalization-Implementation.zh-CN)。
101
+
102
+ ## 附录:资源与参考
103
+
104
+ 为了支持开发者更好地理解和使用 LobeChat 的技术栈,我们提供了一份详尽的资源与参考列表 —— [LobeChat 资源与参考](https://github.com/lobehub/lobe-chat/wiki/Resources.zh-CN) - 访问我们维护的资源列表,包括教程、文章和其他有用的链接。
105
+
106
+ 我们鼓励开发者利用这些资源深入学习和提升技能,通过 [LobeChat GitHub Discussions](https://github.com/lobehub/lobe-chat/discussions) 或者 [Discord](https://discord.com/invite/AYFPHvv2jT) 加入社区讨论,提出问题或分享你的经验。
107
+
108
+ 如果你有任何疑问,或者需要进一步的帮助,请不要犹豫,请通过上述渠道与我们联系。
package/docs/Home.md CHANGED
@@ -12,8 +12,6 @@ LobeChat is a open-source, extensible ([Function Calling][fc-url]), high-perform
12
12
 
13
13
  ![](https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/rainbow.png)
14
14
 
15
- [New Locale Guide](https://github.com/lobehub/lobe-chat/wiki/Add-New-Locale) | [新语种添加指南](https://github.com/lobehub/lobe-chat/wiki/Add-New-Locale.zh-CN)
16
-
17
15
  <!-- DOCS LIST -->
18
16
 
19
17
  ### 🤯 Usage
@@ -40,10 +38,12 @@ LobeChat is a open-source, extensible ([Function Calling][fc-url]), high-perform
40
38
  - [Environment Setup Guide](https://github.com/lobehub/lobe-chat/wiki/Setup-Development) | [开发环境设置](https://github.com/lobehub/lobe-chat/wiki/Setup-Development.zh-CN)
41
39
  - [Architecture Design](https://github.com/lobehub/lobe-chat/wiki/Architecture) | [架构设计](https://github.com/lobehub/lobe-chat/wiki/Architecture.zh-CN)
42
40
  - [Directory Structure](https://github.com/lobehub/lobe-chat/wiki/Folder-Structure) | [目录架构](https://github.com/lobehub/lobe-chat/wiki/Folder-Structure.zh-CN)
43
- - [Data Store Selector](https://github.com/lobehub/lobe-chat/wiki/Data-Store-Selectors) | [数据存储取数模块](https://github.com/lobehub/lobe-chat/wiki/Data-Store-Selectors.zh-CN)
41
+ - [State-Management](https://github.com/lobehub/lobe-chat/wiki/State-Management) | [状态管理](https://github.com/lobehub/lobe-chat/wiki/State-Management.zh-CN)
42
+ - [Selectors](https://github.com/lobehub/lobe-chat/wiki/State-Management/Selectors) | [取数模块](https://github.com/lobehub/lobe-chat/wiki/State-Management/Selectors.zh-CN)
44
43
  - [Conversation API Implementation Logic](https://github.com/lobehub/lobe-chat/wiki/Chat-API) | [会话 API 实现逻辑](https://github.com/lobehub/lobe-chat/wiki/Chat-API.zh-CN)
45
44
  - [How to Develop a New Feature](https://github.com/lobehub/lobe-chat/wiki/Feature-Development) | [如何开发一个新功能](https://github.com/lobehub/lobe-chat/wiki/Feature-Development.zh-CN)
46
45
  - [Testing Guide](https://github.com/lobehub/lobe-chat/wiki/Test) | [测试指南](https://github.com/lobehub/lobe-chat/wiki/Test.zh-CN)
46
+ - [New Locale Guide](https://github.com/lobehub/lobe-chat/wiki/Add-New-Locale) | [新语种添加指南](https://github.com/lobehub/lobe-chat/wiki/Add-New-Locale.zh-CN)
47
47
  - [Resources and References](https://github.com/lobehub/lobe-chat/wiki/Resources) | [资源与参考](https://github.com/lobehub/lobe-chat/wiki/Resources.zh-CN)
48
48
 
49
49
  <br/>
package/docs/_Sidebar.md CHANGED
@@ -6,8 +6,6 @@
6
6
 
7
7
  <!-- DOCS LIST -->
8
8
 
9
- [New Locale Guide](https://github.com/lobehub/lobe-chat/wiki/Add-New-Locale) | [新语种添加指南](https://github.com/lobehub/lobe-chat/wiki/Add-New-Locale.zh-CN)
10
-
11
9
  #### 🤯 Usage
12
10
 
13
11
  - [Custom Agents Guide](https://github.com/lobehub/lobe-chat/wiki/Usage-Agents) | [自定义助手指南](https://github.com/lobehub/lobe-chat/wiki/Usage-Agents.zh-CN)
@@ -28,10 +26,12 @@
28
26
  - [Environment Setup Guide](https://github.com/lobehub/lobe-chat/wiki/Setup-Development) | [开发环境设置](https://github.com/lobehub/lobe-chat/wiki/Setup-Development.zh-CN)
29
27
  - [Architecture Design](https://github.com/lobehub/lobe-chat/wiki/Architecture) | [架构设计](https://github.com/lobehub/lobe-chat/wiki/Architecture.zh-CN)
30
28
  - [Directory Structure](https://github.com/lobehub/lobe-chat/wiki/Folder-Structure) | [目录架构](https://github.com/lobehub/lobe-chat/wiki/Folder-Structure.zh-CN)
31
- - [Data Store Selector](https://github.com/lobehub/lobe-chat/wiki/Data-Store-Selectors) | [数据存储取数模块](https://github.com/lobehub/lobe-chat/wiki/Data-Store-Selectors.zh-CN)
29
+ - [State-Management](https://github.com/lobehub/lobe-chat/wiki/State-Management) | [状态管理](https://github.com/lobehub/lobe-chat/wiki/State-Management.zh-CN)
30
+ - [Data Store Selector](https://github.com/lobehub/lobe-chat/wiki/State-Management/Selectors) | [取数模块](https://github.com/lobehub/lobe-chat/wiki/State-Management/Selectors.zh-CN)
32
31
  - [Conversation API Implementation Logic](https://github.com/lobehub/lobe-chat/wiki/Chat-API) | [会话 API 实现逻辑](https://github.com/lobehub/lobe-chat/wiki/Chat-API.zh-CN)
33
32
  - [How to Develop a New Feature](https://github.com/lobehub/lobe-chat/wiki/Feature-Development) | [如何开发一个新功能](https://github.com/lobehub/lobe-chat/wiki/Feature-Development.zh-CN)
34
- - [Testing Guide](https://github.com/lobehub/lobe-chat/wiki/Test) | [中文](https://github.com/lobehub/lobe-chat/wiki/Test.zh-CN)
33
+ - [Testing Guide](https://github.com/lobehub/lobe-chat/wiki/Test) | [测试指南](https://github.com/lobehub/lobe-chat/wiki/Test.zh-CN)
34
+ - [New Locale Guide](https://github.com/lobehub/lobe-chat/wiki/Add-New-Locale) | [新语种添加指南](https://github.com/lobehub/lobe-chat/wiki/Add-New-Locale.zh-CN)
35
35
  - [Resources and References](https://github.com/lobehub/lobe-chat/wiki/Resources) | [资源与参考](https://github.com/lobehub/lobe-chat/wiki/Resources.zh-CN)
36
36
 
37
37
  #### 🤖 Agents
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "0.120.0",
3
+ "version": "0.120.2",
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",
@@ -44,8 +44,11 @@
44
44
  "release": "semantic-release",
45
45
  "start": "next start",
46
46
  "stylelint": "stylelint \"src/**/*.{js,jsx,ts,tsx}\" --fix",
47
- "test": "vitest --passWithNoTests",
48
- "test:coverage": "vitest run --coverage --passWithNoTests",
47
+ "test": "npm run test-temp-fixture-ci && vitest",
48
+ "test-a-local": "vitest",
49
+ "test-temp-fixture-ci": "echo 'please remove this script after new bun@1.0.24 released' && rm -rf node_modules && npx bun@1.0.22 install",
50
+ "test:coverage": "npm run test-temp-fixture-ci && vitest run --coverage",
51
+ "test:coverage-local": "vitest run --coverage",
49
52
  "test:update": "vitest -u",
50
53
  "type-check": "tsc --noEmit",
51
54
  "workflow:docs": "bun scripts/docsWorkflow/index.ts",
@@ -73,6 +76,7 @@
73
76
  },
74
77
  "dependencies": {
75
78
  "@ant-design/icons": "^5",
79
+ "@cfworker/json-schema": "^1",
76
80
  "@icons-pack/react-simple-icons": "^9",
77
81
  "@lobehub/chat-plugin-sdk": "latest",
78
82
  "@lobehub/chat-plugins-gateway": "latest",
@@ -77,8 +77,8 @@ const IFrameRender = memo<IFrameRenderProps>(({ url, id, payload, width = 600, h
77
77
 
78
78
  // when plugin try to send back message, we should fill it to the message content
79
79
  const fillPluginContent = useChatStore((s) => s.fillPluginMessageContent);
80
- useOnPluginFillContent((content) => {
81
- fillPluginContent(id, content);
80
+ useOnPluginFillContent((content, triggerAiMessage) => {
81
+ fillPluginContent(id, content, triggerAiMessage);
82
82
  });
83
83
 
84
84
  // when plugin wants to get plugin state, send it to plugin
@@ -72,7 +72,7 @@ describe('useOnPluginFillContent', () => {
72
72
 
73
73
  window.dispatchEvent(event);
74
74
 
75
- expect(mockCallback).toHaveBeenCalledWith(testContent);
75
+ expect(mockCallback).toHaveBeenCalledWith(testContent, undefined);
76
76
  });
77
77
 
78
78
  it('calls callback with JSON stringified content if content is not a string', () => {
@@ -86,7 +86,7 @@ describe('useOnPluginFillContent', () => {
86
86
 
87
87
  window.dispatchEvent(event);
88
88
 
89
- expect(mockCallback).toHaveBeenCalledWith(JSON.stringify(testContent));
89
+ expect(mockCallback).toHaveBeenCalledWith(JSON.stringify(testContent), undefined);
90
90
  });
91
91
  });
92
92
 
@@ -31,14 +31,17 @@ export const useOnPluginFetchPluginState = (onRequest: (key: string) => void) =>
31
31
  }, []);
32
32
  };
33
33
 
34
- export const useOnPluginFillContent = (callback: (content: string) => void) => {
34
+ export const useOnPluginFillContent = (
35
+ callback: (content: string, triggerAiMessage?: boolean) => void,
36
+ ) => {
35
37
  useEffect(() => {
36
38
  const fn = (e: MessageEvent) => {
37
39
  if (e.data.type === PluginChannel.fillStandalonePluginContent) {
38
40
  const data = e.data.content;
41
+ const triggerAiMessage = e.data.triggerAiMessage;
39
42
  const content = typeof data !== 'string' ? JSON.stringify(data) : data;
40
43
 
41
- callback(content);
44
+ callback(content, triggerAiMessage);
42
45
  }
43
46
  };
44
47
 
@@ -1,4 +1,5 @@
1
1
  import { type AlertProps, ChatItem } from '@lobehub/ui';
2
+ import { createStyles } from 'antd-style';
2
3
  import isEqual from 'fast-deep-equal';
3
4
  import { ReactNode, memo, useCallback, useMemo, useState } from 'react';
4
5
  import { useTranslation } from 'react-i18next';
@@ -15,6 +16,15 @@ import { renderMessages, useAvatarsClick } from '../../Messages';
15
16
  import ActionsBar from './ActionsBar';
16
17
  import HistoryDivider from './HistoryDivider';
17
18
 
19
+ const useStyles = createStyles(({ css, prefixCls }) => ({
20
+ message: css`
21
+ // prevent the textarea too long
22
+ .${prefixCls}-input {
23
+ max-height: 900px;
24
+ }
25
+ `,
26
+ }));
27
+
18
28
  export interface ChatListItemProps {
19
29
  id: string;
20
30
  index: number;
@@ -22,7 +32,7 @@ export interface ChatListItemProps {
22
32
 
23
33
  const Item = memo<ChatListItemProps>(({ index, id }) => {
24
34
  const { t } = useTranslation('common');
25
-
35
+ const { styles } = useStyles();
26
36
  const [editing, setEditing] = useState(false);
27
37
  const [type = 'chat'] = useSessionStore((s) => {
28
38
  const config = agentSelectors.currentAgentConfig(s);
@@ -111,6 +121,7 @@ const Item = memo<ChatListItemProps>(({ index, id }) => {
111
121
  <ChatItem
112
122
  actions={<ActionsBar index={index} setEditing={setEditing} />}
113
123
  avatar={item.meta}
124
+ className={styles.message}
114
125
  editing={editing}
115
126
  error={error}
116
127
  errorMessage={<ErrorMessage data={item} />}
@@ -42,6 +42,9 @@ const VirtualizedList = memo<VirtualizedListProps>(({ mobile }) => {
42
42
  }
43
43
  }, [id]);
44
44
 
45
+ // overscan should be 1.5 times the height of the window
46
+ const overscan = typeof window !== 'undefined' ? window.innerHeight * 1.5 : 0;
47
+
45
48
  return chatLoading && data.length === 2 ? null : (
46
49
  <Flexbox height={'100%'}>
47
50
  <Virtuoso
@@ -52,7 +55,7 @@ const VirtualizedList = memo<VirtualizedListProps>(({ mobile }) => {
52
55
  followOutput={'auto'}
53
56
  initialTopMostItemIndex={data?.length - 1}
54
57
  itemContent={itemContent}
55
- overscan={70 * 10}
58
+ overscan={overscan}
56
59
  ref={virtuosoRef}
57
60
  />
58
61
  <AutoScroll