@lobehub/lobehub 2.0.0-next.35 → 2.0.0-next.37
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/changelog/v1.json +18 -0
- package/next.config.ts +5 -6
- package/package.json +2 -2
- package/packages/agent-runtime/src/core/__tests__/runtime.test.ts +112 -77
- package/packages/agent-runtime/src/core/runtime.ts +63 -18
- package/packages/agent-runtime/src/types/generalAgent.ts +55 -0
- package/packages/agent-runtime/src/types/index.ts +1 -0
- package/packages/agent-runtime/src/types/instruction.ts +10 -3
- package/packages/const/src/user.ts +0 -1
- package/packages/context-engine/src/processors/GroupMessageFlatten.ts +8 -6
- package/packages/context-engine/src/processors/__tests__/GroupMessageFlatten.test.ts +12 -12
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/branch/assistant-group-branches.json +249 -0
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/branch/index.ts +4 -0
- package/packages/conversation-flow/src/__tests__/fixtures/inputs/branch/multi-assistant-group.json +260 -0
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/active-index-1.json +4 -0
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/assistant-group-branches.json +481 -0
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/conversation.json +5 -1
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/index.ts +4 -0
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/multi-assistant-group.json +407 -0
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/branch/nested.json +18 -2
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/complex-scenario.json +25 -3
- package/packages/conversation-flow/src/__tests__/parse.test.ts +12 -0
- package/packages/conversation-flow/src/index.ts +1 -1
- package/packages/conversation-flow/src/transformation/FlatListBuilder.ts +112 -34
- package/packages/conversation-flow/src/types/flatMessageList.ts +0 -12
- package/packages/conversation-flow/src/{types.ts → types/index.ts} +3 -14
- package/packages/database/src/models/__tests__/apiKey.test.ts +444 -0
- package/packages/database/src/models/message.ts +18 -19
- package/packages/types/src/aiChat.ts +2 -0
- package/packages/types/src/importer.ts +2 -2
- package/packages/types/src/message/ui/chat.ts +17 -1
- package/packages/types/src/message/ui/extra.ts +2 -2
- package/packages/types/src/message/ui/params.ts +2 -2
- package/packages/types/src/user/preference.ts +0 -4
- package/packages/utils/src/tokenizer/index.ts +3 -11
- package/src/app/[variants]/(main)/chat/components/conversation/features/ChatInput/Desktop/MessageFromUrl.tsx +3 -3
- package/src/app/[variants]/(main)/chat/components/conversation/features/ChatInput/V1Mobile/index.tsx +1 -1
- package/src/app/[variants]/(main)/chat/components/conversation/features/ChatInput/V1Mobile/useSend.ts +3 -3
- package/src/app/[variants]/(main)/chat/components/conversation/features/ChatInput/useSend.ts +6 -6
- package/src/app/[variants]/(main)/chat/components/conversation/features/ChatList/Content.tsx +5 -3
- package/src/app/[variants]/(main)/chat/components/conversation/features/ChatList/WelcomeChatItem/AgentWelcome/OpeningQuestions.tsx +2 -2
- package/src/app/[variants]/(main)/chat/components/conversation/features/ChatList/WelcomeChatItem/GroupWelcome/GroupUsageSuggest.tsx +2 -2
- package/src/app/[variants]/(main)/labs/page.tsx +0 -9
- package/src/features/ChatInput/ActionBar/STT/browser.tsx +3 -3
- package/src/features/ChatInput/ActionBar/STT/openai.tsx +3 -3
- package/src/features/Conversation/Error/AccessCodeForm.tsx +1 -1
- package/src/features/Conversation/Error/ChatInvalidApiKey.tsx +1 -1
- package/src/features/Conversation/Error/ClerkLogin/index.tsx +1 -1
- package/src/features/Conversation/Error/OAuthForm.tsx +1 -1
- package/src/features/Conversation/Error/index.tsx +0 -5
- package/src/features/Conversation/Messages/Assistant/Actions/index.tsx +13 -10
- package/src/features/Conversation/Messages/Assistant/Extra/index.test.tsx +3 -8
- package/src/features/Conversation/Messages/Assistant/Extra/index.tsx +2 -6
- package/src/features/Conversation/Messages/Assistant/MessageContent.tsx +7 -9
- package/src/features/Conversation/Messages/Assistant/Tool/Inspector/PluginResult.tsx +2 -2
- package/src/features/Conversation/Messages/Assistant/Tool/Inspector/PluginState.tsx +2 -2
- package/src/features/Conversation/Messages/Assistant/Tool/Render/PluginSettings.tsx +4 -1
- package/src/features/Conversation/Messages/Assistant/Tool/Render/index.tsx +2 -3
- package/src/features/Conversation/Messages/Assistant/index.tsx +57 -60
- package/src/features/Conversation/Messages/Default.tsx +1 -0
- package/src/features/Conversation/Messages/Group/Actions/WithContentId.tsx +38 -10
- package/src/features/Conversation/Messages/Group/Actions/index.tsx +1 -1
- package/src/features/Conversation/Messages/Group/ContentBlock.tsx +1 -3
- package/src/features/Conversation/Messages/Group/GroupChildren.tsx +12 -12
- package/src/features/Conversation/Messages/Group/MessageContent.tsx +7 -1
- package/src/features/Conversation/Messages/Group/Tool/Render/PluginSettings.tsx +1 -1
- package/src/features/Conversation/Messages/Group/index.tsx +2 -1
- package/src/features/Conversation/Messages/Supervisor/index.tsx +2 -2
- package/src/features/Conversation/Messages/User/{Actions.tsx → Actions/ActionsBar.tsx} +26 -25
- package/src/features/Conversation/Messages/User/Actions/MessageBranch.tsx +107 -0
- package/src/features/Conversation/Messages/User/Actions/index.tsx +42 -0
- package/src/features/Conversation/Messages/User/index.tsx +43 -44
- package/src/features/Conversation/Messages/index.tsx +3 -3
- package/src/features/Conversation/components/AutoScroll.tsx +3 -3
- package/src/features/Conversation/components/Extras/Usage/UsageDetail/AnimatedNumber.tsx +55 -0
- package/src/features/Conversation/components/Extras/Usage/UsageDetail/index.tsx +5 -2
- package/src/features/Conversation/components/VirtualizedList/index.tsx +29 -20
- package/src/features/Conversation/hooks/useChatListActionsBar.tsx +8 -10
- package/src/features/Portal/Thread/Chat/ChatInput/useSend.ts +3 -3
- package/src/hooks/useHotkeys/chatScope.ts +15 -7
- package/src/libs/trpc/client/lambda.ts +4 -3
- package/src/server/routers/lambda/__tests__/aiChat.test.ts +1 -1
- package/src/server/routers/lambda/__tests__/integration/message.integration.test.ts +0 -26
- package/src/server/routers/lambda/aiChat.ts +3 -2
- package/src/server/routers/lambda/message.ts +8 -16
- package/src/server/services/message/__tests__/index.test.ts +29 -39
- package/src/server/services/message/index.ts +41 -36
- package/src/services/electron/desktopNotification.ts +6 -6
- package/src/services/electron/file.ts +6 -6
- package/src/services/file/ClientS3/index.ts +8 -8
- package/src/services/message/__tests__/metadata-race-condition.test.ts +157 -0
- package/src/services/message/index.ts +21 -15
- package/src/services/upload.ts +11 -11
- package/src/services/utils/abortableRequest.test.ts +161 -0
- package/src/services/utils/abortableRequest.ts +67 -0
- package/src/store/chat/agents/GeneralChatAgent.ts +137 -0
- package/src/store/chat/agents/createAgentExecutors.ts +395 -0
- package/src/store/chat/helpers.test.ts +0 -99
- package/src/store/chat/helpers.ts +0 -11
- package/src/store/chat/slices/aiChat/actions/__tests__/conversationControl.test.ts +332 -0
- package/src/store/chat/slices/aiChat/actions/__tests__/conversationLifecycle.test.ts +257 -0
- package/src/store/chat/slices/aiChat/actions/__tests__/helpers.ts +11 -2
- package/src/store/chat/slices/aiChat/actions/__tests__/rag.test.ts +6 -6
- package/src/store/chat/slices/aiChat/actions/__tests__/streamingExecutor.test.ts +391 -0
- package/src/store/chat/slices/aiChat/actions/__tests__/streamingStates.test.ts +179 -0
- package/src/store/chat/slices/aiChat/actions/conversationControl.ts +157 -0
- package/src/store/chat/slices/aiChat/actions/conversationLifecycle.ts +329 -0
- package/src/store/chat/slices/aiChat/actions/generateAIGroupChat.ts +14 -14
- package/src/store/chat/slices/aiChat/actions/index.ts +12 -6
- package/src/store/chat/slices/aiChat/actions/rag.ts +9 -6
- package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +604 -0
- package/src/store/chat/slices/aiChat/actions/streamingStates.ts +84 -0
- package/src/store/chat/slices/builtinTool/actions/__tests__/localSystem.test.ts +4 -4
- package/src/store/chat/slices/builtinTool/actions/__tests__/search.test.ts +11 -11
- package/src/store/chat/slices/builtinTool/actions/interpreter.ts +8 -8
- package/src/store/chat/slices/builtinTool/actions/localSystem.ts +2 -2
- package/src/store/chat/slices/builtinTool/actions/search.ts +8 -8
- package/src/store/chat/slices/message/action.test.ts +79 -68
- package/src/store/chat/slices/message/actions/index.ts +39 -0
- package/src/store/chat/slices/message/actions/internals.ts +77 -0
- package/src/store/chat/slices/message/actions/optimisticUpdate.ts +260 -0
- package/src/store/chat/slices/message/actions/publicApi.ts +224 -0
- package/src/store/chat/slices/message/actions/query.ts +120 -0
- package/src/store/chat/slices/message/actions/runtimeState.ts +108 -0
- package/src/store/chat/slices/message/initialState.ts +13 -0
- package/src/store/chat/slices/message/reducer.test.ts +48 -370
- package/src/store/chat/slices/message/reducer.ts +17 -81
- package/src/store/chat/slices/message/selectors/chat.test.ts +13 -50
- package/src/store/chat/slices/message/selectors/chat.ts +78 -242
- package/src/store/chat/slices/message/selectors/dbMessage.ts +140 -0
- package/src/store/chat/slices/message/selectors/displayMessage.ts +301 -0
- package/src/store/chat/slices/message/selectors/messageState.ts +5 -2
- package/src/store/chat/slices/plugin/action.test.ts +62 -64
- package/src/store/chat/slices/plugin/action.ts +34 -28
- package/src/store/chat/slices/thread/action.test.ts +28 -31
- package/src/store/chat/slices/thread/action.ts +13 -10
- package/src/store/chat/slices/thread/selectors/index.ts +8 -6
- package/src/store/chat/slices/topic/reducer.ts +11 -3
- package/src/store/chat/store.ts +1 -1
- package/src/store/user/slices/preference/selectors/labPrefer.ts +0 -3
- package/packages/database/src/models/__tests__/message.grouping.test.ts +0 -812
- package/packages/database/src/utils/__tests__/groupMessages.test.ts +0 -1132
- package/packages/database/src/utils/groupMessages.ts +0 -361
- package/packages/utils/src/tokenizer/client.ts +0 -35
- package/packages/utils/src/tokenizer/estimated.ts +0 -4
- package/packages/utils/src/tokenizer/server.ts +0 -11
- package/packages/utils/src/tokenizer/tokenizer.worker.ts +0 -12
- package/src/app/(backend)/webapi/tokenizer/index.test.ts +0 -32
- package/src/app/(backend)/webapi/tokenizer/route.ts +0 -8
- package/src/features/Conversation/Error/InvalidAccessCode.tsx +0 -79
- package/src/store/chat/slices/aiChat/actions/__tests__/generateAIChat.test.ts +0 -975
- package/src/store/chat/slices/aiChat/actions/__tests__/generateAIChatV2.test.ts +0 -1050
- package/src/store/chat/slices/aiChat/actions/generateAIChat.ts +0 -720
- package/src/store/chat/slices/aiChat/actions/generateAIChatV2.ts +0 -849
- package/src/store/chat/slices/message/action.ts +0 -629
|
@@ -154,36 +154,6 @@ describe('chatSelectors', () => {
|
|
|
154
154
|
});
|
|
155
155
|
});
|
|
156
156
|
|
|
157
|
-
describe('getMessageByToolCallId', () => {
|
|
158
|
-
it('should return undefined if the message with the given id does not exist', () => {
|
|
159
|
-
const message = chatSelectors.getMessageByToolCallId('non-existent-id')(initialStore);
|
|
160
|
-
expect(message).toBeUndefined();
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
it('should return the message object with the matching tool_call_id', () => {
|
|
164
|
-
const toolMessage = {
|
|
165
|
-
id: 'msg3',
|
|
166
|
-
content: 'Function Message',
|
|
167
|
-
role: 'tool',
|
|
168
|
-
tool_call_id: 'ttt',
|
|
169
|
-
plugin: {
|
|
170
|
-
arguments: 'arg1',
|
|
171
|
-
identifier: 'func1',
|
|
172
|
-
apiName: 'ttt',
|
|
173
|
-
type: 'default',
|
|
174
|
-
},
|
|
175
|
-
} as UIChatMessage;
|
|
176
|
-
const state = merge(initialStore, {
|
|
177
|
-
messagesMap: {
|
|
178
|
-
[messageMapKey('abc')]: [...mockMessages, toolMessage],
|
|
179
|
-
},
|
|
180
|
-
activeId: 'abc',
|
|
181
|
-
});
|
|
182
|
-
const message = chatSelectors.getMessageByToolCallId('ttt')(state);
|
|
183
|
-
expect(message).toMatchObject(toolMessage);
|
|
184
|
-
});
|
|
185
|
-
});
|
|
186
|
-
|
|
187
157
|
describe('currentChatsWithHistoryConfig', () => {
|
|
188
158
|
it('should slice the messages according to the current agent config', () => {
|
|
189
159
|
const state = merge(initialStore, {
|
|
@@ -255,19 +225,6 @@ describe('chatSelectors', () => {
|
|
|
255
225
|
});
|
|
256
226
|
});
|
|
257
227
|
|
|
258
|
-
describe('mainDisplayChats', () => {
|
|
259
|
-
it('should return existing messages except tool message', () => {
|
|
260
|
-
const state = merge(initialStore, {
|
|
261
|
-
messagesMap: {
|
|
262
|
-
[messageMapKey('someActiveId')]: mockMessages,
|
|
263
|
-
},
|
|
264
|
-
activeId: 'someActiveId',
|
|
265
|
-
});
|
|
266
|
-
const chats = chatSelectors.mainDisplayChats(state);
|
|
267
|
-
expect(chats).toEqual(mockedChats.slice(0, 2));
|
|
268
|
-
});
|
|
269
|
-
});
|
|
270
|
-
|
|
271
228
|
describe('chatsMessageString', () => {
|
|
272
229
|
it('should concatenate the contents of all messages returned by currentChatsWithHistoryConfig', () => {
|
|
273
230
|
// Prepare a state with a few messages
|
|
@@ -353,6 +310,9 @@ describe('chatSelectors', () => {
|
|
|
353
310
|
] as UIChatMessage[];
|
|
354
311
|
const state: Partial<ChatStore> = {
|
|
355
312
|
activeId: 'test-id',
|
|
313
|
+
dbMessagesMap: {
|
|
314
|
+
[messageMapKey('test-id')]: messages,
|
|
315
|
+
},
|
|
356
316
|
messagesMap: {
|
|
357
317
|
[messageMapKey('test-id')]: messages,
|
|
358
318
|
},
|
|
@@ -369,6 +329,9 @@ describe('chatSelectors', () => {
|
|
|
369
329
|
] as UIChatMessage[];
|
|
370
330
|
const state: Partial<ChatStore> = {
|
|
371
331
|
activeId: 'test-id',
|
|
332
|
+
dbMessagesMap: {
|
|
333
|
+
[messageMapKey('test-id')]: messages,
|
|
334
|
+
},
|
|
372
335
|
messagesMap: {
|
|
373
336
|
[messageMapKey('test-id')]: messages,
|
|
374
337
|
},
|
|
@@ -446,7 +409,7 @@ describe('chatSelectors', () => {
|
|
|
446
409
|
it('should return the last child without tools', () => {
|
|
447
410
|
const groupMessage = {
|
|
448
411
|
id: 'group-1',
|
|
449
|
-
role: '
|
|
412
|
+
role: 'assistantGroup',
|
|
450
413
|
content: '',
|
|
451
414
|
children: [
|
|
452
415
|
{
|
|
@@ -490,7 +453,7 @@ describe('chatSelectors', () => {
|
|
|
490
453
|
it('should return null if the last child has tools', () => {
|
|
491
454
|
const groupMessage = {
|
|
492
455
|
id: 'group-2',
|
|
493
|
-
role: '
|
|
456
|
+
role: 'assistantGroup',
|
|
494
457
|
content: '',
|
|
495
458
|
children: [
|
|
496
459
|
{
|
|
@@ -527,7 +490,7 @@ describe('chatSelectors', () => {
|
|
|
527
490
|
it('should return the last child when it has empty tools array', () => {
|
|
528
491
|
const groupMessage = {
|
|
529
492
|
id: 'group-3',
|
|
530
|
-
role: '
|
|
493
|
+
role: 'assistantGroup',
|
|
531
494
|
content: '',
|
|
532
495
|
children: [
|
|
533
496
|
{
|
|
@@ -585,7 +548,7 @@ describe('chatSelectors', () => {
|
|
|
585
548
|
it('should return null for group messages without children', () => {
|
|
586
549
|
const groupMessage = {
|
|
587
550
|
id: 'group-4',
|
|
588
|
-
role: '
|
|
551
|
+
role: 'assistantGroup',
|
|
589
552
|
content: '',
|
|
590
553
|
children: undefined,
|
|
591
554
|
} as UIChatMessage;
|
|
@@ -604,7 +567,7 @@ describe('chatSelectors', () => {
|
|
|
604
567
|
it('should return null for group messages with empty children array', () => {
|
|
605
568
|
const groupMessage = {
|
|
606
569
|
id: 'group-5',
|
|
607
|
-
role: '
|
|
570
|
+
role: 'assistantGroup',
|
|
608
571
|
content: '',
|
|
609
572
|
children: [],
|
|
610
573
|
} as unknown as UIChatMessage;
|
|
@@ -623,7 +586,7 @@ describe('chatSelectors', () => {
|
|
|
623
586
|
it('should return null if all children have tools', () => {
|
|
624
587
|
const groupMessage = {
|
|
625
588
|
id: 'group-6',
|
|
626
|
-
role: '
|
|
589
|
+
role: 'assistantGroup',
|
|
627
590
|
content: '',
|
|
628
591
|
children: [
|
|
629
592
|
{
|
|
@@ -669,7 +632,7 @@ describe('chatSelectors', () => {
|
|
|
669
632
|
it('should handle empty tools array as no tools', () => {
|
|
670
633
|
const groupMessage = {
|
|
671
634
|
id: 'group-7',
|
|
672
|
-
role: '
|
|
635
|
+
role: 'assistantGroup',
|
|
673
636
|
content: '',
|
|
674
637
|
children: [
|
|
675
638
|
{
|
|
@@ -1,272 +1,108 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Chat Selectors - Backward Compatibility Layer
|
|
3
|
+
*
|
|
4
|
+
* This file provides backward compatibility by re-exporting selectors from:
|
|
5
|
+
* - dbMessage.ts: Raw database message selectors (for data operations)
|
|
6
|
+
* - displayMessage.ts: Display message selectors (for UI rendering)
|
|
7
|
+
*
|
|
8
|
+
* MIGRATION GUIDE:
|
|
9
|
+
* ================
|
|
10
|
+
*
|
|
11
|
+
* For Data Operations (create, update, delete):
|
|
12
|
+
* ----------------------------------------------
|
|
13
|
+
* Use dbMessageSelectors from './dbMessage'
|
|
14
|
+
*
|
|
15
|
+
* Before: chatSelectors.getMessageById(id)(state)
|
|
16
|
+
* After: dbMessageSelectors.getDbMessageById(id)(state)
|
|
17
|
+
*
|
|
18
|
+
* Before: chatSelectors.latestMessage(state)
|
|
19
|
+
* After: dbMessageSelectors.latestDbMessage(state)
|
|
20
|
+
*
|
|
21
|
+
* Before: chatSelectors.currentToolMessages(state)
|
|
22
|
+
* After: dbMessageSelectors.dbToolMessages(state)
|
|
23
|
+
*
|
|
24
|
+
* For UI Rendering:
|
|
25
|
+
* -----------------
|
|
26
|
+
* Use displayMessageSelectors from './displayMessage'
|
|
27
|
+
*
|
|
28
|
+
* Before: chatSelectors.mainDisplayChats(state)
|
|
29
|
+
* After: displayMessageSelectors.mainDisplayChats(state)
|
|
30
|
+
*
|
|
31
|
+
* Before: chatSelectors.getMessageById(id)(state) // For display
|
|
32
|
+
* After: displayMessageSelectors.getDisplayMessageById(id)(state)
|
|
33
|
+
*/
|
|
34
|
+
import { ChatFileItem } from '@lobechat/types';
|
|
12
35
|
|
|
13
|
-
import { chatHelpers } from '../../../helpers';
|
|
14
36
|
import type { ChatStoreState } from '../../../initialState';
|
|
37
|
+
import { dbMessageSelectors } from './dbMessage';
|
|
38
|
+
import { displayMessageSelectors } from './displayMessage';
|
|
15
39
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return {
|
|
20
|
-
avatar: userProfileSelectors.userAvatar(useUserStore.getState()) || DEFAULT_USER_AVATAR,
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
case 'system': {
|
|
25
|
-
return message.meta;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
default: {
|
|
29
|
-
// For group chat, get meta from agent session
|
|
30
|
-
if (message.groupId && message.agentId) {
|
|
31
|
-
return sessionMetaSelectors.getAgentMetaByAgentId(message.agentId)(
|
|
32
|
-
useSessionStore.getState(),
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Otherwise, use the current session's agent meta for single agent chat
|
|
37
|
-
return sessionMetaSelectors.currentAgentMeta(useSessionStore.getState());
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const getBaseChatsByKey =
|
|
43
|
-
(key: string) =>
|
|
44
|
-
(s: ChatStoreState): UIChatMessage[] => {
|
|
45
|
-
const messages = s.messagesMap[key] || [];
|
|
40
|
+
// Re-export new selector groups
|
|
41
|
+
export { dbMessageSelectors } from './dbMessage';
|
|
42
|
+
export { displayMessageSelectors } from './displayMessage';
|
|
46
43
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
export const currentChatKey = (s: ChatStoreState) => messageMapKey(s.activeId, s.activeTopicId);
|
|
44
|
+
// ============= Backward Compatibility Exports ========== //
|
|
45
|
+
// These maintain the old API for gradual migration
|
|
46
|
+
// Prefer using dbMessageSelectors or displayMessageSelectors directly
|
|
51
47
|
|
|
52
48
|
/**
|
|
53
|
-
*
|
|
49
|
+
* @deprecated Use displayMessageSelectors.currentDisplayChatKey instead
|
|
54
50
|
*/
|
|
55
|
-
const
|
|
56
|
-
if (!s.activeId) return [];
|
|
57
|
-
|
|
58
|
-
return getBaseChatsByKey(currentChatKey(s))(s);
|
|
59
|
-
};
|
|
51
|
+
export const currentChatKey = displayMessageSelectors.currentDisplayChatKey;
|
|
60
52
|
|
|
61
53
|
/**
|
|
62
|
-
*
|
|
54
|
+
* @deprecated Use displayMessageSelectors.mainDisplayChatIDs instead
|
|
63
55
|
*/
|
|
64
|
-
const
|
|
65
|
-
const messages = activeBaseChats(s);
|
|
66
|
-
|
|
67
|
-
return messages.filter((m) => m.role !== 'tool');
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
const getChatsWithThread = (s: ChatStoreState, messages: UIChatMessage[]) => {
|
|
71
|
-
// 如果没有 activeThreadId,则返回所有的主消息
|
|
72
|
-
if (!s.activeThreadId) return messages.filter((m) => !m.threadId);
|
|
73
|
-
|
|
74
|
-
const thread = s.threadMaps[s.activeTopicId!]?.find((t) => t.id === s.activeThreadId);
|
|
75
|
-
|
|
76
|
-
if (!thread) return messages.filter((m) => !m.threadId);
|
|
77
|
-
|
|
78
|
-
const sourceIndex = messages.findIndex((m) => m.id === thread.sourceMessageId);
|
|
79
|
-
const sliced = messages.slice(0, sourceIndex + 1);
|
|
80
|
-
|
|
81
|
-
return [...sliced, ...messages.filter((m) => m.threadId === s.activeThreadId)];
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
// ============= Main Display Chats ========== //
|
|
85
|
-
// =========================================== //
|
|
86
|
-
const mainDisplayChats = (s: ChatStoreState): UIChatMessage[] => {
|
|
87
|
-
const displayChats = activeBaseChatsWithoutTool(s);
|
|
88
|
-
|
|
89
|
-
return getChatsWithThread(s, displayChats);
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
export const mainDisplayChatIDs = (s: ChatStoreState) => mainDisplayChats(s).map((s) => s.id);
|
|
93
|
-
|
|
94
|
-
const mainAIChats = (s: ChatStoreState): UIChatMessage[] => {
|
|
95
|
-
const messages = activeBaseChats(s);
|
|
96
|
-
|
|
97
|
-
return getChatsWithThread(s, messages);
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
const mainAIChatsWithHistoryConfig = (s: ChatStoreState): UIChatMessage[] => {
|
|
101
|
-
const chats = mainAIChats(s);
|
|
102
|
-
const enableHistoryCount = agentChatConfigSelectors.enableHistoryCount(useAgentStore.getState());
|
|
103
|
-
const historyCount = agentChatConfigSelectors.historyCount(useAgentStore.getState());
|
|
104
|
-
|
|
105
|
-
return chatHelpers.getSlicedMessages(chats, {
|
|
106
|
-
enableHistoryCount,
|
|
107
|
-
historyCount,
|
|
108
|
-
});
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
const mainAIChatsMessageString = (s: ChatStoreState): string => {
|
|
112
|
-
const chats = mainAIChatsWithHistoryConfig(s);
|
|
113
|
-
return chats.map((m) => m.content).join('');
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
const mainAILatestMessageReasoningContent = (s: ChatStoreState) =>
|
|
117
|
-
mainAIChats(s).at(-1)?.reasoning?.content;
|
|
56
|
+
export const mainDisplayChatIDs = displayMessageSelectors.mainDisplayChatIDs;
|
|
118
57
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
return messages.filter((m) => m.role === 'user');
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
const currentUserFiles = (s: ChatStoreState) => {
|
|
132
|
-
const userMessages = currentUserMessages(s);
|
|
133
|
-
|
|
134
|
-
return userMessages
|
|
135
|
-
.filter((m) => m.fileList && m.fileList?.length > 0)
|
|
136
|
-
.flatMap((m) => m.fileList)
|
|
137
|
-
.filter(Boolean) as ChatFileItem[];
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
const showInboxWelcome = (s: ChatStoreState): boolean => {
|
|
141
|
-
const isInbox = s.activeId === INBOX_SESSION_ID;
|
|
142
|
-
if (!isInbox) return false;
|
|
143
|
-
|
|
144
|
-
const data = activeBaseChats(s);
|
|
145
|
-
return data.length === 0;
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
const getMessageById = (id: string) => (s: ChatStoreState) =>
|
|
149
|
-
chatHelpers.getMessageById(activeBaseChats(s), id);
|
|
150
|
-
|
|
151
|
-
const countMessagesByThreadId = (id: string) => (s: ChatStoreState) => {
|
|
152
|
-
const messages = activeBaseChats(s).filter((m) => m.threadId === id);
|
|
153
|
-
|
|
154
|
-
return messages.length;
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
export const getMessageByToolCallId = (id: string) => (s: ChatStoreState) => {
|
|
158
|
-
const messages = activeBaseChats(s);
|
|
159
|
-
return messages.find((m) => m.tool_call_id === id);
|
|
160
|
-
};
|
|
161
|
-
const getTraceIdByMessageId = (id: string) => (s: ChatStoreState) => getMessageById(id)(s)?.traceId;
|
|
58
|
+
/**
|
|
59
|
+
* Legacy chatSelectors object for backward compatibility
|
|
60
|
+
* @deprecated Import dbMessageSelectors or displayMessageSelectors directly
|
|
61
|
+
*/
|
|
62
|
+
export const chatSelectors = {
|
|
63
|
+
// Display message selectors (from messagesMap)
|
|
64
|
+
activeBaseChats: displayMessageSelectors.activeDisplayMessages,
|
|
65
|
+
// DB message selectors (from dbMessagesMap)
|
|
66
|
+
countMessagesByThreadId: dbMessageSelectors.countDbMessagesByThreadId,
|
|
162
67
|
|
|
163
|
-
|
|
68
|
+
currentChatKey: displayMessageSelectors.currentDisplayChatKey,
|
|
164
69
|
|
|
165
|
-
|
|
70
|
+
currentChatLoadingState: displayMessageSelectors.currentChatLoadingState,
|
|
166
71
|
|
|
167
|
-
|
|
72
|
+
currentToolMessages: dbMessageSelectors.dbToolMessages,
|
|
168
73
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
return state.messagesMap[messageMapKey(INBOX_SESSION_ID, activeTopicId)] || [];
|
|
172
|
-
};
|
|
74
|
+
currentUserFiles: (s: ChatStoreState) =>
|
|
75
|
+
dbMessageSelectors.dbUserFiles(s) as unknown as ChatFileItem[],
|
|
173
76
|
|
|
174
|
-
|
|
175
|
-
* Gets messages between the current user and a specific agent (thread messages)
|
|
176
|
-
* This is like a DM (Direct Message) view between user and agent
|
|
177
|
-
*/
|
|
178
|
-
const getThreadMessages =
|
|
179
|
-
(agentId: string) =>
|
|
180
|
-
(s: ChatStoreState): UIChatMessage[] => {
|
|
181
|
-
if (!agentId) return [];
|
|
77
|
+
getBaseChatsByKey: displayMessageSelectors.getDisplayMessagesByKey,
|
|
182
78
|
|
|
183
|
-
|
|
79
|
+
getGroupLatestMessageWithoutTools: displayMessageSelectors.getGroupLatestMessageWithoutTools,
|
|
184
80
|
|
|
185
|
-
|
|
186
|
-
// 1. User messages sent TO the specific agent (role: 'user' && targetId matches agentId)
|
|
187
|
-
// 2. Assistant messages FROM the specific agent sent TO user (role: 'assistant' && agentId matches && targetId is 'user')
|
|
188
|
-
return allMessages.filter((message) => {
|
|
189
|
-
if (message.role === 'user' && message.targetId === agentId) {
|
|
190
|
-
return true; // Include user messages sent to the specific agent
|
|
191
|
-
}
|
|
81
|
+
getMessageById: displayMessageSelectors.getDisplayMessageById,
|
|
192
82
|
|
|
193
|
-
|
|
194
|
-
message.role === 'assistant' &&
|
|
195
|
-
message.agentId === agentId &&
|
|
196
|
-
message.targetId === 'user'
|
|
197
|
-
) {
|
|
198
|
-
return true; // Include messages from the specific agent sent to user
|
|
199
|
-
}
|
|
83
|
+
getSupervisorTodos: displayMessageSelectors.getSupervisorTodos,
|
|
200
84
|
|
|
201
|
-
|
|
202
|
-
});
|
|
203
|
-
};
|
|
85
|
+
getThreadMessageIDs: displayMessageSelectors.getThreadMessageIDs,
|
|
204
86
|
|
|
205
|
-
|
|
206
|
-
* Gets thread message IDs for a specific agent
|
|
207
|
-
*/
|
|
208
|
-
const getThreadMessageIDs =
|
|
209
|
-
(agentId: string) =>
|
|
210
|
-
(s: ChatStoreState): string[] => {
|
|
211
|
-
return getThreadMessages(agentId)(s).map((message) => message.id);
|
|
212
|
-
};
|
|
87
|
+
getThreadMessages: displayMessageSelectors.getThreadMessages,
|
|
213
88
|
|
|
214
|
-
|
|
215
|
-
s.supervisorDecisionLoading.includes(groupId);
|
|
89
|
+
getTraceIdByMessageId: dbMessageSelectors.getTraceIdByDbMessageId,
|
|
216
90
|
|
|
217
|
-
|
|
218
|
-
if (!groupId) return [];
|
|
219
|
-
return s.supervisorTodos[messageMapKey(groupId, topicId)] || [];
|
|
220
|
-
};
|
|
91
|
+
inboxActiveTopicMessages: displayMessageSelectors.inboxActiveTopicDisplayMessages,
|
|
221
92
|
|
|
222
|
-
|
|
223
|
-
* Gets the latest message block from a group message that doesn't contain tools
|
|
224
|
-
* Returns null if the last block contains tools or if message is not a group message
|
|
225
|
-
*/
|
|
226
|
-
const getGroupLatestMessageWithoutTools = (id: string) => (s: ChatStoreState) => {
|
|
227
|
-
const message = getMessageById(id)(s);
|
|
93
|
+
isCurrentChatLoaded: displayMessageSelectors.isCurrentDisplayChatLoaded,
|
|
228
94
|
|
|
229
|
-
|
|
230
|
-
return;
|
|
95
|
+
isSupervisorLoading: displayMessageSelectors.isSupervisorLoading,
|
|
231
96
|
|
|
232
|
-
|
|
233
|
-
const lastChild = message.children.at(-1);
|
|
97
|
+
latestMessage: dbMessageSelectors.latestDbMessage,
|
|
234
98
|
|
|
235
|
-
|
|
99
|
+
mainAIChats: displayMessageSelectors.mainAIChats,
|
|
236
100
|
|
|
237
|
-
|
|
238
|
-
if (!lastChild.tools || lastChild.tools.length === 0) {
|
|
239
|
-
return lastChild;
|
|
240
|
-
}
|
|
101
|
+
mainAIChatsMessageString: displayMessageSelectors.mainAIChatsMessageString,
|
|
241
102
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
activeBaseChatsWithoutTool,
|
|
248
|
-
countMessagesByThreadId,
|
|
249
|
-
currentChatKey,
|
|
250
|
-
currentChatLoadingState,
|
|
251
|
-
currentToolMessages,
|
|
252
|
-
currentUserFiles,
|
|
253
|
-
getBaseChatsByKey,
|
|
254
|
-
getGroupLatestMessageWithoutTools,
|
|
255
|
-
getMessageById,
|
|
256
|
-
getMessageByToolCallId,
|
|
257
|
-
getSupervisorTodos,
|
|
258
|
-
getThreadMessageIDs,
|
|
259
|
-
getThreadMessages,
|
|
260
|
-
getTraceIdByMessageId,
|
|
261
|
-
inboxActiveTopicMessages,
|
|
262
|
-
isCurrentChatLoaded,
|
|
263
|
-
isSupervisorLoading,
|
|
264
|
-
latestMessage,
|
|
265
|
-
mainAIChats,
|
|
266
|
-
mainAIChatsMessageString,
|
|
267
|
-
mainAIChatsWithHistoryConfig,
|
|
268
|
-
mainAILatestMessageReasoningContent,
|
|
269
|
-
mainDisplayChatIDs,
|
|
270
|
-
mainDisplayChats,
|
|
271
|
-
showInboxWelcome,
|
|
103
|
+
mainAIChatsWithHistoryConfig: displayMessageSelectors.mainAIChatsWithHistoryConfig,
|
|
104
|
+
mainAILatestMessageReasoningContent: displayMessageSelectors.mainAILatestMessageReasoningContent,
|
|
105
|
+
mainDisplayChatIDs: displayMessageSelectors.mainDisplayChatIDs,
|
|
106
|
+
mainDisplayChats: displayMessageSelectors.mainDisplayChats,
|
|
107
|
+
showInboxWelcome: displayMessageSelectors.showInboxWelcome,
|
|
272
108
|
};
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { UIChatMessage } from '@lobechat/types';
|
|
2
|
+
|
|
3
|
+
import { chatHelpers } from '../../../helpers';
|
|
4
|
+
import type { ChatStoreState } from '../../../initialState';
|
|
5
|
+
import { messageMapKey } from '../../../utils/messageMapKey';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* DB Message Selectors
|
|
9
|
+
*
|
|
10
|
+
* These selectors access raw messages from dbMessagesMap (database source).
|
|
11
|
+
* Use these selectors when you need to:
|
|
12
|
+
* - Operate on raw message data (create, update, delete)
|
|
13
|
+
* - Access original message structure before processing
|
|
14
|
+
* - Perform data mutations or service calls
|
|
15
|
+
*
|
|
16
|
+
* DO NOT use these for UI rendering - use displayMessage.ts selectors instead.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
// ============= Basic DB Message Access ========== //
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Get the current chat key for accessing dbMessagesMap
|
|
23
|
+
*/
|
|
24
|
+
export const currentDbChatKey = (s: ChatStoreState) => messageMapKey(s.activeId, s.activeTopicId);
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Get raw messages from database by key
|
|
28
|
+
*/
|
|
29
|
+
const getDbMessagesByKey =
|
|
30
|
+
(key: string) =>
|
|
31
|
+
(s: ChatStoreState): UIChatMessage[] => {
|
|
32
|
+
return s.dbMessagesMap[key] || [];
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Get current active session's raw messages from database
|
|
37
|
+
*/
|
|
38
|
+
const activeDbMessages = (s: ChatStoreState): UIChatMessage[] => {
|
|
39
|
+
if (!s.activeId) return [];
|
|
40
|
+
return getDbMessagesByKey(currentDbChatKey(s))(s);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// ============= DB Message Queries ========== //
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Get raw message by ID from database
|
|
47
|
+
* This searches in dbMessagesMap, which contains flat message structure
|
|
48
|
+
*/
|
|
49
|
+
const getDbMessageById = (id: string) => (s: ChatStoreState) =>
|
|
50
|
+
chatHelpers.getMessageById(activeDbMessages(s), id);
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Get raw message by tool_call_id from database
|
|
54
|
+
*/
|
|
55
|
+
export const getDbMessageByToolCallId = (id: string) => (s: ChatStoreState) => {
|
|
56
|
+
const messages = activeDbMessages(s);
|
|
57
|
+
return messages.find((m) => m.tool_call_id === id);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Get traceId from a message by ID
|
|
62
|
+
*/
|
|
63
|
+
const getTraceIdByDbMessageId = (id: string) => (s: ChatStoreState) =>
|
|
64
|
+
getDbMessageById(id)(s)?.traceId;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Get latest raw message from database
|
|
68
|
+
*/
|
|
69
|
+
const latestDbMessage = (s: ChatStoreState) => activeDbMessages(s).at(-1);
|
|
70
|
+
|
|
71
|
+
// ============= DB Message Filtering ========== //
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Get all tool messages from database
|
|
75
|
+
*/
|
|
76
|
+
const dbToolMessages = (s: ChatStoreState) => {
|
|
77
|
+
const messages = activeDbMessages(s);
|
|
78
|
+
return messages.filter((m) => m.role === 'tool');
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Get all user messages from database
|
|
83
|
+
*/
|
|
84
|
+
const dbUserMessages = (s: ChatStoreState) => {
|
|
85
|
+
const messages = activeDbMessages(s);
|
|
86
|
+
return messages.filter((m) => m.role === 'user');
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Get all file attachments from user messages
|
|
91
|
+
*/
|
|
92
|
+
const dbUserFiles = (s: ChatStoreState) => {
|
|
93
|
+
const userMessages = dbUserMessages(s);
|
|
94
|
+
return userMessages
|
|
95
|
+
.filter((m) => m.fileList && m.fileList.length > 0)
|
|
96
|
+
.flatMap((m) => m.fileList)
|
|
97
|
+
.filter(Boolean);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// ============= DB Message Counting ========== //
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Count messages in a specific thread
|
|
104
|
+
*/
|
|
105
|
+
const countDbMessagesByThreadId = (id: string) => (s: ChatStoreState) => {
|
|
106
|
+
const messages = activeDbMessages(s).filter((m) => m.threadId === id);
|
|
107
|
+
return messages.length;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// ============= DB Message Status ========== //
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Check if current chat is loaded in dbMessagesMap
|
|
114
|
+
*/
|
|
115
|
+
const isCurrentDbChatLoaded = (s: ChatStoreState) => !!s.dbMessagesMap[currentDbChatKey(s)];
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Get inbox active topic raw messages from database
|
|
119
|
+
*/
|
|
120
|
+
const inboxActiveTopicDbMessages = (state: ChatStoreState) => {
|
|
121
|
+
const activeTopicId = state.activeTopicId;
|
|
122
|
+
const key = messageMapKey('inbox', activeTopicId);
|
|
123
|
+
return state.dbMessagesMap[key] || [];
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export const dbMessageSelectors = {
|
|
127
|
+
activeDbMessages,
|
|
128
|
+
countDbMessagesByThreadId,
|
|
129
|
+
currentDbChatKey,
|
|
130
|
+
dbToolMessages,
|
|
131
|
+
dbUserFiles,
|
|
132
|
+
dbUserMessages,
|
|
133
|
+
getDbMessageById,
|
|
134
|
+
getDbMessageByToolCallId,
|
|
135
|
+
getDbMessagesByKey,
|
|
136
|
+
getTraceIdByDbMessageId,
|
|
137
|
+
inboxActiveTopicDbMessages,
|
|
138
|
+
isCurrentDbChatLoaded,
|
|
139
|
+
latestDbMessage,
|
|
140
|
+
};
|