@lobehub/chat 0.120.6 → 0.121.0

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 (121) hide show
  1. package/.github/ISSUE_TEMPLATE/2_feature_request_cn.yml +1 -1
  2. package/CHANGELOG.md +25 -0
  3. package/README.md +9 -9
  4. package/README.zh-CN.md +9 -9
  5. package/docs/Development/Feature-Development-Frontend.zh-CN.md +126 -0
  6. package/docs/Development/Feature-Development.zh-CN.md +664 -83
  7. package/docs/Development/{State-Management/State-Management-Intro.zh-CN.md → State-Management-Intro.zh-CN.md} +9 -9
  8. package/docs/Home.md +1 -0
  9. package/docs/_Sidebar.md +1 -0
  10. package/locales/ar/chat.json +13 -1
  11. package/locales/ar/common.json +1 -0
  12. package/locales/de-DE/chat.json +13 -1
  13. package/locales/de-DE/common.json +1 -0
  14. package/locales/en-US/chat.json +13 -1
  15. package/locales/en-US/common.json +1 -0
  16. package/locales/es-ES/chat.json +13 -1
  17. package/locales/es-ES/common.json +1 -0
  18. package/locales/fr-FR/chat.json +13 -1
  19. package/locales/fr-FR/common.json +1 -0
  20. package/locales/it-IT/chat.json +13 -1
  21. package/locales/it-IT/common.json +1 -0
  22. package/locales/ja-JP/chat.json +13 -1
  23. package/locales/ja-JP/common.json +1 -0
  24. package/locales/ko-KR/chat.json +13 -1
  25. package/locales/ko-KR/common.json +1 -0
  26. package/locales/nl-NL/chat.json +13 -1
  27. package/locales/nl-NL/common.json +1 -0
  28. package/locales/pl-PL/chat.json +13 -1
  29. package/locales/pl-PL/common.json +1 -0
  30. package/locales/pt-BR/chat.json +13 -1
  31. package/locales/pt-BR/common.json +1 -0
  32. package/locales/ru-RU/chat.json +13 -1
  33. package/locales/ru-RU/common.json +1 -0
  34. package/locales/tr-TR/chat.json +13 -1
  35. package/locales/tr-TR/common.json +1 -0
  36. package/locales/vi-VN/chat.json +13 -1
  37. package/locales/vi-VN/common.json +1 -0
  38. package/locales/zh-CN/chat.json +13 -1
  39. package/locales/zh-CN/common.json +1 -0
  40. package/locales/zh-TW/chat.json +13 -1
  41. package/locales/zh-TW/common.json +1 -0
  42. package/package.json +4 -6
  43. package/src/app/chat/(desktop)/features/ChatInput/Footer/index.tsx +18 -5
  44. package/src/app/chat/(desktop)/features/ChatInput/index.tsx +1 -1
  45. package/src/app/chat/features/ChatHeader/ShareButton/index.tsx +0 -1
  46. package/src/app/chat/features/Migration/Failed.tsx +2 -0
  47. package/src/app/chat/features/SessionListContent/CollapseGroup/Actions.tsx +115 -0
  48. package/src/app/chat/features/SessionListContent/CollapseGroup/index.tsx +6 -0
  49. package/src/app/chat/features/SessionListContent/DefaultMode.tsx +63 -23
  50. package/src/app/chat/features/SessionListContent/List/AddButton.tsx +3 -3
  51. package/src/app/chat/features/SessionListContent/List/Item/Actions.tsx +89 -35
  52. package/src/app/chat/features/SessionListContent/List/Item/index.tsx +35 -15
  53. package/src/app/chat/features/SessionListContent/List/index.tsx +4 -2
  54. package/src/app/chat/features/SessionListContent/Modals/ConfigGroupModal/GroupItem.tsx +84 -0
  55. package/src/app/chat/features/SessionListContent/Modals/ConfigGroupModal/index.tsx +79 -0
  56. package/src/app/chat/features/SessionListContent/Modals/CreateGroupModal.tsx +63 -0
  57. package/src/app/chat/features/SessionListContent/Modals/RenameGroupModal.tsx +50 -0
  58. package/src/app/chat/features/SessionListContent/SearchMode.tsx +1 -1
  59. package/src/app/settings/common/Common.tsx +5 -1
  60. package/src/components/FullscreenLoading/index.tsx +1 -1
  61. package/src/database/core/__tests__/db-upgrade.test.ts +42 -0
  62. package/src/database/core/db.ts +26 -4
  63. package/src/database/core/schemas.ts +14 -1
  64. package/src/database/core/types/db.ts +2 -0
  65. package/src/database/models/__tests__/message.test.ts +42 -0
  66. package/src/database/models/__tests__/plugin.test.ts +77 -0
  67. package/src/database/models/__tests__/session.test.ts +202 -63
  68. package/src/database/models/__tests__/sessionGroup.test.ts +195 -0
  69. package/src/database/models/__tests__/topic.test.ts +76 -1
  70. package/src/database/models/message.ts +7 -8
  71. package/src/database/models/session.ts +103 -7
  72. package/src/database/models/sessionGroup.ts +76 -0
  73. package/src/database/schemas/session.ts +1 -0
  74. package/src/database/schemas/sessionGroup.ts +8 -0
  75. package/src/features/ChatInput/ActionBar/Clear.tsx +2 -1
  76. package/src/features/Conversation/Actions/Assistant.tsx +1 -1
  77. package/src/features/Conversation/Actions/Function.tsx +2 -2
  78. package/src/features/Conversation/Actions/User.tsx +1 -1
  79. package/src/features/Conversation/hooks/useChatListActionsBar.tsx +3 -3
  80. package/src/features/PluginDevModal/index.tsx +3 -0
  81. package/src/features/PluginStore/PluginItem/Action.tsx +2 -0
  82. package/src/locales/default/chat.ts +13 -1
  83. package/src/locales/default/common.ts +1 -0
  84. package/src/migrations/FromV2ToV3/fixtures/input-v2-session.json +72 -0
  85. package/src/migrations/FromV2ToV3/fixtures/output-v3-from-v1.json +203 -0
  86. package/src/migrations/FromV2ToV3/fixtures/output-v3.json +74 -0
  87. package/src/migrations/FromV2ToV3/index.ts +30 -0
  88. package/src/migrations/FromV2ToV3/migrations.test.ts +42 -0
  89. package/src/migrations/FromV2ToV3/types/v3.ts +27 -0
  90. package/src/migrations/index.ts +7 -1
  91. package/src/services/__tests__/session.test.ts +198 -7
  92. package/src/services/config.ts +23 -7
  93. package/src/services/session.ts +67 -14
  94. package/src/store/global/slices/common/action.test.ts +130 -0
  95. package/src/store/global/slices/common/action.ts +14 -0
  96. package/src/store/global/slices/common/initialState.ts +6 -2
  97. package/src/store/global/slices/common/selectors.ts +1 -4
  98. package/src/store/global/slices/settings/__snapshots__/selectors.test.ts.snap +83 -0
  99. package/src/store/global/slices/settings/action.ts +2 -2
  100. package/src/store/global/slices/settings/selectors.test.ts +132 -182
  101. package/src/store/global/store.ts +7 -0
  102. package/src/store/session/initialState.ts +5 -30
  103. package/src/store/session/selectors.ts +2 -1
  104. package/src/store/session/slices/session/action.test.ts +56 -0
  105. package/src/store/session/slices/session/action.ts +13 -9
  106. package/src/store/session/slices/session/helpers.ts +2 -3
  107. package/src/store/session/slices/session/initialState.ts +31 -23
  108. package/src/store/session/slices/session/selectors/index.ts +0 -1
  109. package/src/store/session/slices/session/selectors/list.ts +11 -18
  110. package/src/store/session/slices/sessionGroup/action.ts +54 -0
  111. package/src/store/session/slices/sessionGroup/initialState.ts +5 -0
  112. package/src/store/session/slices/sessionGroup/selectors.ts +15 -0
  113. package/src/store/session/store.ts +9 -2
  114. package/src/styles/antdOverride.ts +0 -7
  115. package/src/types/exportConfig.ts +3 -1
  116. package/src/types/session.ts +27 -3
  117. package/src/store/session/slices/session/selectors/export.ts +0 -31
  118. /package/docs/Development/{Feature-Development.md → Feature-Development-Frontend.md} +0 -0
  119. /package/docs/Development/{State-Management/State-Management-Intro.md → State-Management-Intro.md} +0 -0
  120. /package/docs/Development/{State-Management/Selectors.md → State-Management-Selectors.md} +0 -0
  121. /package/docs/Development/{State-Management/Selectors.zh-CN.md → State-Management-Selectors.zh-CN.md} +0 -0
@@ -153,187 +153,137 @@ describe('settingsSelectors', () => {
153
153
  expect(result).toMatchSnapshot();
154
154
  });
155
155
  });
156
+ describe('defaultAgent', () => {
157
+ it('should merge DEFAULT_AGENT and s.settings.defaultAgent correctly', () => {
158
+ const s = {
159
+ settings: {
160
+ defaultAgent: {
161
+ config: {
162
+ systemRole: 'user',
163
+ model: LanguageModel.GPT3_5,
164
+ },
165
+ meta: {
166
+ avatar: 'agent-avatar.jpg',
167
+ description: 'Test agent',
168
+ },
169
+ },
170
+ },
171
+ } as unknown as GlobalStore;
172
+
173
+ const result = settingsSelectors.defaultAgent(s);
174
+
175
+ expect(result).toMatchSnapshot();
176
+ });
177
+ });
178
+
179
+ describe('defaultAgentConfig', () => {
180
+ it('should merge DEFAULT_AGENT_CONFIG and defaultAgent(s).config correctly', () => {
181
+ const s = {
182
+ settings: {
183
+ defaultAgent: {
184
+ config: {
185
+ systemRole: 'user',
186
+ model: LanguageModel.GPT3_5,
187
+ params: {
188
+ temperature: 0.7,
189
+ },
190
+ },
191
+ },
192
+ },
193
+ } as unknown as GlobalStore;
194
+
195
+ const result = settingsSelectors.defaultAgentConfig(s);
196
+
197
+ expect(result).toMatchSnapshot();
198
+ });
199
+ });
200
+
201
+ describe('defaultAgentMeta', () => {
202
+ it('should merge DEFAULT_AGENT_META and defaultAgent(s).meta correctly', () => {
203
+ const s = {
204
+ settings: {
205
+ defaultAgent: {
206
+ meta: {
207
+ avatar: 'agent-avatar.jpg',
208
+ description: 'Test agent',
209
+ },
210
+ },
211
+ },
212
+ } as unknown as GlobalStore;
213
+
214
+ const result = settingsSelectors.defaultAgentMeta(s);
215
+
216
+ expect(result).toMatchSnapshot();
217
+ });
218
+ });
156
219
 
157
- // describe('defaultAgent', () => {
158
- // it('should merge DEFAULT_AGENT and s.settings.defaultAgent correctly', () => {
159
- // const s: GlobalStore = {
160
- // settings: {
161
- // defaultAgent: {
162
- // config: {
163
- // model: 'gpt-3.5-turbo',
164
- // maxTokens: 100,
165
- // },
166
- // meta: {
167
- // name: 'Default Agent',
168
- // description: 'Default agent for testing',
169
- // },
170
- // },
171
- // },
172
- // };
173
- //
174
- // const result = settingsSelectors.defaultAgent(s);
175
- //
176
- // expect(result).toEqual(expected);
177
- // });
178
- // });
179
- //
180
- // describe('defaultAgentConfig', () => {
181
- // it('should merge DEFAULT_AGENT_CONFIG and defaultAgent(s).config correctly', () => {
182
- // const s: GlobalStore = {
183
- // settings: {
184
- // defaultAgent: {
185
- // config: {
186
- // model: 'gpt-3.5-turbo',
187
- // maxTokens: 100,
188
- // },
189
- // },
190
- // },
191
- // };
192
- //
193
- // const result = settingsSelectors.defaultAgentConfig(s);
194
- //
195
- // const defaultAgent = settingsSelectors.defaultAgent(s);
196
- // const expected = merge({}, DEFAULT_AGENT_CONFIG, defaultAgent.config);
197
- //
198
- // expect(result).toEqual(expected);
199
- // });
200
- // });
201
- //
202
- // describe('defaultAgentMeta', () => {
203
- // it('should merge DEFAULT_AGENT_META and defaultAgent(s).meta correctly', () => {
204
- // const s: GlobalStore = {
205
- // settings: {
206
- // defaultAgent: {
207
- // meta: {
208
- // name: 'Default Agent',
209
- // description: 'Default agent for testing',
210
- // },
211
- // },
212
- // },
213
- // };
214
- //
215
- // const result = settingsSelectors.defaultAgentMeta(s);
216
- //
217
- // const defaultAgent = settingsSelectors.defaultAgent(s);
218
- // const expected = merge({}, DEFAULT_AGENT_META, defaultAgent.meta);
219
- //
220
- // expect(result).toEqual(expected);
221
- // });
222
- // });
223
- //
224
- // describe('exportSettings', () => {
225
- // it('should remove OPENAI_API_KEY and password fields from s.settings', () => {
226
- // const s: GlobalStore = {
227
- // settings: {
228
- // OPENAI_API_KEY: 'openai-api-key',
229
- // password: 'password123',
230
- // avatar: 'avatar.jpg',
231
- // fontSize: 14,
232
- // language: 'en',
233
- // neutralColor: 'white',
234
- // primaryColor: 'blue',
235
- // themeMode: 'light',
236
- // defaultAgent: {
237
- // config: {
238
- // model: 'gpt-3.5-turbo',
239
- // maxTokens: 100,
240
- // },
241
- // meta: {
242
- // name: 'Default Agent',
243
- // description: 'Default agent for testing',
244
- // },
245
- // },
246
- // languageModel: {
247
- // azureOpenAI: {
248
- // AZURE_API_KEY: 'azure-api-key',
249
- // apiVersion: 'v1',
250
- // endpoint: 'https://azure-openai-endpoint.com',
251
- // models: ['gpt-3.5-turbo'],
252
- // },
253
- // openAI: {
254
- // OPENAI_API_KEY: 'openai-api-key',
255
- // endpoint: 'https://openai-endpoint.com',
256
- // models: ['gpt-3.5-turbo'],
257
- // },
258
- // },
259
- // },
260
- // };
261
- //
262
- // const result = settingsSelectors.exportSettings(s);
263
- //
264
- // const expected = {
265
- // avatar: 'avatar.jpg',
266
- // fontSize: 14,
267
- // language: 'en',
268
- // neutralColor: 'white',
269
- // primaryColor: 'blue',
270
- // themeMode: 'light',
271
- // defaultAgent: {
272
- // config: {
273
- // model: 'gpt-3.5-turbo',
274
- // maxTokens: 100,
275
- // },
276
- // meta: {
277
- // name: 'Default Agent',
278
- // description: 'Default agent for testing',
279
- // },
280
- // },
281
- // languageModel: {
282
- // azureOpenAI: {
283
- // AZURE_API_KEY: 'azure-api-key',
284
- // apiVersion: 'v1',
285
- // endpoint: 'https://azure-openai-endpoint.com',
286
- // models: ['gpt-3.5-turbo'],
287
- // },
288
- // openAI: {
289
- // endpoint: 'https://openai-endpoint.com',
290
- // models: ['gpt-3.5-turbo'],
291
- // },
292
- // },
293
- // };
294
- //
295
- // expect(result).toEqual(expected);
296
- // });
297
- //
298
- // it('should return the result as GlobalSettings type', () => {
299
- // const s: GlobalStore = {
300
- // settings: {
301
- // avatar: 'avatar.jpg',
302
- // fontSize: 14,
303
- // language: 'en',
304
- // neutralColor: 'white',
305
- // password: 'password123',
306
- // primaryColor: 'blue',
307
- // themeMode: 'light',
308
- // defaultAgent: {
309
- // config: {
310
- // model: 'gpt-3.5-turbo',
311
- // maxTokens: 100,
312
- // },
313
- // meta: {
314
- // name: 'Default Agent',
315
- // description: 'Default agent for testing',
316
- // },
317
- // },
318
- // languageModel: {
319
- // azureOpenAI: {
320
- // AZURE_API_KEY: 'azure-api-key',
321
- // apiVersion: 'v1',
322
- // endpoint: 'https://azure-openai-endpoint.com',
323
- // models: ['gpt-3.5-turbo'],
324
- // },
325
- // openAI: {
326
- // OPENAI_API_KEY: 'openai-api-key',
327
- // endpoint: 'https://openai-endpoint.com',
328
- // models: ['gpt-3.5-turbo'],
329
- // },
330
- // },
331
- // },
332
- // };
333
- //
334
- // const result = settingsSelectors.exportSettings(s);
335
- //
336
- // expect(result).toBeInstanceOf(GlobalSettings);
337
- // });
338
- // });
220
+ describe('currentTTS', () => {
221
+ it('should merge DEFAULT_TTS_CONFIG and s.settings.tts correctly', () => {
222
+ const s = {
223
+ settings: {
224
+ tts: {
225
+ sttAutoStop: false,
226
+ openAI: {
227
+ sttModel: 'whisper-2',
228
+ },
229
+ },
230
+ },
231
+ } as unknown as GlobalStore;
232
+
233
+ const result = settingsSelectors.currentTTS(s);
234
+
235
+ expect(result).toMatchSnapshot();
236
+ });
237
+ });
238
+
239
+ describe('currentLanguage', () => {
240
+ it('should return the correct language setting', () => {
241
+ const s = {
242
+ settings: {
243
+ language: 'fr',
244
+ },
245
+ } as unknown as GlobalStore;
246
+
247
+ const result = settingsSelectors.currentLanguage(s);
248
+
249
+ expect(result).toBe('fr');
250
+ });
251
+ });
252
+
253
+ describe('dalleConfig', () => {
254
+ it('should return the dalle configuration', () => {
255
+ const s = {
256
+ settings: {
257
+ tool: {
258
+ dalle: {
259
+ apiKey: 'dalle-api-key',
260
+ autoGenerate: true,
261
+ },
262
+ },
263
+ },
264
+ } as unknown as GlobalStore;
265
+
266
+ const result = settingsSelectors.dalleConfig(s);
267
+
268
+ expect(result).toMatchSnapshot();
269
+ });
270
+ });
271
+
272
+ describe('isDalleAutoGenerating', () => {
273
+ it('should return the autoGenerate flag from dalle configuration', () => {
274
+ const s = {
275
+ settings: {
276
+ tool: {
277
+ dalle: {
278
+ autoGenerate: true,
279
+ },
280
+ },
281
+ },
282
+ } as unknown as GlobalStore;
283
+
284
+ const result = settingsSelectors.isDalleAutoGenerating(s);
285
+
286
+ expect(result).toBe(true);
287
+ });
288
+ });
339
289
  });
@@ -5,6 +5,7 @@ import { createWithEqualityFn } from 'zustand/traditional';
5
5
  import { StateCreator } from 'zustand/vanilla';
6
6
 
7
7
  import { DEFAULT_AGENT, DEFAULT_LLM_CONFIG } from '@/const/settings';
8
+ import { SessionDefaultGroup } from '@/types/session';
8
9
  import { isDev } from '@/utils/env';
9
10
 
10
11
  import { createHyperStorage } from '../middleware/createHyperStorage';
@@ -32,6 +33,12 @@ const persistOptions: PersistOptions<GlobalStore, GlobalPersist> = {
32
33
  return {
33
34
  ...currentState,
34
35
  ...state,
36
+ preference: produce(state.preference, (draft) => {
37
+ if (!draft.expandSessionGroupKeys) {
38
+ draft.expandSessionGroupKeys = [SessionDefaultGroup.Pinned, SessionDefaultGroup.Default];
39
+ delete (draft as any).sessionGroupKeys;
40
+ }
41
+ }),
35
42
  settings: produce(state.settings, (draft) => {
36
43
  if (!draft.defaultAgent) {
37
44
  draft.defaultAgent = DEFAULT_AGENT;
@@ -1,34 +1,9 @@
1
- import { AppRouterInstance } from 'next/dist/shared/lib/app-router-context.shared-runtime';
1
+ import { SessionState, initialSessionState } from './slices/session/initialState';
2
+ import { SessionGroupState, initSessionGroupState } from './slices/sessionGroup/initialState';
2
3
 
3
- import { LobeAgentSession } from '@/types/session';
4
-
5
- export type SessionStoreState = SessionState;
6
-
7
- export interface SessionState {
8
- /**
9
- * @title 当前活动的会话
10
- * @description 当前正在编辑或查看的会话
11
- */
12
- activeId: string;
13
- isMobile?: boolean;
14
- isSearching: boolean;
15
- isSessionsFirstFetchFinished: boolean;
16
- /**
17
- * 后续看看是否可以将 router 部分的逻辑移出去
18
- * @deprecated
19
- */
20
- router?: AppRouterInstance;
21
- searchKeywords: string;
22
- searchSessions: LobeAgentSession[];
23
- sessions: LobeAgentSession[];
24
- }
4
+ export interface SessionStoreState extends SessionGroupState, SessionState {}
25
5
 
26
6
  export const initialState: SessionStoreState = {
27
- activeId: 'inbox',
28
- isMobile: false,
29
- isSearching: false,
30
- isSessionsFirstFetchFinished: false,
31
- searchKeywords: '',
32
- searchSessions: [],
33
- sessions: [],
7
+ ...initSessionGroupState,
8
+ ...initialSessionState,
34
9
  };
@@ -1,2 +1,3 @@
1
1
  export { agentSelectors } from './slices/agent/selectors';
2
- export { sessionExportSelectors, sessionSelectors } from './slices/session/selectors';
2
+ export { sessionSelectors } from './slices/session/selectors';
3
+ export { sessionGroupSelectors } from './slices/sessionGroup/selectors';
@@ -17,7 +17,9 @@ vi.mock('@/services/session', () => ({
17
17
  updateSessionGroup: vi.fn(),
18
18
  removeSession: vi.fn(),
19
19
  getSessions: vi.fn(),
20
+ updateSessionGroupId: vi.fn(),
20
21
  searchSessions: vi.fn(),
22
+ updateSessionPinned: vi.fn(),
21
23
  },
22
24
  }));
23
25
 
@@ -133,4 +135,58 @@ describe('SessionAction', () => {
133
135
  );
134
136
  });
135
137
  });
138
+
139
+ describe('activeSession', () => {
140
+ it('should set the provided session id as active', async () => {
141
+ const { result } = renderHook(() => useSessionStore());
142
+ const sessionId = 'active-session-id';
143
+
144
+ act(() => {
145
+ result.current.activeSession(sessionId);
146
+ });
147
+
148
+ expect(result.current.activeId).toBe(sessionId);
149
+ });
150
+ });
151
+
152
+ describe('pinSession', () => {
153
+ it('should pin a session when pinned is true', async () => {
154
+ const { result } = renderHook(() => useSessionStore());
155
+ const sessionId = 'session-id-to-pin';
156
+
157
+ await act(async () => {
158
+ await result.current.pinSession(sessionId, true);
159
+ });
160
+
161
+ expect(sessionService.updateSessionPinned).toHaveBeenCalledWith(sessionId, true);
162
+ expect(mockRefresh).toHaveBeenCalled();
163
+ });
164
+
165
+ it('should unpin a session when pinned is false', async () => {
166
+ const { result } = renderHook(() => useSessionStore());
167
+ const sessionId = 'session-id-to-unpin';
168
+
169
+ await act(async () => {
170
+ await result.current.pinSession(sessionId, false);
171
+ });
172
+
173
+ expect(sessionService.updateSessionPinned).toHaveBeenCalledWith(sessionId, false);
174
+ expect(mockRefresh).toHaveBeenCalled();
175
+ });
176
+ });
177
+
178
+ describe('updateSessionGroupId', () => {
179
+ it('should update the session group and refresh the list', async () => {
180
+ const { result } = renderHook(() => useSessionStore());
181
+ const sessionId = 'session-id';
182
+ const groupId = 'new-group-id';
183
+
184
+ await act(async () => {
185
+ await result.current.updateSessionGroupId(sessionId, groupId);
186
+ });
187
+
188
+ expect(sessionService.updateSessionGroupId).toHaveBeenCalledWith(sessionId, groupId);
189
+ expect(mockRefresh).toHaveBeenCalled();
190
+ });
191
+ });
136
192
  });
@@ -11,8 +11,8 @@ import { useGlobalStore } from '@/store/global';
11
11
  import { settingsSelectors } from '@/store/global/selectors';
12
12
  import { SessionStore } from '@/store/session';
13
13
  import {
14
+ ChatSessionList,
14
15
  LobeAgentSession,
15
- LobeAgentSettings,
16
16
  LobeSessionType,
17
17
  LobeSessions,
18
18
  } from '@/types/session';
@@ -42,12 +42,12 @@ export interface SessionAction {
42
42
  * @param agent
43
43
  * @returns sessionId
44
44
  */
45
- createSession: (agent?: DeepPartial<LobeAgentSettings>) => Promise<string>;
45
+ createSession: (session?: DeepPartial<LobeAgentSession>) => Promise<string>;
46
46
  duplicateSession: (id: string) => Promise<void>;
47
47
  /**
48
48
  * Pins or unpins a session.
49
49
  */
50
- pinSession: (id: string, pinned?: boolean) => Promise<void>;
50
+ pinSession: (id: string, pinned: boolean) => Promise<void>;
51
51
  /**
52
52
  * re-fetch the data
53
53
  */
@@ -127,7 +127,7 @@ export const createSessionSlice: StateCreator<
127
127
  },
128
128
 
129
129
  pinSession: async (sessionId, pinned) => {
130
- await sessionService.updateSessionGroup(sessionId, pinned ? 'pinned' : 'default');
130
+ await sessionService.updateSessionPinned(sessionId, pinned);
131
131
 
132
132
  await get().refreshSessions();
133
133
  },
@@ -144,6 +144,7 @@ export const createSessionSlice: StateCreator<
144
144
  get().switchSession();
145
145
  }
146
146
  },
147
+
147
148
  switchSession: (sessionId = INBOX_SESSION_ID) => {
148
149
  const { isMobile, router } = get();
149
150
 
@@ -154,20 +155,23 @@ export const createSessionSlice: StateCreator<
154
155
  },
155
156
 
156
157
  useFetchSessions: () =>
157
- useSWR<LobeSessions>(FETCH_SESSIONS_KEY, sessionService.getSessions, {
158
+ useSWR<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
161
- // 因此这里不能补充判断,否则会导致页面不更新
162
+ // 因此这里不能补充 equal 判断,否则会导致页面不更新
163
+ // if (get().isSessionsFirstFetchFinished && isEqual(get().sessions, data)) return;
164
+
162
165
  // TODO:后续的根本解法应该是解除 inbox 和 session 的数据耦合
163
166
  // 避免互相依赖的情况出现
164
167
 
165
- // if (get().isSessionsFirstFetchFinished && isEqual(get().sessions, data)) return;
166
-
167
168
  set(
168
169
  {
170
+ customSessionGroups: data.customGroup,
171
+ defaultSessions: data.default,
169
172
  isSessionsFirstFetchFinished: true,
170
- sessions: data,
173
+ pinnedSessions: data.pinned,
174
+ sessions: data.all,
171
175
  },
172
176
  false,
173
177
  n('useFetchSessions/onSuccess', data),
@@ -1,9 +1,8 @@
1
- import { LobeAgentSession, LobeSessions, SessionGroupDefaultKeys } from '@/types/session';
1
+ import { LobeAgentSession, LobeSessions } from '@/types/session';
2
2
 
3
3
  import { initLobeSession } from './initialState';
4
4
 
5
- export const getSessionPinned = (session: LobeAgentSession) =>
6
- session.group === SessionGroupDefaultKeys.Pinned;
5
+ export const getSessionPinned = (session: LobeAgentSession) => session.pinned;
7
6
 
8
7
  const getSessionById = (id: string, sessions: LobeSessions): LobeAgentSession => {
9
8
  const session = sessions.find((s) => s.id === id);
@@ -1,44 +1,52 @@
1
1
  import { AppRouterInstance } from 'next/dist/shared/lib/app-router-context.shared-runtime';
2
2
 
3
- import { DEFAULT_AGENT_META, DEFAULT_INBOX_AVATAR } from '@/const/meta';
3
+ import { DEFAULT_AGENT_META } from '@/const/meta';
4
4
  import { DEFAULT_AGENT_CONFIG } from '@/const/settings';
5
- import { LobeAgentSession, LobeSessionType } from '@/types/session';
6
- import { merge } from '@/utils/merge';
5
+ import { CustomSessionGroup, LobeAgentSession, LobeSessionType } from '@/types/session';
6
+
7
+ export const initLobeSession: LobeAgentSession = {
8
+ config: DEFAULT_AGENT_CONFIG,
9
+ createdAt: Date.now(),
10
+ id: '',
11
+ meta: DEFAULT_AGENT_META,
12
+ type: LobeSessionType.Agent,
13
+ updatedAt: Date.now(),
14
+ };
7
15
 
8
16
  export interface SessionState {
9
17
  /**
10
18
  * @title 当前活动的会话
11
19
  * @description 当前正在编辑或查看的会话
12
20
  */
13
- activeId: string | undefined;
14
- fetchSessionsLoading: boolean;
21
+ activeId: string;
22
+ customSessionGroups: CustomSessionGroup[];
23
+ defaultSessions: LobeAgentSession[];
15
24
  isMobile?: boolean;
25
+ isSearching: boolean;
26
+ isSessionsFirstFetchFinished: boolean;
27
+ pinnedSessions: LobeAgentSession[];
28
+ /**
29
+ * 后续看看是否可以将 router 部分的逻辑移出去
30
+ * @deprecated
31
+ */
16
32
  router?: AppRouterInstance;
17
33
  searchKeywords: string;
34
+ searchSessions: LobeAgentSession[];
35
+ /**
36
+ * it means defaultSessions
37
+ */
18
38
  sessions: LobeAgentSession[];
19
- topicSearchKeywords: string;
20
39
  }
21
40
 
22
- export const initLobeSession: LobeAgentSession = {
23
- config: DEFAULT_AGENT_CONFIG,
24
- createdAt: Date.now(),
25
- id: '',
26
- meta: DEFAULT_AGENT_META,
27
- type: LobeSessionType.Agent,
28
- updatedAt: Date.now(),
29
- };
30
- export const initInboxSession: LobeAgentSession = merge(initLobeSession, {
31
- id: 'inbox',
32
- meta: {
33
- avatar: DEFAULT_INBOX_AVATAR,
34
- },
35
- });
36
-
37
41
  export const initialSessionState: SessionState = {
38
42
  activeId: 'inbox',
39
- fetchSessionsLoading: true,
43
+ customSessionGroups: [],
44
+ defaultSessions: [],
40
45
  isMobile: false,
46
+ isSearching: false,
47
+ isSessionsFirstFetchFinished: false,
48
+ pinnedSessions: [],
41
49
  searchKeywords: '',
50
+ searchSessions: [],
42
51
  sessions: [],
43
- topicSearchKeywords: '',
44
52
  };
@@ -1,2 +1 @@
1
- export * from './export';
2
1
  export * from './list';