@lobehub/chat 0.135.0 → 0.135.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,56 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 0.135.2](https://github.com/lobehub/lobe-chat/compare/v0.135.1...v0.135.2)
6
+
7
+ <sup>Released on **2024-03-14**</sup>
8
+
9
+ #### ♻ Code Refactoring
10
+
11
+ - **misc**: Upgrade plugin db schema.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### Code refactoring
19
+
20
+ - **misc**: Upgrade plugin db schema, closes [#1571](https://github.com/lobehub/lobe-chat/issues/1571) ([757574a](https://github.com/lobehub/lobe-chat/commit/757574a))
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.135.1](https://github.com/lobehub/lobe-chat/compare/v0.135.0...v0.135.1)
31
+
32
+ <sup>Released on **2024-03-14**</sup>
33
+
34
+ #### ♻ Code Refactoring
35
+
36
+ - **misc**: Refactor the db model.
37
+
38
+ <br/>
39
+
40
+ <details>
41
+ <summary><kbd>Improvements and Fixes</kbd></summary>
42
+
43
+ #### Code refactoring
44
+
45
+ - **misc**: Refactor the db model, closes [#1567](https://github.com/lobehub/lobe-chat/issues/1567) ([3d56dd6](https://github.com/lobehub/lobe-chat/commit/3d56dd6))
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.135.0](https://github.com/lobehub/lobe-chat/compare/v0.134.1...v0.135.0)
6
56
 
7
57
  <sup>Released on **2024-03-14**</sup>
package/README.md CHANGED
@@ -216,14 +216,14 @@ In addition, these plugins are not limited to news aggregation, but can also ext
216
216
 
217
217
  <!-- PLUGIN LIST -->
218
218
 
219
- | Recent Submits | Description |
220
- | ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
221
- | [Charts & Diagrams](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **pyxl** on **2024-02-05**</sup> | Mermaid Diagrams, Schemes for Presentations, Analysis, research websites, pie charts.<br/>`chart` `diagram` |
222
- | [Social Search](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **say-apps** on **2024-02-02**</sup> | The Social Search provides access to tweets, users, followers, images, media and more.<br/>`social` `twitter` `x` `search` |
223
- | [TokenInsights](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **feednews** on **2024-01-27**</sup> | Get realtime crypto price, BTC, ETH, BNB, and the latest insights.The latest coin news and airdrop opportunities.<br/>`crypto` `btc` `eth` `bnb` |
224
- | [Bilibili](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **LobeHub** on **2024-01-27**</sup> | Dive into Bilibili's vast content with features like keyword video search, replay access, interactive danmaku, trending video recommendations, and hot-search insights, all at your fingertips.<br/>`video` `bilibili` `search` |
225
-
226
- > 📊 Total plugins: [<kbd>**58**</kbd>](https://github.com/lobehub/lobe-chat-plugins)
219
+ | Recent Submits | Description |
220
+ | ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
221
+ | [Calendar Assistant](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **cc** on **2024-03-13**</sup> | A plugin to manage your calendar events # will auto generate i18n in workflow<br/>`calendar` `schedule` `will-auto-generate-i-18-n-in-workflow` |
222
+ | [Charts & Diagrams](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **pyxl** on **2024-02-05**</sup> | Mermaid Diagrams, Schemes for Presentations, Analysis, research websites, pie charts.<br/>`chart` `diagram` |
223
+ | [Social Search](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **say-apps** on **2024-02-02**</sup> | The Social Search provides access to tweets, users, followers, images, media and more.<br/>`social` `twitter` `x` `search` |
224
+ | [TokenInsights](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **feednews** on **2024-01-27**</sup> | Get realtime crypto price, BTC, ETH, BNB, and the latest insights.The latest coin news and airdrop opportunities.<br/>`crypto` `btc` `eth` `bnb` |
225
+
226
+ > 📊 Total plugins: [<kbd>**59**</kbd>](https://github.com/lobehub/lobe-chat-plugins)
227
227
 
228
228
  <!-- PLUGIN LIST -->
229
229
 
package/README.zh-CN.md CHANGED
@@ -208,14 +208,14 @@ LobeChat 的插件生态系统是其核心功能的重要扩展,它极大地
208
208
 
209
209
  <!-- PLUGIN LIST -->
210
210
 
211
- | 最近新增 | 插件描述 |
212
- | ----------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
213
- | [图表和图示](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **pyxl** on **2024-02-05**</sup> | 美人鱼图表,演示文稿方案,分析,研究网站,饼图。<br/>`图表` `图示` |
214
- | [社交搜索](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **say-apps** on **2024-02-02**</sup> | 社交搜索提供访问推文、用户、关注者、图片、媒体等功能。<br/>`社交` `推特` `x` `搜索` |
215
- | [TokenInsights](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **feednews** on **2024-01-27**</sup> | 获取实时加密货币价格,BTC,ETH,BNB 和最新见解。最新的币新闻和空投机会。<br/>`加密货币` `btc` `eth` `bnb` |
216
- | [哔哩哔哩](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **LobeHub** on **2024-01-27**</sup> | 通过关键词视频搜索、回放访问、互动弹幕、热门视频推荐和热搜洞察等功能,深入体验哔哩哔哩丰富的内容,尽在您的指尖。<br/>`视频` `哔哩哔哩` `搜索` |
217
-
218
- > 📊 Total plugins: [<kbd>**58**</kbd>](https://github.com/lobehub/lobe-chat-plugins)
211
+ | 最近新增 | 插件描述 |
212
+ | ----------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
213
+ | [日历助手](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **cc** on **2024-03-13**</sup> | 一个用于管理日历事件的插件 # 将自动生成工作流程中的 i18n<br/>`日历` `日程安排` `将自动生成工作流程中的-i-18-n` |
214
+ | [图表和图示](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **pyxl** on **2024-02-05**</sup> | 美人鱼图表,演示文稿方案,分析,研究网站,饼图。<br/>`图表` `图示` |
215
+ | [社交搜索](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **say-apps** on **2024-02-02**</sup> | 社交搜索提供访问推文、用户、关注者、图片、媒体等功能。<br/>`社交` `推特` `x` `搜索` |
216
+ | [TokenInsights](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **feednews** on **2024-01-27**</sup> | 获取实时加密货币价格,BTC,ETH,BNB 和最新见解。最新的币新闻和空投机会。<br/>`加密货币` `btc` `eth` `bnb` |
217
+
218
+ > 📊 Total plugins: [<kbd>**59**</kbd>](https://github.com/lobehub/lobe-chat-plugins)
219
219
 
220
220
  <!-- PLUGIN LIST -->
221
221
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "0.135.0",
3
+ "version": "0.135.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",
@@ -148,7 +148,7 @@
148
148
  "uuid": "^9",
149
149
  "yaml": "^2",
150
150
  "zod": "^3",
151
- "zustand": "^4.4",
151
+ "zustand": "^4.5.2",
152
152
  "zustand-utils": "^1.3.2"
153
153
  },
154
154
  "devDependencies": {
@@ -11,7 +11,7 @@ export const GET = async (req: Request) => {
11
11
 
12
12
  let res: Response;
13
13
 
14
- res = await fetch(pluginStore.getPluginIndexUrl(locale as any));
14
+ res = await fetch(pluginStore.getPluginIndexUrl(locale as any), { next: { revalidate: 3600 } });
15
15
 
16
16
  if (res.status === 404) {
17
17
  res = await fetch(pluginStore.getPluginIndexUrl(DEFAULT_LANG));
@@ -10,7 +10,15 @@ import { DB_User } from '@/database/schemas/user';
10
10
  import { uuid } from '@/utils/uuid';
11
11
 
12
12
  import { migrateSettingsToUser } from './migrations/migrateSettingsToUser';
13
- import { dbSchemaV1, dbSchemaV2, dbSchemaV3, dbSchemaV4, dbSchemaV5, dbSchemaV6 } from './schemas';
13
+ import {
14
+ dbSchemaV1,
15
+ dbSchemaV2,
16
+ dbSchemaV3,
17
+ dbSchemaV4,
18
+ dbSchemaV5,
19
+ dbSchemaV6,
20
+ dbSchemaV7,
21
+ } from './schemas';
14
22
  import { DBModel, LOBE_CHAT_LOCAL_DB_NAME } from './types/db';
15
23
 
16
24
  interface LobeDBSchemaMap {
@@ -50,6 +58,10 @@ export class LocalDB extends Dexie {
50
58
  .stores(dbSchemaV6)
51
59
  .upgrade((trans) => this.upgradeToV6(trans));
52
60
 
61
+ this.version(7)
62
+ .stores(dbSchemaV7)
63
+ .upgrade((trans) => this.upgradeToV7(trans));
64
+
53
65
  this.files = this.table('files');
54
66
  this.sessions = this.table('sessions');
55
67
  this.messages = this.table('messages');
@@ -115,6 +127,18 @@ export class LocalDB extends Dexie {
115
127
  if (!user.uuid) user.uuid = uuid();
116
128
  });
117
129
  };
130
+
131
+ /**
132
+ * 2024.03.14
133
+ * add `id` in plugins
134
+ */
135
+ upgradeToV7 = async (trans: Transaction) => {
136
+ const plugins = trans.table('plugins');
137
+
138
+ await plugins.toCollection().modify((plugin: DB_Plugin) => {
139
+ plugin.id = plugin.identifier;
140
+ });
141
+ };
118
142
  }
119
143
 
120
144
  export const LocalDBInstance = new LocalDB();
@@ -66,3 +66,13 @@ export const dbSchemaV6 = {
66
66
  '&id, role, content, fromModel, favorite, plugin.identifier, plugin.apiName, translate.content, createdAt, updatedAt, sessionId, topicId, quotaId, parentId, [sessionId+topicId], traceId',
67
67
  users: '++id, uuid',
68
68
  };
69
+
70
+ // ************************************** //
71
+ // ******* Version 7 - 2024-03-14 ******* //
72
+ // ************************************** //
73
+ // - Added id to `plugins` table
74
+ export const dbSchemaV7 = {
75
+ ...dbSchemaV6,
76
+ plugins:
77
+ '&identifier, id, type, manifest.type, manifest.meta.title, manifest.meta.description, manifest.meta.author, createdAt, updatedAt',
78
+ };
@@ -10,6 +10,7 @@ describe('PluginModel', () => {
10
10
  // 设置正确结构的插件数据
11
11
  pluginData = {
12
12
  identifier: 'test-plugin',
13
+ id: 'test-plugin',
13
14
  manifest: {},
14
15
  type: 'plugin',
15
16
  };
@@ -26,19 +26,8 @@ class _MessageModel extends BaseModel {
26
26
  constructor() {
27
27
  super('messages', DB_MessageSchema);
28
28
  }
29
- async create(data: CreateMessageParams) {
30
- const id = nanoid();
31
-
32
- const messageData: DB_Message = this.mapChatMessageToDBMessage(data as ChatMessage);
33
-
34
- return this._add(messageData, id);
35
- }
36
-
37
- async batchCreate(messages: ChatMessage[]) {
38
- const data: DB_Message[] = messages.map((m) => this.mapChatMessageToDBMessage(m));
39
29
 
40
- return this._batchAdd(data);
41
- }
30
+ // **************** Query *************** //
42
31
 
43
32
  async query({
44
33
  sessionId,
@@ -91,45 +80,79 @@ class _MessageModel extends BaseModel {
91
80
  return this.table.get(id);
92
81
  }
93
82
 
94
- async delete(id: string) {
95
- return this.table.delete(id);
83
+ async queryAll() {
84
+ const data: DBModel<DB_Message>[] = await this.table.orderBy('updatedAt').toArray();
85
+
86
+ return data.map((element) => this.mapToChatMessage(element));
96
87
  }
97
88
 
98
- async clearTable() {
99
- return this.table.clear();
89
+ async queryBySessionId(sessionId: string) {
90
+ return this.table.where('sessionId').equals(sessionId).toArray();
100
91
  }
101
92
 
102
- async update(id: string, data: DeepPartial<DB_Message>) {
103
- return super._update(id, data);
93
+ queryByTopicId = async (topicId: string) => {
94
+ const dbMessages = await this.table.where('topicId').equals(topicId).toArray();
95
+
96
+ return dbMessages.map((message) => this.mapToChatMessage(message));
97
+ };
98
+
99
+ async count() {
100
+ return this.table.count();
104
101
  }
105
102
 
106
- async updatePluginState(id: string, key: string, value: any) {
107
- const item = await this.findById(id);
103
+ // **************** Create *************** //
108
104
 
109
- return this.update(id, { pluginState: { ...item.pluginState, [key]: value } });
105
+ async create(data: CreateMessageParams) {
106
+ const id = nanoid();
107
+
108
+ const messageData: DB_Message = this.mapChatMessageToDBMessage(data as ChatMessage);
109
+
110
+ return this._add(messageData, id);
110
111
  }
111
112
 
112
- /**
113
- * Batch updates multiple fields of the specified messages.
114
- *
115
- * @param {string[]} messageIds - The identifiers of the messages to be updated.
116
- * @param {Partial<DB_Message>} updateFields - An object containing the fields to update and their new values.
117
- * @returns {Promise<number>} - The number of updated messages.
118
- */
119
- async batchUpdate(messageIds: string[], updateFields: Partial<DB_Message>): Promise<number> {
120
- // Retrieve the messages by their IDs
121
- const messagesToUpdate = await this.table.where(':id').anyOf(messageIds).toArray();
113
+ async batchCreate(messages: ChatMessage[]) {
114
+ const data: DB_Message[] = messages.map((m) => this.mapChatMessageToDBMessage(m));
122
115
 
123
- // Update the specified fields of each message
124
- const updatedMessages = messagesToUpdate.map((message) => ({
125
- ...message,
126
- ...updateFields,
127
- }));
116
+ return this._batchAdd(data);
117
+ }
128
118
 
129
- // Use the bulkPut method to update the messages in bulk
130
- await this.table.bulkPut(updatedMessages);
119
+ async duplicateMessages(messages: ChatMessage[]): Promise<ChatMessage[]> {
120
+ const duplicatedMessages = await this.createDuplicateMessages(messages);
121
+ // 批量添加复制后的消息到数据库
122
+ await this.batchCreate(duplicatedMessages);
123
+ return duplicatedMessages;
124
+ }
131
125
 
132
- return updatedMessages.length;
126
+ async createDuplicateMessages(messages: ChatMessage[]): Promise<ChatMessage[]> {
127
+ // 创建一个映射来存储原始消息ID和复制消息ID之间的关系
128
+ const idMapping = new Map<string, string>();
129
+
130
+ // 首先复制所有消息,并为每个复制的消息生成新的ID
131
+ const duplicatedMessages = messages.map((originalMessage) => {
132
+ const newId = nanoid();
133
+ idMapping.set(originalMessage.id, newId);
134
+
135
+ return { ...originalMessage, id: newId };
136
+ });
137
+
138
+ // 更新 parentId 为复制后的新ID
139
+ for (const duplicatedMessage of duplicatedMessages) {
140
+ if (duplicatedMessage.parentId && idMapping.has(duplicatedMessage.parentId)) {
141
+ duplicatedMessage.parentId = idMapping.get(duplicatedMessage.parentId);
142
+ }
143
+ }
144
+
145
+ return duplicatedMessages;
146
+ }
147
+
148
+ // **************** Delete *************** //
149
+
150
+ async delete(id: string) {
151
+ return this.table.delete(id);
152
+ }
153
+
154
+ async clearTable() {
155
+ return this.table.clear();
133
156
  }
134
157
 
135
158
  /**
@@ -158,55 +181,43 @@ class _MessageModel extends BaseModel {
158
181
  return this.table.bulkDelete(messageIds);
159
182
  }
160
183
 
161
- async queryAll() {
162
- const data: DBModel<DB_Message>[] = await this.table.orderBy('updatedAt').toArray();
163
-
164
- return data.map((element) => this.mapToChatMessage(element));
165
- }
166
-
167
- async count() {
168
- return this.table.count();
169
- }
184
+ // **************** Update *************** //
170
185
 
171
- async queryBySessionId(sessionId: string) {
172
- return this.table.where('sessionId').equals(sessionId).toArray();
186
+ async update(id: string, data: DeepPartial<DB_Message>) {
187
+ return this._update(id, data);
173
188
  }
174
189
 
175
- queryByTopicId = async (topicId: string) => {
176
- const dbMessages = await this.table.where('topicId').equals(topicId).toArray();
177
-
178
- return dbMessages.map((message) => this.mapToChatMessage(message));
179
- };
190
+ async updatePluginState(id: string, key: string, value: any) {
191
+ const item = await this.findById(id);
180
192
 
181
- async duplicateMessages(messages: ChatMessage[]): Promise<ChatMessage[]> {
182
- const duplicatedMessages = await this.createDuplicateMessages(messages);
183
- // 批量添加复制后的消息到数据库
184
- await this.batchCreate(duplicatedMessages);
185
- return duplicatedMessages;
193
+ return this.update(id, { pluginState: { ...item.pluginState, [key]: value } });
186
194
  }
187
195
 
188
- async createDuplicateMessages(messages: ChatMessage[]): Promise<ChatMessage[]> {
189
- // 创建一个映射来存储原始消息ID和复制消息ID之间的关系
190
- const idMapping = new Map<string, string>();
191
-
192
- // 首先复制所有消息,并为每个复制的消息生成新的ID
193
- const duplicatedMessages = messages.map((originalMessage) => {
194
- const newId = nanoid();
195
- idMapping.set(originalMessage.id, newId);
196
+ /**
197
+ * Batch updates multiple fields of the specified messages.
198
+ *
199
+ * @param {string[]} messageIds - The identifiers of the messages to be updated.
200
+ * @param {Partial<DB_Message>} updateFields - An object containing the fields to update and their new values.
201
+ * @returns {Promise<number>} - The number of updated messages.
202
+ */
203
+ async batchUpdate(messageIds: string[], updateFields: Partial<DB_Message>): Promise<number> {
204
+ // Retrieve the messages by their IDs
205
+ const messagesToUpdate = await this.table.where(':id').anyOf(messageIds).toArray();
196
206
 
197
- return { ...originalMessage, id: newId };
198
- });
207
+ // Update the specified fields of each message
208
+ const updatedMessages = messagesToUpdate.map((message) => ({
209
+ ...message,
210
+ ...updateFields,
211
+ }));
199
212
 
200
- // 更新 parentId 为复制后的新ID
201
- for (const duplicatedMessage of duplicatedMessages) {
202
- if (duplicatedMessage.parentId && idMapping.has(duplicatedMessage.parentId)) {
203
- duplicatedMessage.parentId = idMapping.get(duplicatedMessage.parentId);
204
- }
205
- }
213
+ // Use the bulkPut method to update the messages in bulk
214
+ await this.table.bulkPut(updatedMessages);
206
215
 
207
- return duplicatedMessages;
216
+ return updatedMessages.length;
208
217
  }
209
218
 
219
+ // **************** Helper *************** //
220
+
210
221
  private mapChatMessageToDBMessage(message: ChatMessage): DB_Message {
211
222
  const { extra, ...messageData } = message;
212
223
 
@@ -1,37 +1,60 @@
1
+ import { LobeChatPluginManifest } from '@lobehub/chat-plugin-sdk';
2
+
1
3
  import { BaseModel } from '@/database/core';
4
+ import { LobeTool } from '@/types/tool';
2
5
  import { merge } from '@/utils/merge';
3
6
 
4
7
  import { DB_Plugin, DB_PluginSchema } from '../schemas/plugin';
5
8
 
9
+ export interface InstallPluginParams {
10
+ identifier: string;
11
+ manifest?: LobeChatPluginManifest;
12
+ type: 'plugin' | 'customPlugin';
13
+ }
14
+
6
15
  class _PluginModel extends BaseModel {
7
16
  constructor() {
8
17
  super('plugins', DB_PluginSchema);
9
18
  }
19
+ // **************** Query *************** //
10
20
 
11
21
  getList = async (): Promise<DB_Plugin[]> => {
12
22
  return this.table.toArray();
13
23
  };
14
24
 
15
- create = async (plugin: DB_Plugin) => {
25
+ // **************** Create *************** //
26
+
27
+ create = async (plugin: InstallPluginParams) => {
16
28
  const old = await this.table.get(plugin.identifier);
29
+ const dbPlugin = this.mapToDBPlugin(plugin);
17
30
 
18
- return this.table.put(merge(old, plugin), plugin.identifier);
31
+ return this.table.put(merge(old, dbPlugin), plugin.identifier);
19
32
  };
20
33
 
21
- batchCreate = async (plugins: DB_Plugin[]) => {
22
- return this._batchAdd(plugins);
34
+ batchCreate = async (plugins: LobeTool[]) => {
35
+ const dbPlugins = plugins.map((item) => this.mapToDBPlugin(item));
36
+
37
+ return this._batchAdd(dbPlugins);
23
38
  };
39
+ // **************** Delete *************** //
24
40
 
25
41
  delete(id: string) {
26
42
  return this.table.delete(id);
27
43
  }
44
+ clear() {
45
+ return this.table.clear();
46
+ }
47
+
48
+ // **************** Update *************** //
28
49
 
29
50
  update: (id: string, value: Partial<DB_Plugin>) => Promise<number> = async (id, value) => {
30
51
  return this.table.update(id, value);
31
52
  };
32
53
 
33
- clear() {
34
- return this.table.clear();
54
+ // **************** Helper *************** //
55
+
56
+ mapToDBPlugin(plugin: LobeTool) {
57
+ return { ...plugin, id: plugin.identifier } as DB_Plugin;
35
58
  }
36
59
  }
37
60
 
@@ -21,29 +21,7 @@ class _SessionModel extends BaseModel {
21
21
  super('sessions', DB_SessionSchema);
22
22
  }
23
23
 
24
- async create(type: 'agent' | 'group', defaultValue: Partial<LobeAgentSession>, id = uuid()) {
25
- const data = merge(DEFAULT_AGENT_LOBE_SESSION, { type, ...defaultValue });
26
- const dataDB = this.mapToDB_Session(data);
27
- return this._add(dataDB, id);
28
- }
29
-
30
- async batchCreate(sessions: LobeAgentSession[]) {
31
- const DB_Sessions = await Promise.all(
32
- sessions.map(async (s) => {
33
- if (s.group && s.group !== SessionDefaultGroup.Default) {
34
- // Check if the group exists in the SessionGroup table
35
- const groupExists = await SessionGroupModel.findById(s.group);
36
- // If the group does not exist, set it to default
37
- if (!groupExists) {
38
- s.group = SessionDefaultGroup.Default;
39
- }
40
- }
41
- return this.mapToDB_Session(s);
42
- }),
43
- );
44
-
45
- return this._batchAdd<DB_Session>(DB_Sessions, { idGenerator: uuid });
46
- }
24
+ // **************** Query *************** //
47
25
 
48
26
  async query({
49
27
  pageSize = 9999,
@@ -103,59 +81,6 @@ class _SessionModel extends BaseModel {
103
81
  return Object.fromEntries(groupItems);
104
82
  }
105
83
 
106
- async update(id: string, data: Partial<DB_Session>) {
107
- return super._update(id, data);
108
- }
109
-
110
- async updatePinned(id: string, pinned: boolean) {
111
- return this.update(id, { pinned: pinned ? 1 : 0 });
112
- }
113
-
114
- async updateConfig(id: string, data: DeepPartial<LobeAgentConfig>) {
115
- const session = await this.findById(id);
116
- if (!session) return;
117
-
118
- const config = merge(session.config, data);
119
-
120
- return this.update(id, { config });
121
- }
122
-
123
- /**
124
- * Delete a session , also delete all messages and topic associated with it.
125
- */
126
- async delete(id: string) {
127
- return this.db.transaction('rw', [this.table, this.db.topics, this.db.messages], async () => {
128
- // Delete all topics associated with the session
129
- const topics = await this.db.topics.where('sessionId').equals(id).toArray();
130
- const topicIds = topics.map((topic) => topic.id);
131
- if (topicIds.length > 0) {
132
- await this.db.topics.bulkDelete(topicIds);
133
- }
134
-
135
- // Delete all messages associated with the session
136
- const messages = await this.db.messages.where('sessionId').equals(id).toArray();
137
- const messageIds = messages.map((message) => message.id);
138
- if (messageIds.length > 0) {
139
- await this.db.messages.bulkDelete(messageIds);
140
- }
141
-
142
- // Finally, delete the session itself
143
- await this.table.delete(id);
144
- });
145
- }
146
-
147
- async clearTable() {
148
- return this.table.clear();
149
- }
150
-
151
- async findById(id: string): Promise<DBModel<DB_Session>> {
152
- return this.table.get(id);
153
- }
154
-
155
- async isEmpty() {
156
- return (await this.table.count()) === 0;
157
- }
158
-
159
84
  /**
160
85
  * Query sessions by keyword in title, description, content, or translated content
161
86
  * @param keyword The keyword to search for
@@ -225,6 +150,50 @@ class _SessionModel extends BaseModel {
225
150
  return this.mapToAgentSessions(items);
226
151
  }
227
152
 
153
+ async getPinnedSessions(): Promise<LobeSessions> {
154
+ const items: DBModel<DB_Session>[] = await this.table
155
+ .where('pinned')
156
+ .equals(1)
157
+ .reverse()
158
+ .sortBy('updatedAt');
159
+
160
+ return this.mapToAgentSessions(items);
161
+ }
162
+
163
+ async findById(id: string): Promise<DBModel<DB_Session>> {
164
+ return this.table.get(id);
165
+ }
166
+
167
+ async isEmpty() {
168
+ return (await this.table.count()) === 0;
169
+ }
170
+
171
+ // **************** Create *************** //
172
+
173
+ async create(type: 'agent' | 'group', defaultValue: Partial<LobeAgentSession>, id = uuid()) {
174
+ const data = merge(DEFAULT_AGENT_LOBE_SESSION, { type, ...defaultValue });
175
+ const dataDB = this.mapToDB_Session(data);
176
+ return this._add(dataDB, id);
177
+ }
178
+
179
+ async batchCreate(sessions: LobeAgentSession[]) {
180
+ const DB_Sessions = await Promise.all(
181
+ sessions.map(async (s) => {
182
+ if (s.group && s.group !== SessionDefaultGroup.Default) {
183
+ // Check if the group exists in the SessionGroup table
184
+ const groupExists = await SessionGroupModel.findById(s.group);
185
+ // If the group does not exist, set it to default
186
+ if (!groupExists) {
187
+ s.group = SessionDefaultGroup.Default;
188
+ }
189
+ }
190
+ return this.mapToDB_Session(s);
191
+ }),
192
+ );
193
+
194
+ return this._batchAdd<DB_Session>(DB_Sessions, { idGenerator: uuid });
195
+ }
196
+
228
197
  async duplicate(id: string, newTitle?: string) {
229
198
  const session = await this.findById(id);
230
199
  if (!session) return;
@@ -234,16 +203,57 @@ class _SessionModel extends BaseModel {
234
203
  return this._add(newSession, uuid());
235
204
  }
236
205
 
237
- async getPinnedSessions(): Promise<LobeSessions> {
238
- const items: DBModel<DB_Session>[] = await this.table
239
- .where('pinned')
240
- .equals(1)
241
- .reverse()
242
- .sortBy('updatedAt');
206
+ // **************** Delete *************** //
243
207
 
244
- return this.mapToAgentSessions(items);
208
+ /**
209
+ * Delete a session , also delete all messages and topic associated with it.
210
+ */
211
+ async delete(id: string) {
212
+ return this.db.transaction('rw', [this.table, this.db.topics, this.db.messages], async () => {
213
+ // Delete all topics associated with the session
214
+ const topics = await this.db.topics.where('sessionId').equals(id).toArray();
215
+ const topicIds = topics.map((topic) => topic.id);
216
+ if (topicIds.length > 0) {
217
+ await this.db.topics.bulkDelete(topicIds);
218
+ }
219
+
220
+ // Delete all messages associated with the session
221
+ const messages = await this.db.messages.where('sessionId').equals(id).toArray();
222
+ const messageIds = messages.map((message) => message.id);
223
+ if (messageIds.length > 0) {
224
+ await this.db.messages.bulkDelete(messageIds);
225
+ }
226
+
227
+ // Finally, delete the session itself
228
+ await this.table.delete(id);
229
+ });
230
+ }
231
+
232
+ async clearTable() {
233
+ return this.table.clear();
234
+ }
235
+
236
+ // **************** Update *************** //
237
+
238
+ async update(id: string, data: Partial<DB_Session>) {
239
+ return this._update(id, data);
240
+ }
241
+
242
+ async updatePinned(id: string, pinned: boolean) {
243
+ return this.update(id, { pinned: pinned ? 1 : 0 });
245
244
  }
246
245
 
246
+ async updateConfig(id: string, data: DeepPartial<LobeAgentConfig>) {
247
+ const session = await this.findById(id);
248
+ if (!session) return;
249
+
250
+ const config = merge(session.config, data);
251
+
252
+ return this.update(id, { config });
253
+ }
254
+
255
+ // **************** Helper *************** //
256
+
247
257
  private mapToDB_Session(session: LobeAgentSession): DBModel<DB_Session> {
248
258
  return {
249
259
  ...session,
@@ -8,32 +8,7 @@ class _SessionGroupModel extends BaseModel {
8
8
  super('sessionGroups', DB_SessionGroupSchema);
9
9
  }
10
10
 
11
- async create(name: string, sort?: number, id = nanoid()) {
12
- return this._add({ name, sort }, id);
13
- }
14
- async batchCreate(groups: SessionGroups) {
15
- return this._batchAdd(groups, { idGenerator: nanoid });
16
- }
17
-
18
- async findById(id: string): Promise<DB_SessionGroup> {
19
- return this.table.get(id);
20
- }
21
-
22
- async update(id: string, data: Partial<DB_SessionGroup>) {
23
- return super._update(id, data);
24
- }
25
-
26
- async delete(id: string, removeGroupItem: boolean = false) {
27
- this.db.sessions.toCollection().modify((session) => {
28
- // update all session associated with the sessionGroup to default
29
- if (session.group === id) session.group = 'default';
30
- });
31
- if (!removeGroupItem) {
32
- return this.table.delete(id);
33
- } else {
34
- return this.db.sessions.where('group').equals(id).delete();
35
- }
36
- }
11
+ // **************** Query *************** //
37
12
 
38
13
  async query(): Promise<SessionGroups> {
39
14
  const allGroups = await this.table.toArray();
@@ -60,6 +35,43 @@ class _SessionGroupModel extends BaseModel {
60
35
  });
61
36
  }
62
37
 
38
+ async findById(id: string): Promise<DB_SessionGroup> {
39
+ return this.table.get(id);
40
+ }
41
+
42
+ // **************** Create *************** //
43
+
44
+ async create(name: string, sort?: number, id = nanoid()) {
45
+ return this._add({ name, sort }, id);
46
+ }
47
+
48
+ async batchCreate(groups: SessionGroups) {
49
+ return this._batchAdd(groups, { idGenerator: nanoid });
50
+ }
51
+
52
+ // **************** Delete *************** //
53
+ async delete(id: string, removeGroupItem: boolean = false) {
54
+ this.db.sessions.toCollection().modify((session) => {
55
+ // update all session associated with the sessionGroup to default
56
+ if (session.group === id) session.group = 'default';
57
+ });
58
+ if (!removeGroupItem) {
59
+ return this.table.delete(id);
60
+ } else {
61
+ return this.db.sessions.where('group').equals(id).delete();
62
+ }
63
+ }
64
+
65
+ async clear() {
66
+ this.table.clear();
67
+ }
68
+
69
+ // **************** Update *************** //
70
+
71
+ async update(id: string, data: Partial<DB_SessionGroup>) {
72
+ return super._update(id, data);
73
+ }
74
+
63
75
  async updateOrder(sortMap: { id: string; sort: number }[]) {
64
76
  return this.db.transaction('rw', this.table, async () => {
65
77
  for (const { id, sort } of sortMap) {
@@ -67,10 +79,6 @@ class _SessionGroupModel extends BaseModel {
67
79
  }
68
80
  });
69
81
  }
70
-
71
- async clear() {
72
- this.table.clear();
73
- }
74
82
  }
75
83
 
76
84
  export const SessionGroupModel = new _SessionGroupModel();
@@ -23,19 +23,7 @@ class _TopicModel extends BaseModel {
23
23
  super('topics', DB_TopicSchema);
24
24
  }
25
25
 
26
- async create({ title, favorite, sessionId, messages }: CreateTopicParams, id = nanoid()) {
27
- const topic = await this._add({ favorite: favorite ? 1 : 0, sessionId, title: title }, id);
28
-
29
- // add topicId to these messages
30
- if (messages) {
31
- await this.db.messages.where('id').anyOf(messages).modify({ topicId: topic.id });
32
- }
33
- return topic;
34
- }
35
-
36
- async batchCreate(topics: CreateTopicParams[]) {
37
- return this._batchAdd(topics.map((t) => ({ ...t, favorite: t.favorite ? 1 : 0 })));
38
- }
26
+ // **************** Query *************** //
39
27
 
40
28
  async query({ pageSize = 9999, current = 0, sessionId }: QueryTopicParams): Promise<ChatTopic[]> {
41
29
  const offset = current * pageSize;
@@ -58,90 +46,6 @@ class _TopicModel extends BaseModel {
58
46
  return pagedTopics.map((i) => this.mapToChatTopic(i));
59
47
  }
60
48
 
61
- async findBySessionId(sessionId: string) {
62
- return this.table.where({ sessionId }).toArray();
63
- }
64
-
65
- async findById(id: string): Promise<DBModel<DB_Topic>> {
66
- return this.table.get(id);
67
- }
68
-
69
- /**
70
- * Deletes a topic and all messages associated with it.
71
- */
72
- async delete(id: string) {
73
- return this.db.transaction('rw', [this.table, this.db.messages], async () => {
74
- // Delete all messages associated with the topic
75
- const messages = await this.db.messages.where('topicId').equals(id).toArray();
76
-
77
- if (messages.length > 0) {
78
- const messageIds = messages.map((msg) => msg.id);
79
- await this.db.messages.bulkDelete(messageIds);
80
- }
81
-
82
- await this.table.delete(id);
83
- });
84
- }
85
-
86
- /**
87
- * Deletes multiple topic based on the sessionId.
88
- *
89
- * @param {string} sessionId - The identifier of the assistant associated with the messages.
90
- * @returns {Promise<void>}
91
- */
92
- async batchDeleteBySessionId(sessionId: string): Promise<void> {
93
- // use sessionId as the filter criteria in the query.
94
- const query = this.table.where('sessionId').equals(sessionId);
95
-
96
- // Retrieve a collection of message IDs that satisfy the criteria
97
- const topicIds = await query.primaryKeys();
98
-
99
- // Use the bulkDelete method to delete all selected messages in bulk
100
- return this.table.bulkDelete(topicIds);
101
- }
102
-
103
- async clearTable() {
104
- return this.table.clear();
105
- }
106
-
107
- async update(id: string, data: Partial<DB_Topic>) {
108
- return super._update(id, { ...data, updatedAt: Date.now() });
109
- }
110
-
111
- async toggleFavorite(id: string, newState?: boolean) {
112
- const topic = await this.findById(id);
113
- if (!topic) {
114
- throw new Error(`Topic with id ${id} not found`);
115
- }
116
-
117
- // Toggle the 'favorite' status
118
- const nextState = typeof newState !== 'undefined' ? newState : !topic.favorite;
119
-
120
- await this.update(id, { favorite: nextState ? 1 : 0 });
121
-
122
- return nextState;
123
- }
124
-
125
- /**
126
- * Deletes multiple topics and all messages associated with them in a transaction.
127
- */
128
- async batchDelete(topicIds: string[]) {
129
- return this.db.transaction('rw', [this.table, this.db.messages], async () => {
130
- // Iterate over each topicId and delete related messages, then delete the topic itself
131
- for (const topicId of topicIds) {
132
- // Delete all messages associated with the topic
133
- const messages = await this.db.messages.where('topicId').equals(topicId).toArray();
134
- if (messages.length > 0) {
135
- const messageIds = messages.map((msg) => msg.id);
136
- await this.db.messages.bulkDelete(messageIds);
137
- }
138
-
139
- // Delete the topic
140
- await this.table.delete(topicId);
141
- }
142
- });
143
- }
144
-
145
49
  queryAll() {
146
50
  return this.table.orderBy('updatedAt').toArray();
147
51
  }
@@ -201,6 +105,29 @@ class _TopicModel extends BaseModel {
201
105
  return uniqueTopics.map((i) => ({ ...i, favorite: !!i.favorite }));
202
106
  }
203
107
 
108
+ async findBySessionId(sessionId: string) {
109
+ return this.table.where({ sessionId }).toArray();
110
+ }
111
+
112
+ async findById(id: string): Promise<DBModel<DB_Topic>> {
113
+ return this.table.get(id);
114
+ }
115
+
116
+ // **************** Create *************** //
117
+
118
+ async create({ title, favorite, sessionId, messages }: CreateTopicParams, id = nanoid()) {
119
+ const topic = await this._add({ favorite: favorite ? 1 : 0, sessionId, title: title }, id);
120
+
121
+ // add topicId to these messages
122
+ if (messages) {
123
+ await this.db.messages.where('id').anyOf(messages).modify({ topicId: topic.id });
124
+ }
125
+ return topic;
126
+ }
127
+ async batchCreate(topics: CreateTopicParams[]) {
128
+ return this._batchAdd(topics.map((t) => ({ ...t, favorite: t.favorite ? 1 : 0 })));
129
+ }
130
+
204
131
  async duplicateTopic(topicId: string, newTitle?: string) {
205
132
  return this.db.transaction('rw', this.db.topics, this.db.messages, async () => {
206
133
  // Step 1: get DB_Topic
@@ -226,6 +153,86 @@ class _TopicModel extends BaseModel {
226
153
  });
227
154
  }
228
155
 
156
+ // **************** Delete *************** //
157
+
158
+ /**
159
+ * Deletes a topic and all messages associated with it.
160
+ */
161
+ async delete(id: string) {
162
+ return this.db.transaction('rw', [this.table, this.db.messages], async () => {
163
+ // Delete all messages associated with the topic
164
+ const messages = await this.db.messages.where('topicId').equals(id).toArray();
165
+
166
+ if (messages.length > 0) {
167
+ const messageIds = messages.map((msg) => msg.id);
168
+ await this.db.messages.bulkDelete(messageIds);
169
+ }
170
+
171
+ await this.table.delete(id);
172
+ });
173
+ }
174
+
175
+ /**
176
+ * Deletes multiple topic based on the sessionId.
177
+ *
178
+ * @param {string} sessionId - The identifier of the assistant associated with the messages.
179
+ * @returns {Promise<void>}
180
+ */
181
+ async batchDeleteBySessionId(sessionId: string): Promise<void> {
182
+ // use sessionId as the filter criteria in the query.
183
+ const query = this.table.where('sessionId').equals(sessionId);
184
+
185
+ // Retrieve a collection of message IDs that satisfy the criteria
186
+ const topicIds = await query.primaryKeys();
187
+
188
+ // Use the bulkDelete method to delete all selected messages in bulk
189
+ return this.table.bulkDelete(topicIds);
190
+ }
191
+ /**
192
+ * Deletes multiple topics and all messages associated with them in a transaction.
193
+ */
194
+ async batchDelete(topicIds: string[]) {
195
+ return this.db.transaction('rw', [this.table, this.db.messages], async () => {
196
+ // Iterate over each topicId and delete related messages, then delete the topic itself
197
+ for (const topicId of topicIds) {
198
+ // Delete all messages associated with the topic
199
+ const messages = await this.db.messages.where('topicId').equals(topicId).toArray();
200
+ if (messages.length > 0) {
201
+ const messageIds = messages.map((msg) => msg.id);
202
+ await this.db.messages.bulkDelete(messageIds);
203
+ }
204
+
205
+ // Delete the topic
206
+ await this.table.delete(topicId);
207
+ }
208
+ });
209
+ }
210
+
211
+ async clearTable() {
212
+ return this.table.clear();
213
+ }
214
+
215
+ // **************** Update *************** //
216
+ async update(id: string, data: Partial<DB_Topic>) {
217
+ return this._update(id, data);
218
+ }
219
+
220
+ async toggleFavorite(id: string, newState?: boolean) {
221
+ const topic = await this.findById(id);
222
+ if (!topic) {
223
+ throw new Error(`Topic with id ${id} not found`);
224
+ }
225
+
226
+ // Toggle the 'favorite' status
227
+ const nextState = typeof newState !== 'undefined' ? newState : !topic.favorite;
228
+
229
+ await this.update(id, { favorite: nextState ? 1 : 0 });
230
+
231
+ return nextState;
232
+ }
233
+
234
+ // **************** Helper *************** //
235
+
229
236
  private mapToChatTopic = (dbTopic: DBModel<DB_Topic>): ChatTopic => ({
230
237
  ...dbTopic,
231
238
  favorite: !!dbTopic.favorite,
@@ -10,6 +10,7 @@ class _UserModel extends BaseModel {
10
10
  constructor() {
11
11
  super('users', DB_UserSchema);
12
12
  }
13
+ // **************** Query *************** //
13
14
 
14
15
  getUser = async (): Promise<DB_User & { id: number }> => {
15
16
  const noUser = !(await this.table.count());
@@ -21,18 +22,20 @@ class _UserModel extends BaseModel {
21
22
  return list[0];
22
23
  };
23
24
 
25
+ // **************** Create *************** //
26
+
24
27
  create = async (user: DB_User) => {
25
28
  return this.table.put(user);
26
29
  };
27
30
 
28
- private update = async (id: number, value: DeepPartial<DB_User>) => {
29
- return this.table.update(id, value);
30
- };
31
+ // **************** Delete *************** //
31
32
 
32
33
  clear() {
33
34
  return this.table.clear();
34
35
  }
35
36
 
37
+ // **************** Update *************** //
38
+
36
39
  async updateSettings(settings: DeepPartial<GlobalSettings>) {
37
40
  const user = await this.getUser();
38
41
 
@@ -50,6 +53,12 @@ class _UserModel extends BaseModel {
50
53
 
51
54
  return this.update(user.id, { avatar });
52
55
  }
56
+
57
+ // **************** Helper *************** //
58
+
59
+ private update = async (id: number, value: DeepPartial<DB_User>) => {
60
+ return this.table.update(id, value);
61
+ };
53
62
  }
54
63
 
55
64
  export const UserModel = new _UserModel();
@@ -3,6 +3,7 @@ import { z } from 'zod';
3
3
 
4
4
  export const DB_PluginSchema = z.object({
5
5
  identifier: z.string(),
6
+ id: z.string(),
6
7
  type: z.enum(['plugin', 'customPlugin']),
7
8
  manifest: z.any().optional(),
8
9
  settings: z.any().optional(),
@@ -0,0 +1,18 @@
1
+ import useSWR, { SWRHook } from 'swr';
2
+
3
+ /**
4
+ * 这一类请求方法是比较「死」的请求模式,只会在第一次请求时触发。不会自动刷新,刷新需要搭配 refreshXXX 这样的方法实现,
5
+ * 适用于 messages、topics、sessions 等由用户在客户端交互产生的数据。
6
+ */
7
+ // @ts-ignore
8
+ export const useClientDataSWR: SWRHook = (key, fetch, config) =>
9
+ useSWR(key, fetch, {
10
+ // default is 2000ms ,it makes the user's quick switch don't work correctly.
11
+ // Cause issue like this: https://github.com/lobehub/lobe-chat/issues/532
12
+ // we need to set it to 0.
13
+ dedupingInterval: 0,
14
+ refreshWhenOffline: false,
15
+ revalidateOnFocus: false,
16
+ revalidateOnReconnect: false,
17
+ ...config,
18
+ });
@@ -559,7 +559,7 @@ describe('chatMessage actions', () => {
559
559
  });
560
560
 
561
561
  // 确保 mutate 调用了正确的参数
562
- expect(mutate).toHaveBeenCalledWith([activeId, activeTopicId]);
562
+ expect(mutate).toHaveBeenCalledWith(['SWR_USE_FETCH_MESSAGES', activeId, activeTopicId]);
563
563
  });
564
564
  it('should handle errors during refreshing messages', async () => {
565
565
  useChatStore.setState({ refreshMessages: realRefreshMessages });
@@ -2,12 +2,13 @@
2
2
  // Disable the auto sort key eslint rule to make the code more logic and readable
3
3
  import { copyToClipboard } from '@lobehub/ui';
4
4
  import { template } from 'lodash-es';
5
- import useSWR, { SWRResponse, mutate } from 'swr';
5
+ import { SWRResponse, mutate } from 'swr';
6
6
  import { StateCreator } from 'zustand/vanilla';
7
7
 
8
8
  import { LOADING_FLAT, isFunctionMessageAtStart, testFunctionMessageAtEnd } from '@/const/message';
9
9
  import { TraceEventType, TraceNameMap } from '@/const/trace';
10
10
  import { CreateMessageParams } from '@/database/models/message';
11
+ import { useClientDataSWR } from '@/libs/swr';
11
12
  import { chatService } from '@/services/chat';
12
13
  import { messageService } from '@/services/message';
13
14
  import { topicService } from '@/services/topic';
@@ -25,6 +26,8 @@ import { MessageDispatch, messagesReducer } from './reducer';
25
26
 
26
27
  const n = setNamespace('message');
27
28
 
29
+ const SWR_USE_FETCH_MESSAGES = 'SWR_USE_FETCH_MESSAGES';
30
+
28
31
  interface SendMessageParams {
29
32
  message: string;
30
33
  files?: { id: string; url: string }[];
@@ -274,9 +277,9 @@ export const chatMessage: StateCreator<
274
277
  await get().internalUpdateMessageContent(id, content);
275
278
  },
276
279
  useFetchMessages: (sessionId, activeTopicId) =>
277
- useSWR<ChatMessage[]>(
278
- [sessionId, activeTopicId],
279
- async ([sessionId, topicId]: [string, string | undefined]) =>
280
+ useClientDataSWR<ChatMessage[]>(
281
+ [SWR_USE_FETCH_MESSAGES, sessionId, activeTopicId],
282
+ async ([, sessionId, topicId]: [string, string, string | undefined]) =>
280
283
  messageService.getMessages(sessionId, topicId),
281
284
  {
282
285
  onSuccess: (messages, key) => {
@@ -289,14 +292,10 @@ export const chatMessage: StateCreator<
289
292
  }),
290
293
  );
291
294
  },
292
- // default is 2000ms ,it makes the user's quick switch don't work correctly.
293
- // Cause issue like this: https://github.com/lobehub/lobe-chat/issues/532
294
- // we need to set it to 0.
295
- dedupingInterval: 0,
296
295
  },
297
296
  ),
298
297
  refreshMessages: async () => {
299
- await mutate([get().activeId, get().activeTopicId]);
298
+ await mutate([SWR_USE_FETCH_MESSAGES, get().activeId, get().activeTopicId]);
300
299
  },
301
300
 
302
301
  // the internal process method of the AI message
@@ -6,6 +6,7 @@ import { StateCreator } from 'zustand/vanilla';
6
6
 
7
7
  import { INBOX_SESSION_ID } from '@/const/session';
8
8
  import { SESSION_CHAT_URL } from '@/const/url';
9
+ import { useClientDataSWR } from '@/libs/swr';
9
10
  import { sessionService } from '@/services/session';
10
11
  import { useGlobalStore } from '@/store/global';
11
12
  import { settingsSelectors } from '@/store/global/selectors';
@@ -154,7 +155,7 @@ export const createSessionSlice: StateCreator<
154
155
  },
155
156
 
156
157
  useFetchSessions: () =>
157
- useSWR<ChatSessionList>(FETCH_SESSIONS_KEY, sessionService.getSessionsWithGroup, {
158
+ useClientDataSWR<ChatSessionList>(FETCH_SESSIONS_KEY, sessionService.getSessionsWithGroup, {
158
159
  onSuccess: (data) => {
159
160
  // 由于 https://github.com/lobehub/lobe-chat/pull/541 的关系
160
161
  // 只有触发了 refreshSessions 才会更新 sessions,进而触发页面 rerender