@lobehub/chat 0.105.2 → 0.107.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.
- package/CHANGELOG.md +50 -0
- package/README.md +18 -0
- package/README.zh-CN.md +18 -0
- package/docs/Environment-Variable.md +4 -2
- package/docs/Environment-Variable.zh-CN.md +4 -2
- package/locales/en_US/common.json +19 -0
- package/locales/en_US/migration.json +45 -0
- package/locales/en_US/setting.json +7 -7
- package/locales/ja_JP/common.json +19 -0
- package/locales/ja_JP/migration.json +45 -0
- package/locales/ja_JP/setting.json +2 -2
- package/locales/ko_KR/common.json +19 -0
- package/locales/ko_KR/migration.json +45 -0
- package/locales/ko_KR/setting.json +2 -2
- package/locales/ru_RU/common.json +19 -0
- package/locales/ru_RU/migration.json +45 -0
- package/locales/ru_RU/setting.json +2 -2
- package/locales/zh_CN/common.json +19 -0
- package/locales/zh_CN/migration.json +45 -0
- package/locales/zh_CN/setting.json +1 -1
- package/locales/zh_TW/common.json +19 -0
- package/locales/zh_TW/migration.json +45 -0
- package/locales/zh_TW/setting.json +2 -2
- package/package.json +2 -1
- package/src/app/api/openai/chat/createChatCompletion.test.ts +4 -4
- package/src/app/api/openai/chat/createChatCompletion.ts +4 -10
- package/src/app/api/openai/createBizOpenAI/index.ts +1 -1
- package/src/app/api/openai/errorResponse.test.ts +1 -1
- package/src/app/chat/(desktop)/features/ChatInput/Footer/index.tsx +2 -1
- package/src/app/chat/(mobile)/features/ChatInput/SendButton.tsx +2 -2
- package/src/app/chat/features/ChatHeader/ShareButton/Inner.tsx +2 -5
- package/src/app/chat/features/ChatHeader/ShareButton/index.tsx +2 -2
- package/src/app/chat/features/ChatInput/ActionBar/Clear.tsx +2 -2
- package/src/app/chat/features/ChatInput/ActionBar/ModelSwitch.tsx +1 -1
- package/src/app/chat/features/ChatInput/ActionBar/Token/TokenTag.tsx +8 -2
- package/src/app/chat/features/ChatInput/InputAreaInner/index.tsx +2 -2
- package/src/app/chat/features/ChatInput/STT/index.tsx +2 -2
- package/src/app/chat/features/ChatInput/Topic/index.tsx +2 -2
- package/src/app/chat/features/ChatInput/useSend.ts +3 -3
- package/src/app/chat/features/Conversation/ChatList/Actions/index.ts +2 -2
- package/src/app/chat/features/Conversation/ChatList/Error/ApiKeyForm.tsx +2 -2
- package/src/app/chat/features/Conversation/ChatList/Error/InvalidAccess.tsx +2 -2
- package/src/app/chat/features/Conversation/ChatList/Error/Plugin/PluginSettings.tsx +2 -2
- package/src/app/chat/features/Conversation/ChatList/Extras/Assistant.test.tsx +4 -4
- package/src/app/chat/features/Conversation/ChatList/Extras/Assistant.tsx +30 -31
- package/src/app/chat/features/Conversation/ChatList/Extras/TTS.tsx +2 -2
- package/src/app/chat/features/Conversation/ChatList/Extras/Translate.tsx +2 -2
- package/src/app/chat/features/Conversation/ChatList/Extras/User.tsx +8 -5
- package/src/app/chat/features/Conversation/ChatList/Extras/index.ts +3 -3
- package/src/app/chat/features/Conversation/ChatList/Extras/type.ts +5 -0
- package/src/app/chat/features/Conversation/ChatList/Messages/Assistant.tsx +10 -6
- package/src/app/chat/features/Conversation/ChatList/Messages/Default.tsx +7 -3
- package/src/app/chat/features/Conversation/ChatList/Messages/Function.tsx +7 -6
- package/src/app/chat/features/Conversation/ChatList/Messages/index.ts +7 -7
- package/src/app/chat/features/Conversation/ChatList/Plugins/Render/StandaloneType/Iframe.tsx +6 -6
- package/src/app/chat/features/Conversation/ChatList/index.tsx +16 -24
- package/src/app/chat/features/Conversation/ScrollAnchor/index.tsx +2 -2
- package/src/app/chat/features/Conversation/index.tsx +3 -3
- package/src/app/chat/features/Conversation/useInitConversation.ts +43 -0
- package/src/app/chat/features/Migration/ExportConfigButton.tsx +33 -0
- package/src/app/chat/features/Migration/Failed.tsx +115 -0
- package/src/app/chat/features/Migration/Modal.tsx +80 -0
- package/src/app/chat/features/Migration/Start.tsx +106 -0
- package/src/app/chat/features/Migration/UpgradeButton.tsx +74 -0
- package/src/app/chat/features/Migration/const.ts +15 -0
- package/src/app/chat/features/Migration/index.tsx +44 -0
- package/src/app/chat/features/SessionListContent/DefaultMode.tsx +54 -0
- package/src/app/chat/features/SessionListContent/List/Item/Actions.tsx +5 -4
- package/src/app/chat/features/SessionListContent/List/Item/index.tsx +22 -28
- package/src/app/chat/features/SessionListContent/SearchMode.tsx +15 -0
- package/src/app/chat/features/SessionListContent/index.tsx +4 -44
- package/src/app/chat/features/SessionSearchBar/index.tsx +11 -3
- package/src/app/chat/features/TopicListContent/Header.tsx +4 -4
- package/src/app/chat/features/TopicListContent/Topic/TopicContent.tsx +11 -9
- package/src/app/chat/features/TopicListContent/Topic/TopicItem.tsx +15 -13
- package/src/app/chat/features/TopicListContent/Topic/index.tsx +9 -16
- package/src/app/chat/features/TopicListContent/TopicSearchBar/index.tsx +13 -4
- package/src/app/chat/features/TopicListContent/index.tsx +1 -2
- package/src/app/chat/page.tsx +6 -1
- package/src/app/chat/settings/features/HeaderContent.tsx +3 -3
- package/src/app/home/Redirect.tsx +13 -7
- package/src/app/settings/(mobile)/features/ExtraList.tsx +12 -4
- package/src/app/settings/common/Common.tsx +16 -4
- package/src/app/welcome/features/Banner/index.tsx +9 -10
- package/src/chains/summaryTitle.ts +5 -2
- package/src/components/DataStyleModal/index.tsx +64 -0
- package/src/config/client.ts +5 -0
- package/src/const/session.ts +21 -0
- package/src/const/settings.ts +1 -1
- package/src/database/core/__tests__/db.test.ts +8 -5
- package/src/database/core/__tests__/model.test.ts +3 -3
- package/src/database/core/db.ts +38 -10
- package/src/database/core/index.ts +1 -0
- package/src/database/core/model.ts +121 -10
- package/src/database/core/schemas.ts +22 -0
- package/src/database/core/types/db.ts +13 -0
- package/src/database/models/__DEBUG.ts +119 -0
- package/src/database/models/{file.test.ts → __tests__/file.test.ts} +19 -6
- package/src/database/models/__tests__/message.test.ts +314 -0
- package/src/database/models/__tests__/session.test.ts +117 -0
- package/src/database/models/__tests__/topic.test.ts +250 -0
- package/src/database/models/file.ts +9 -5
- package/src/database/models/message.ts +186 -0
- package/src/database/models/session.ts +160 -0
- package/src/database/models/topic.ts +196 -0
- package/src/{types/database → database/schemas}/files.ts +2 -2
- package/src/database/schemas/message.ts +37 -0
- package/src/database/schemas/session.ts +56 -0
- package/src/database/schemas/topic.ts +12 -0
- package/src/features/AgentSetting/AgentConfig/index.tsx +8 -1
- package/src/features/AgentSetting/AgentTTS/SelectWithTTSPreview.tsx +1 -1
- package/src/features/AgentSetting/store/action.ts +1 -1
- package/src/features/AgentSetting/store/initialState.ts +1 -1
- package/src/features/AgentSetting/store/reducers/config.ts +1 -1
- package/src/features/DataImporter/index.tsx +240 -0
- package/src/features/DebugUI/index.tsx +34 -0
- package/src/features/SideBar/BottomActions.tsx +8 -14
- package/src/hooks/useImportConfig.ts +13 -30
- package/src/hooks/useTTS.ts +1 -1
- package/src/layout/GlobalLayout/index.tsx +16 -1
- package/src/locales/default/common.ts +19 -0
- package/src/locales/default/migration.ts +47 -0
- package/src/locales/default/setting.ts +1 -1
- package/src/locales/resources/en_US.ts +2 -0
- package/src/locales/resources/ja_JP.ts +2 -0
- package/src/locales/resources/ko_KR.ts +2 -0
- package/src/locales/resources/ru_RU.ts +2 -0
- package/src/locales/resources/zh_CN.ts +2 -0
- package/src/locales/resources/zh_TW.ts +2 -0
- package/src/migrations/FromV0ToV1.ts +2 -4
- package/src/migrations/FromV1ToV2/fixtures/input-v1-session.json +191 -0
- package/src/migrations/FromV1ToV2/fixtures/output-v2.json +202 -0
- package/src/migrations/FromV1ToV2/index.ts +82 -0
- package/src/migrations/FromV1ToV2/migrations.test.ts +224 -0
- package/src/migrations/FromV1ToV2/types/v1.ts +78 -0
- package/src/migrations/FromV1ToV2/types/v2.ts +52 -0
- package/src/{utils → migrations}/VersionController.test.ts +1 -3
- package/src/{utils → migrations}/VersionController.ts +5 -2
- package/src/migrations/index.ts +17 -3
- package/src/services/__tests__/file.test.ts +3 -3
- package/src/services/chat.ts +66 -5
- package/src/services/config.ts +184 -0
- package/src/services/debug.ts +13 -0
- package/src/services/file.ts +6 -2
- package/src/services/github.ts +25 -0
- package/src/services/message.ts +79 -0
- package/src/services/session.ts +63 -0
- package/src/services/topic.ts +56 -0
- package/src/store/chat/actions/enhance.ts +95 -0
- package/src/store/{session/slices/chat → chat}/actions/message.ts +225 -247
- package/src/store/{session/slices/chat → chat}/actions/plugin.ts +29 -34
- package/src/store/{session/slices/chat → chat}/actions/share.ts +9 -13
- package/src/store/chat/actions/topic.ts +197 -0
- package/src/store/chat/helpers.ts +23 -0
- package/src/store/chat/index.ts +3 -0
- package/src/store/chat/initialState.ts +48 -0
- package/src/store/chat/reducers/message.test.ts +83 -0
- package/src/store/chat/reducers/message.ts +83 -0
- package/src/store/chat/selectors/__tests__/topic.test.ts +43 -0
- package/src/store/chat/selectors/chat.ts +119 -0
- package/src/store/chat/selectors/index.ts +2 -0
- package/src/store/chat/selectors/topic.ts +28 -0
- package/src/store/chat/store.ts +63 -0
- package/src/store/files/slices/images/action.ts +6 -4
- package/src/store/global/selectors/__snapshots__/settings.test.ts.snap +99 -0
- package/src/store/global/selectors/settings.test.ts +51 -0
- package/src/store/global/selectors/settings.ts +36 -5
- package/src/store/global/store.ts +1 -1
- package/src/store/middleware/createHyperStorage/index.ts +40 -24
- package/src/store/middleware/createHyperStorage/keyMapper.ts +8 -2
- package/src/store/middleware/createHyperStorage/type.ts +10 -8
- package/src/store/plugin/slices/plugin/action.ts +1 -1
- package/src/store/plugin/store.ts +2 -4
- package/src/store/session/helpers.ts +1 -1
- package/src/store/session/hooks/useSessionHydrated.ts +6 -10
- package/src/store/session/initialState.ts +26 -7
- package/src/store/session/selectors.ts +1 -2
- package/src/store/session/slices/agent/action.ts +26 -35
- package/src/store/session/slices/agent/selectors.ts +32 -37
- package/src/store/session/slices/session/action.ts +81 -88
- package/src/store/session/slices/session/helpers.ts +19 -0
- package/src/store/session/slices/session/initialState.ts +7 -10
- package/src/store/session/slices/session/selectors/export.ts +12 -9
- package/src/store/session/slices/session/selectors/index.ts +2 -35
- package/src/store/session/slices/session/selectors/list.test.ts +25 -203
- package/src/store/session/slices/session/selectors/list.ts +40 -78
- package/src/store/session/store.ts +11 -17
- package/src/types/agent/index.ts +61 -0
- package/src/types/chatMessage.ts +11 -20
- package/src/types/exportConfig.ts +7 -2
- package/src/types/files.ts +2 -2
- package/src/types/llm.ts +1 -1
- package/src/types/meta.ts +24 -12
- package/src/types/openai/chat.ts +9 -1
- package/src/types/openai/functionCall.ts +4 -0
- package/src/types/session.ts +10 -94
- package/src/types/settings.ts +2 -0
- package/src/types/translate.ts +2 -1
- package/src/utils/config.ts +5 -11
- package/src/utils/fetch.ts +8 -2
- package/src/app/chat/features/Conversation/usePluginsInit.ts +0 -14
- package/src/database/core/schema.ts +0 -9
- package/src/helpers/export.ts +0 -69
- package/src/hooks/useExportConfig.ts +0 -6
- package/src/store/session/slices/chat/actions/index.ts +0 -32
- package/src/store/session/slices/chat/actions/topic.ts +0 -171
- package/src/store/session/slices/chat/actions/translate.ts +0 -113
- package/src/store/session/slices/chat/helpers.ts +0 -9
- package/src/store/session/slices/chat/initialState.ts +0 -13
- package/src/store/session/slices/chat/reducers/message.test.ts +0 -319
- package/src/store/session/slices/chat/reducers/message.ts +0 -156
- package/src/store/session/slices/chat/reducers/topic.test.ts +0 -179
- package/src/store/session/slices/chat/reducers/topic.ts +0 -81
- package/src/store/session/slices/chat/selectors/chat.ts +0 -111
- package/src/store/session/slices/chat/selectors/index.ts +0 -26
- package/src/store/session/slices/chat/selectors/topic.ts +0 -30
- package/src/store/session/slices/chat/selectors/utils.test.ts +0 -385
- package/src/store/session/slices/chat/selectors/utils.ts +0 -91
- package/src/store/session/slices/chat/utils.ts +0 -13
- package/src/store/session/slices/session/reducers/session.test.ts +0 -577
- package/src/store/session/slices/session/reducers/session.ts +0 -182
- package/src/types/database/db.ts +0 -4
- /package/src/store/{session/slices/chat → chat}/reducers/files.test.ts +0 -0
- /package/src/store/{session/slices/chat → chat}/reducers/files.ts +0 -0
|
@@ -3,20 +3,13 @@ import { LanguageModel } from '@/types/llm';
|
|
|
3
3
|
import { LobeAgentSession, LobeSessionType } from '@/types/session';
|
|
4
4
|
|
|
5
5
|
import { initLobeSession } from '../initialState';
|
|
6
|
-
import {
|
|
7
|
-
currentSession,
|
|
8
|
-
currentSessionSafe,
|
|
9
|
-
getSessionById,
|
|
10
|
-
getSessionMetaById,
|
|
11
|
-
hasSessionList,
|
|
12
|
-
sessionList,
|
|
13
|
-
} from './list';
|
|
6
|
+
import { sessionSelectors } from './list';
|
|
14
7
|
|
|
15
8
|
describe('currentSession', () => {
|
|
16
9
|
const s = {
|
|
17
10
|
activeId: '1',
|
|
18
|
-
sessions:
|
|
19
|
-
|
|
11
|
+
sessions: [
|
|
12
|
+
{
|
|
20
13
|
id: '1',
|
|
21
14
|
config: {
|
|
22
15
|
model: LanguageModel.GPT3_5,
|
|
@@ -25,7 +18,7 @@ describe('currentSession', () => {
|
|
|
25
18
|
},
|
|
26
19
|
type: LobeSessionType.Agent,
|
|
27
20
|
} as LobeAgentSession,
|
|
28
|
-
|
|
21
|
+
{
|
|
29
22
|
id: '2',
|
|
30
23
|
config: {
|
|
31
24
|
model: LanguageModel.GPT3_5,
|
|
@@ -34,36 +27,23 @@ describe('currentSession', () => {
|
|
|
34
27
|
},
|
|
35
28
|
type: LobeSessionType.Agent,
|
|
36
29
|
} as LobeAgentSession,
|
|
37
|
-
|
|
38
|
-
inbox: {
|
|
39
|
-
id: 'inbox',
|
|
40
|
-
config: {
|
|
41
|
-
model: LanguageModel.GPT3_5,
|
|
42
|
-
params: {},
|
|
43
|
-
systemRole: 'system-role',
|
|
44
|
-
},
|
|
45
|
-
type: LobeSessionType.Agent,
|
|
46
|
-
} as LobeAgentSession,
|
|
30
|
+
],
|
|
47
31
|
} as unknown as SessionStore;
|
|
48
32
|
|
|
49
33
|
it('should return undefined when s.activeId is not defined', () => {
|
|
50
|
-
expect(currentSession({ sessions: {} } as any)).toBeUndefined();
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it('should return s.inbox when s.activeId is equal to INBOX_SESSION_ID', () => {
|
|
54
|
-
expect(currentSession({ ...s, activeId: 'inbox' })).toEqual(s.inbox);
|
|
34
|
+
expect(sessionSelectors.currentSession({ sessions: {} } as any)).toBeUndefined();
|
|
55
35
|
});
|
|
56
36
|
|
|
57
37
|
it('should return s.sessions[s.activeId] when s.activeId is not equal to INBOX_SESSION_ID', () => {
|
|
58
|
-
expect(currentSession(s)).toEqual(s.sessions[
|
|
38
|
+
expect(sessionSelectors.currentSession(s)).toEqual(s.sessions[0]);
|
|
59
39
|
});
|
|
60
40
|
});
|
|
61
41
|
|
|
62
42
|
describe('currentSessionSafe', () => {
|
|
63
43
|
const s = {
|
|
64
44
|
activeId: '1',
|
|
65
|
-
sessions:
|
|
66
|
-
|
|
45
|
+
sessions: [
|
|
46
|
+
{
|
|
67
47
|
id: '1',
|
|
68
48
|
config: {
|
|
69
49
|
model: LanguageModel.GPT3_5,
|
|
@@ -72,7 +52,7 @@ describe('currentSessionSafe', () => {
|
|
|
72
52
|
},
|
|
73
53
|
type: LobeSessionType.Agent,
|
|
74
54
|
} as LobeAgentSession,
|
|
75
|
-
|
|
55
|
+
{
|
|
76
56
|
id: '2',
|
|
77
57
|
config: {
|
|
78
58
|
model: LanguageModel.GPT3_5,
|
|
@@ -81,151 +61,23 @@ describe('currentSessionSafe', () => {
|
|
|
81
61
|
},
|
|
82
62
|
type: LobeSessionType.Agent,
|
|
83
63
|
} as LobeAgentSession,
|
|
84
|
-
|
|
85
|
-
inbox: {
|
|
86
|
-
id: 'inbox',
|
|
87
|
-
config: {
|
|
88
|
-
model: LanguageModel.GPT3_5,
|
|
89
|
-
params: {},
|
|
90
|
-
systemRole: 'system-role',
|
|
91
|
-
},
|
|
92
|
-
type: LobeSessionType.Agent,
|
|
93
|
-
} as LobeAgentSession,
|
|
64
|
+
],
|
|
94
65
|
} as unknown as SessionStore;
|
|
95
66
|
|
|
96
67
|
it('should return initLobeSession when currentSession(s) returns undefined', () => {
|
|
97
|
-
expect(currentSessionSafe({ sessions: {} } as any)).toEqual(initLobeSession);
|
|
68
|
+
expect(sessionSelectors.currentSessionSafe({ sessions: {} } as any)).toEqual(initLobeSession);
|
|
98
69
|
});
|
|
99
70
|
|
|
100
71
|
it('should return the result of currentSession(s) when it returns a non-undefined value', () => {
|
|
101
|
-
expect(currentSessionSafe(s)).toEqual(s.sessions[
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
describe('sessionList', () => {
|
|
106
|
-
const s = {
|
|
107
|
-
sessions: {
|
|
108
|
-
'1': {
|
|
109
|
-
pinned: true,
|
|
110
|
-
updateAt: 100,
|
|
111
|
-
},
|
|
112
|
-
'2': {
|
|
113
|
-
pinned: false,
|
|
114
|
-
updateAt: 200,
|
|
115
|
-
},
|
|
116
|
-
'3': {
|
|
117
|
-
pinned: true,
|
|
118
|
-
updateAt: 300,
|
|
119
|
-
},
|
|
120
|
-
},
|
|
121
|
-
} as unknown as SessionStore;
|
|
122
|
-
|
|
123
|
-
it('should return an array of sessions sorted by pinned and updateAt fields', () => {
|
|
124
|
-
expect(sessionList(s)).toEqual([s.sessions['3'], s.sessions['1'], s.sessions['2']]);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it('should return an empty array when s.sessions is an empty object', () => {
|
|
128
|
-
const result = sessionList({
|
|
129
|
-
sessions: {},
|
|
130
|
-
} as any);
|
|
131
|
-
expect(result).toEqual([]);
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
it('should return a sorted session list when s.sessions is not empty object', () => {
|
|
135
|
-
const session1 = {
|
|
136
|
-
id: '1',
|
|
137
|
-
pinned: true,
|
|
138
|
-
updateAt: 1635705600000,
|
|
139
|
-
meta: {},
|
|
140
|
-
};
|
|
141
|
-
const session2 = {
|
|
142
|
-
id: '2',
|
|
143
|
-
pinned: false,
|
|
144
|
-
updateAt: 1635705600000,
|
|
145
|
-
meta: {},
|
|
146
|
-
};
|
|
147
|
-
const session3 = {
|
|
148
|
-
id: '3',
|
|
149
|
-
pinned: true,
|
|
150
|
-
updateAt: 1635705700000,
|
|
151
|
-
meta: {},
|
|
152
|
-
};
|
|
153
|
-
const s = {
|
|
154
|
-
sessions: {
|
|
155
|
-
'1': session1,
|
|
156
|
-
'2': session2,
|
|
157
|
-
'3': session3,
|
|
158
|
-
},
|
|
159
|
-
} as unknown as SessionStore;
|
|
160
|
-
const result = sessionList(s);
|
|
161
|
-
expect(result).toEqual([session3, session1, session2]);
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it('should return a sorted session list when s.searchKeywords is not an empty string', () => {
|
|
165
|
-
const session1 = {
|
|
166
|
-
id: '1',
|
|
167
|
-
pinned: true,
|
|
168
|
-
meta: { title: 'yword' },
|
|
169
|
-
|
|
170
|
-
updateAt: 1635705600000,
|
|
171
|
-
};
|
|
172
|
-
const session2 = {
|
|
173
|
-
id: '2',
|
|
174
|
-
pinned: false,
|
|
175
|
-
meta: { title: 'keyword' },
|
|
176
|
-
updateAt: 1635705600000,
|
|
177
|
-
};
|
|
178
|
-
const session3 = {
|
|
179
|
-
id: '3',
|
|
180
|
-
pinned: true,
|
|
181
|
-
meta: { title: 'kyword' },
|
|
182
|
-
updateAt: 1635705800000,
|
|
183
|
-
};
|
|
184
|
-
const s = {
|
|
185
|
-
sessions: {
|
|
186
|
-
'1': session1,
|
|
187
|
-
'2': session2,
|
|
188
|
-
'3': session3,
|
|
189
|
-
},
|
|
190
|
-
searchKeywords: 'k',
|
|
191
|
-
} as unknown as SessionStore;
|
|
192
|
-
|
|
193
|
-
const result = sessionList(s);
|
|
194
|
-
expect(result).toEqual([session3, session2]);
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
it('should return an empty array when s.sessions is an empty object and s.searchKeywords is not an empty string', () => {
|
|
198
|
-
const result = sessionList({
|
|
199
|
-
sessions: {},
|
|
200
|
-
searchKeywords: 'keyword',
|
|
201
|
-
} as unknown as SessionStore);
|
|
202
|
-
expect(result).toEqual([]);
|
|
203
|
-
});
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
describe('hasSessionList', () => {
|
|
207
|
-
it('should return true when sessionList(s) returns a non-empty array', () => {
|
|
208
|
-
const s = {
|
|
209
|
-
sessions: {
|
|
210
|
-
'1': {},
|
|
211
|
-
},
|
|
212
|
-
} as unknown as SessionStore;
|
|
213
|
-
expect(hasSessionList(s)).toBe(true);
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
it('should return false when sessionList(s) returns an empty array', () => {
|
|
217
|
-
const s = {
|
|
218
|
-
sessions: {},
|
|
219
|
-
} as unknown as SessionStore;
|
|
220
|
-
expect(hasSessionList(s)).toBe(false);
|
|
72
|
+
expect(sessionSelectors.currentSessionSafe(s)).toEqual(s.sessions[0]);
|
|
221
73
|
});
|
|
222
74
|
});
|
|
223
75
|
|
|
224
76
|
describe('getSessionById', () => {
|
|
225
77
|
const s = {
|
|
226
78
|
activeId: '1',
|
|
227
|
-
sessions:
|
|
228
|
-
|
|
79
|
+
sessions: [
|
|
80
|
+
{
|
|
229
81
|
id: '1',
|
|
230
82
|
config: {
|
|
231
83
|
model: LanguageModel.GPT3_5,
|
|
@@ -234,7 +86,7 @@ describe('getSessionById', () => {
|
|
|
234
86
|
},
|
|
235
87
|
type: LobeSessionType.Agent,
|
|
236
88
|
} as LobeAgentSession,
|
|
237
|
-
|
|
89
|
+
{
|
|
238
90
|
id: '2',
|
|
239
91
|
config: {
|
|
240
92
|
model: LanguageModel.GPT3_5,
|
|
@@ -243,61 +95,31 @@ describe('getSessionById', () => {
|
|
|
243
95
|
},
|
|
244
96
|
type: LobeSessionType.Agent,
|
|
245
97
|
} as LobeAgentSession,
|
|
246
|
-
|
|
247
|
-
inbox: {
|
|
248
|
-
id: 'inbox',
|
|
249
|
-
config: {
|
|
250
|
-
model: LanguageModel.GPT3_5,
|
|
251
|
-
params: {},
|
|
252
|
-
systemRole: 'system-role',
|
|
253
|
-
},
|
|
254
|
-
type: LobeSessionType.Agent,
|
|
255
|
-
} as LobeAgentSession,
|
|
98
|
+
],
|
|
256
99
|
} as unknown as SessionStore;
|
|
257
100
|
|
|
258
|
-
it('should return s.inbox when id is equal to INBOX_SESSION_ID', () => {
|
|
259
|
-
expect(getSessionById('inbox')(s)).toEqual(s.inbox);
|
|
260
|
-
});
|
|
261
|
-
|
|
262
101
|
it('should return the session with the specified id when id is not equal to INBOX_SESSION_ID', () => {
|
|
263
|
-
expect(getSessionById('1')(s)).toEqual(s.sessions[
|
|
102
|
+
expect(sessionSelectors.getSessionById('1')(s)).toEqual(s.sessions[0]);
|
|
264
103
|
});
|
|
265
104
|
|
|
266
105
|
it('should return initLobeSession when the session with the specified id does not exist', () => {
|
|
267
|
-
expect(getSessionById('3')(s)).toEqual(initLobeSession);
|
|
106
|
+
expect(sessionSelectors.getSessionById('3')(s)).toEqual(initLobeSession);
|
|
268
107
|
});
|
|
269
108
|
});
|
|
270
109
|
|
|
271
110
|
describe('getSessionMetaById', () => {
|
|
272
111
|
const s: SessionStore = {
|
|
273
|
-
sessions:
|
|
274
|
-
'1': {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
},
|
|
278
|
-
},
|
|
279
|
-
'2': {
|
|
280
|
-
meta: {
|
|
281
|
-
title: 'Session 2',
|
|
282
|
-
},
|
|
283
|
-
},
|
|
284
|
-
},
|
|
285
|
-
inbox: {
|
|
286
|
-
meta: {
|
|
287
|
-
title: 'Inbox',
|
|
288
|
-
},
|
|
289
|
-
},
|
|
112
|
+
sessions: [
|
|
113
|
+
{ id: '1', meta: { title: 'Session 1' } },
|
|
114
|
+
{ id: '2', meta: { title: 'Session 2' } },
|
|
115
|
+
],
|
|
290
116
|
} as unknown as SessionStore;
|
|
291
117
|
|
|
292
118
|
it('should return the meta data of the session with the specified id', () => {
|
|
293
|
-
expect(getSessionMetaById('1')(s)).toEqual({ title: 'Session 1' });
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
it('should return the meta data of the inbox session when id is equal to INBOX_SESSION_ID', () => {
|
|
297
|
-
expect(getSessionMetaById('inbox')(s)).toEqual({ title: 'Inbox' });
|
|
119
|
+
expect(sessionSelectors.getSessionMetaById('1')(s)).toEqual({ title: 'Session 1' });
|
|
298
120
|
});
|
|
299
121
|
|
|
300
122
|
it('should return an empty object when the session with the specified id does not exist', () => {
|
|
301
|
-
expect(getSessionMetaById('3')(s)).toEqual({});
|
|
123
|
+
expect(sessionSelectors.getSessionMetaById('3')(s)).toEqual({});
|
|
302
124
|
});
|
|
303
125
|
});
|
|
@@ -1,68 +1,27 @@
|
|
|
1
1
|
import { INBOX_SESSION_ID } from '@/const/session';
|
|
2
|
+
import { sessionHelpers } from '@/store/session/slices/session/helpers';
|
|
2
3
|
import { MetaData } from '@/types/meta';
|
|
3
|
-
import { LobeAgentSession } from '@/types/session';
|
|
4
|
-
import { filterWithKeywords } from '@/utils/filter';
|
|
4
|
+
import { LobeAgentSession, LobeSessions, SessionGroupDefaultKeys } from '@/types/session';
|
|
5
5
|
|
|
6
6
|
import { SessionStore } from '../../../store';
|
|
7
7
|
import { initLobeSession } from '../initialState';
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
if (!s.activeId) return;
|
|
11
|
-
|
|
12
|
-
if (s.activeId === INBOX_SESSION_ID) return s.inbox;
|
|
9
|
+
const defaultSessions = (s: SessionStore): LobeSessions => s.sessions;
|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
};
|
|
11
|
+
const searchSessions = (s: SessionStore): LobeSessions => s.searchSessions;
|
|
16
12
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export const sessionList = (s: SessionStore) => {
|
|
22
|
-
const filterChats = filterWithKeywords(s.sessions, s.searchKeywords, (item) => [
|
|
23
|
-
Object.values(item.chats || {})
|
|
24
|
-
.map((c) => c.content)
|
|
25
|
-
.join(''),
|
|
26
|
-
]);
|
|
27
|
-
// 先按照 `pinned` 字段进行排序,置顶的会排在前面。然后,根据 `updateAt` 字段进行倒序排序。
|
|
28
|
-
return Object.values(filterChats).sort((a, b) => {
|
|
29
|
-
if (a.pinned && !b.pinned) {
|
|
30
|
-
return -1;
|
|
31
|
-
}
|
|
32
|
-
if (!a.pinned && b.pinned) {
|
|
33
|
-
return 1;
|
|
34
|
-
}
|
|
35
|
-
if (a.updateAt && b.updateAt) {
|
|
36
|
-
return b.updateAt - a.updateAt;
|
|
37
|
-
}
|
|
38
|
-
return 0;
|
|
39
|
-
});
|
|
40
|
-
};
|
|
13
|
+
const pinnedSessionList = (s: SessionStore) =>
|
|
14
|
+
defaultSessions(s).filter((s) => s.group === SessionGroupDefaultKeys.Pinned);
|
|
41
15
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
export const hasSessionList = (s: SessionStore) => {
|
|
46
|
-
const list = sessionList(s);
|
|
47
|
-
return list?.length > 0;
|
|
48
|
-
};
|
|
49
|
-
export const hasPinnedSessionList = (s: SessionStore) => {
|
|
50
|
-
const list = pinnedSessionList(s);
|
|
51
|
-
return list?.length > 0;
|
|
52
|
-
};
|
|
16
|
+
const unpinnedSessionList = (s: SessionStore) =>
|
|
17
|
+
defaultSessions(s).filter((s) => s.group === SessionGroupDefaultKeys.Default);
|
|
53
18
|
|
|
54
|
-
|
|
19
|
+
const getSessionById =
|
|
55
20
|
(id: string) =>
|
|
56
|
-
(s: SessionStore): LobeAgentSession =>
|
|
57
|
-
|
|
21
|
+
(s: SessionStore): LobeAgentSession =>
|
|
22
|
+
sessionHelpers.getSessionById(id, s.sessions);
|
|
58
23
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if (!session) return initLobeSession;
|
|
62
|
-
return session;
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
export const getSessionMetaById =
|
|
24
|
+
const getSessionMetaById =
|
|
66
25
|
(id: string) =>
|
|
67
26
|
(s: SessionStore): MetaData => {
|
|
68
27
|
const session = getSessionById(id)(s);
|
|
@@ -71,31 +30,34 @@ export const getSessionMetaById =
|
|
|
71
30
|
return session.meta;
|
|
72
31
|
};
|
|
73
32
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
//
|
|
84
|
-
// Object.values(s.agents).forEach((agent) => {
|
|
85
|
-
// const chats = Object.values(s.chats).filter((s) => s.agentId === agent.id);
|
|
86
|
-
//
|
|
87
|
-
// sessionTree.push({
|
|
88
|
-
// agentId: agent.id,
|
|
89
|
-
// chats: chats.map((c) => c.id),
|
|
90
|
-
// });
|
|
91
|
-
// });
|
|
92
|
-
//
|
|
93
|
-
// return sessionTree;
|
|
94
|
-
// };
|
|
33
|
+
const currentSession = (s: SessionStore): LobeAgentSession | undefined => {
|
|
34
|
+
if (!s.activeId) return;
|
|
35
|
+
|
|
36
|
+
return s.sessions.find((i) => i.id === s.activeId);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const currentSessionSafe = (s: SessionStore): LobeAgentSession => {
|
|
40
|
+
return currentSession(s) || initLobeSession;
|
|
41
|
+
};
|
|
95
42
|
|
|
96
|
-
|
|
97
|
-
const
|
|
98
|
-
|
|
43
|
+
const hasPinnedSessionList = (s: SessionStore) => {
|
|
44
|
+
const list = pinnedSessionList(s);
|
|
45
|
+
return list?.length > 0;
|
|
46
|
+
};
|
|
99
47
|
|
|
100
|
-
|
|
48
|
+
const hasCustomAgents = (s: SessionStore) => defaultSessions(s).length > 0;
|
|
49
|
+
|
|
50
|
+
const isInboxSession = (s: SessionStore) => s.activeId === INBOX_SESSION_ID;
|
|
51
|
+
|
|
52
|
+
export const sessionSelectors = {
|
|
53
|
+
currentSession,
|
|
54
|
+
currentSessionSafe,
|
|
55
|
+
getSessionById,
|
|
56
|
+
getSessionMetaById,
|
|
57
|
+
hasCustomAgents,
|
|
58
|
+
hasPinnedSessionList,
|
|
59
|
+
isInboxSession,
|
|
60
|
+
pinnedSessionList,
|
|
61
|
+
searchSessions,
|
|
62
|
+
unpinnedSessionList,
|
|
101
63
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PersistOptions, devtools, persist } from 'zustand/middleware';
|
|
1
|
+
import { PersistOptions, devtools, persist, subscribeWithSelector } from 'zustand/middleware';
|
|
2
2
|
import { shallow } from 'zustand/shallow';
|
|
3
3
|
import { createWithEqualityFn } from 'zustand/traditional';
|
|
4
4
|
import { StateCreator } from 'zustand/vanilla';
|
|
@@ -8,54 +8,48 @@ import { isDev } from '@/utils/env';
|
|
|
8
8
|
import { createHyperStorage } from '../middleware/createHyperStorage';
|
|
9
9
|
import { SessionStoreState, initialState } from './initialState';
|
|
10
10
|
import { AgentAction, createAgentSlice } from './slices/agent/action';
|
|
11
|
-
import { ChatAction, createChatSlice } from './slices/chat/actions';
|
|
12
11
|
import { SessionAction, createSessionSlice } from './slices/session/action';
|
|
13
12
|
|
|
14
13
|
// =============== 聚合 createStoreFn ============ //
|
|
15
14
|
|
|
16
|
-
export type SessionStore = SessionAction & AgentAction &
|
|
15
|
+
export type SessionStore = SessionAction & AgentAction & SessionStoreState;
|
|
17
16
|
const createStore: StateCreator<SessionStore, [['zustand/devtools', never]]> = (...parameters) => ({
|
|
18
17
|
...initialState,
|
|
19
18
|
...createAgentSlice(...parameters),
|
|
20
19
|
...createSessionSlice(...parameters),
|
|
21
|
-
...createChatSlice(...parameters),
|
|
22
20
|
});
|
|
23
21
|
|
|
24
22
|
// =============== persist 本地缓存中间件配置 ============ //
|
|
25
23
|
|
|
26
|
-
const LOBE_CHAT = 'LOBE_CHAT';
|
|
27
|
-
|
|
28
24
|
const persistOptions: PersistOptions<SessionStore> = {
|
|
29
|
-
name: LOBE_CHAT,
|
|
25
|
+
name: 'LOBE_CHAT',
|
|
30
26
|
|
|
31
27
|
// 手动控制 Hydration ,避免 ssr 报错
|
|
32
28
|
skipHydration: true,
|
|
33
29
|
|
|
34
30
|
storage: createHyperStorage({
|
|
35
|
-
localStorage:
|
|
36
|
-
dbName: 'LobeHub',
|
|
37
|
-
mode: 'indexedDB',
|
|
38
|
-
selectors: ['inbox', 'sessions'],
|
|
39
|
-
},
|
|
31
|
+
localStorage: false,
|
|
40
32
|
url: {
|
|
41
33
|
mode: 'hash',
|
|
42
34
|
selectors: [
|
|
43
35
|
// map state key to storage key
|
|
44
36
|
{ activeId: 'session' },
|
|
45
|
-
{ activeTopicId: 'topic' },
|
|
46
37
|
],
|
|
47
38
|
},
|
|
48
39
|
}),
|
|
49
|
-
|
|
40
|
+
|
|
41
|
+
version: 2,
|
|
50
42
|
};
|
|
51
43
|
|
|
52
44
|
// =============== 实装 useStore ============ //
|
|
53
45
|
|
|
54
46
|
export const useSessionStore = createWithEqualityFn<SessionStore>()(
|
|
55
47
|
persist(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
48
|
+
subscribeWithSelector(
|
|
49
|
+
devtools(createStore, {
|
|
50
|
+
name: 'LobeChat_Session' + (isDev ? '_DEV' : ''),
|
|
51
|
+
}),
|
|
52
|
+
),
|
|
59
53
|
persistOptions,
|
|
60
54
|
),
|
|
61
55
|
shallow,
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { FewShots, LLMParams, LanguageModel } from '@/types/llm';
|
|
2
|
+
|
|
3
|
+
export type TTSServer = 'openai' | 'edge' | 'microsoft';
|
|
4
|
+
|
|
5
|
+
export interface LobeAgentTTSConfig {
|
|
6
|
+
showAllLocaleVoice?: boolean;
|
|
7
|
+
sttLocale: 'auto' | string;
|
|
8
|
+
ttsService: TTSServer;
|
|
9
|
+
voice: {
|
|
10
|
+
edge?: string;
|
|
11
|
+
microsoft?: string;
|
|
12
|
+
openai: string;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export interface LobeAgentConfig {
|
|
16
|
+
autoCreateTopicThreshold: number;
|
|
17
|
+
compressThreshold?: number;
|
|
18
|
+
displayMode?: 'chat' | 'docs';
|
|
19
|
+
enableAutoCreateTopic: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* 历史消息长度压缩阈值
|
|
22
|
+
*/
|
|
23
|
+
enableCompressThreshold?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* 开启历史记录条数
|
|
26
|
+
*/
|
|
27
|
+
enableHistoryCount?: boolean;
|
|
28
|
+
enableMaxTokens?: boolean;
|
|
29
|
+
|
|
30
|
+
fewShots?: FewShots;
|
|
31
|
+
/**
|
|
32
|
+
* 历史消息条数
|
|
33
|
+
*/
|
|
34
|
+
historyCount?: number;
|
|
35
|
+
inputTemplate?: string;
|
|
36
|
+
/**
|
|
37
|
+
* 角色所使用的语言模型
|
|
38
|
+
* @default gpt-3.5-turbo
|
|
39
|
+
*/
|
|
40
|
+
model: LanguageModel | string;
|
|
41
|
+
/**
|
|
42
|
+
* 语言模型参数
|
|
43
|
+
*/
|
|
44
|
+
params: LLMParams;
|
|
45
|
+
/**
|
|
46
|
+
* 启用的插件
|
|
47
|
+
*/
|
|
48
|
+
plugins?: string[];
|
|
49
|
+
/**
|
|
50
|
+
* 系统角色
|
|
51
|
+
*/
|
|
52
|
+
systemRole: string;
|
|
53
|
+
/**
|
|
54
|
+
* 语音服务
|
|
55
|
+
*/
|
|
56
|
+
tts: LobeAgentTTSConfig;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export type LobeAgentConfigKeys =
|
|
60
|
+
| keyof LobeAgentConfig
|
|
61
|
+
| ['params', keyof LobeAgentConfig['params']];
|
package/src/types/chatMessage.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { PluginRequestPayload } from '@lobehub/chat-plugin-sdk';
|
|
2
|
-
|
|
3
1
|
import { ErrorType } from '@/types/fetch';
|
|
4
2
|
import { Translate } from '@/types/translate';
|
|
5
3
|
|
|
@@ -14,10 +12,6 @@ export interface ChatMessageError {
|
|
|
14
12
|
message: string;
|
|
15
13
|
type: ErrorType;
|
|
16
14
|
}
|
|
17
|
-
export interface OpenAIFunctionCall {
|
|
18
|
-
arguments?: string;
|
|
19
|
-
name: string;
|
|
20
|
-
}
|
|
21
15
|
|
|
22
16
|
export interface ChatTranslate extends Translate {
|
|
23
17
|
content?: string;
|
|
@@ -26,33 +20,29 @@ export interface ChatTranslate extends Translate {
|
|
|
26
20
|
export interface ChatTTS {
|
|
27
21
|
init?: boolean;
|
|
28
22
|
}
|
|
23
|
+
|
|
24
|
+
export interface ChatPluginPayload {
|
|
25
|
+
apiName: string;
|
|
26
|
+
arguments: string;
|
|
27
|
+
identifier: string;
|
|
28
|
+
type: 'standalone' | 'default';
|
|
29
|
+
}
|
|
30
|
+
|
|
29
31
|
export interface ChatMessage extends BaseDataModel {
|
|
30
|
-
/**
|
|
31
|
-
* @title 内容
|
|
32
|
-
* @description 消息内容
|
|
33
|
-
*/
|
|
34
32
|
content: string;
|
|
35
33
|
error?: any;
|
|
36
34
|
// 扩展字段
|
|
37
35
|
extra?: {
|
|
38
36
|
fromModel?: string;
|
|
39
37
|
// 翻译
|
|
40
|
-
translate?: ChatTranslate;
|
|
38
|
+
translate?: ChatTranslate | null;
|
|
41
39
|
// TTS
|
|
42
40
|
tts?: ChatTTS;
|
|
43
41
|
} & Record<string, any>;
|
|
44
42
|
|
|
45
43
|
files?: string[];
|
|
46
|
-
/**
|
|
47
|
-
* replace with plugin
|
|
48
|
-
* @deprecated
|
|
49
|
-
*/
|
|
50
|
-
function_call?: OpenAIFunctionCall;
|
|
51
|
-
|
|
52
|
-
name?: string;
|
|
53
|
-
|
|
54
44
|
parentId?: string;
|
|
55
|
-
plugin?:
|
|
45
|
+
plugin?: ChatPluginPayload;
|
|
56
46
|
|
|
57
47
|
pluginState?: any;
|
|
58
48
|
// 引用
|
|
@@ -62,6 +52,7 @@ export interface ChatMessage extends BaseDataModel {
|
|
|
62
52
|
* @description 消息发送者的角色
|
|
63
53
|
*/
|
|
64
54
|
role: LLMRoleType;
|
|
55
|
+
sessionId?: string;
|
|
65
56
|
/**
|
|
66
57
|
* 保存到主题的消息
|
|
67
58
|
*/
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ChatMessage } from '@/types/chatMessage';
|
|
2
|
+
import { LobeSessions } from '@/types/session';
|
|
2
3
|
import { GlobalSettings } from '@/types/settings';
|
|
4
|
+
import { ChatTopic } from '@/types/topic';
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
7
|
* 导出方式
|
|
@@ -40,15 +42,18 @@ export interface ConfigModelMap {
|
|
|
40
42
|
* 配置状态:会话
|
|
41
43
|
*/
|
|
42
44
|
export interface ConfigStateSessions {
|
|
43
|
-
|
|
45
|
+
messages: ChatMessage[];
|
|
44
46
|
sessions: LobeSessions;
|
|
47
|
+
topics: ChatTopic[];
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
/**
|
|
48
51
|
* 配置状态:单个会话
|
|
49
52
|
*/
|
|
50
53
|
export interface ConfigStateSingleSession {
|
|
54
|
+
messages: ChatMessage[];
|
|
51
55
|
sessions: LobeSessions;
|
|
56
|
+
topics: ChatTopic[];
|
|
52
57
|
}
|
|
53
58
|
|
|
54
59
|
/**
|
package/src/types/files.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DB_File } from '../database/schemas/files';
|
|
2
2
|
|
|
3
|
-
export interface FilePreview extends Pick<
|
|
3
|
+
export interface FilePreview extends Pick<DB_File, 'saveMode' | 'fileType'> {
|
|
4
4
|
base64Url?: string;
|
|
5
5
|
data?: ArrayBuffer;
|
|
6
6
|
name: string;
|