@lobehub/lobehub 2.0.0-next.35 → 2.0.0-next.36
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 +25 -0
- package/changelog/v1.json +9 -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/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/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
|
@@ -17,7 +17,7 @@ export const useSendThreadMessage = () => {
|
|
|
17
17
|
const canNotSend = useChatStore(threadSelectors.isSendButtonDisabledByMessage);
|
|
18
18
|
const generating = useChatStore((s) => threadSelectors.isThreadAIGenerating(s));
|
|
19
19
|
const stop = useChatStore((s) => s.stopGenerateMessage);
|
|
20
|
-
const [sendMessage,
|
|
20
|
+
const [sendMessage, updateMessageInput] = useChatStore((s) => [
|
|
21
21
|
s.sendThreadMessage,
|
|
22
22
|
s.updateThreadInputMessage,
|
|
23
23
|
]);
|
|
@@ -54,11 +54,11 @@ export const useSendThreadMessage = () => {
|
|
|
54
54
|
|
|
55
55
|
if (!shouldContinue) return;
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
updateMessageInput(inputMessage);
|
|
58
58
|
|
|
59
59
|
sendMessage({ message: inputMessage, ...params });
|
|
60
60
|
|
|
61
|
-
|
|
61
|
+
updateMessageInput('');
|
|
62
62
|
threadInputEditor.clearContent();
|
|
63
63
|
threadInputEditor.focus();
|
|
64
64
|
};
|
|
@@ -7,7 +7,7 @@ import { useClearCurrentMessages } from '@/features/ChatInput/ActionBar/Clear';
|
|
|
7
7
|
import { useOpenChatSettings } from '@/hooks/useInterceptingRoutes';
|
|
8
8
|
import { useActionSWR } from '@/libs/swr';
|
|
9
9
|
import { useChatStore } from '@/store/chat';
|
|
10
|
-
import {
|
|
10
|
+
import { displayMessageSelectors } from '@/store/chat/selectors';
|
|
11
11
|
import { useGlobalStore } from '@/store/global';
|
|
12
12
|
import { systemStatusSelectors } from '@/store/global/selectors';
|
|
13
13
|
import { HotkeyEnum, HotkeyScopeEnum } from '@/types/hotkey';
|
|
@@ -32,14 +32,22 @@ export const useOpenChatSettingsHotkey = () => {
|
|
|
32
32
|
};
|
|
33
33
|
|
|
34
34
|
export const useRegenerateMessageHotkey = () => {
|
|
35
|
-
const
|
|
36
|
-
|
|
35
|
+
const [regenerateUserMessage, regenerateAssistantMessage] = useChatStore((s) => [
|
|
36
|
+
s.regenerateUserMessage,
|
|
37
|
+
s.regenerateAssistantMessage,
|
|
38
|
+
]);
|
|
39
|
+
const lastMessage = useChatStore((s) => displayMessageSelectors.mainAIChats(s).at(-1), isEqual);
|
|
37
40
|
|
|
38
|
-
const disable = !lastMessage
|
|
41
|
+
const disable = !lastMessage;
|
|
39
42
|
|
|
40
43
|
return useHotkeyById(
|
|
41
44
|
HotkeyEnum.RegenerateMessage,
|
|
42
|
-
() =>
|
|
45
|
+
() => {
|
|
46
|
+
if (!lastMessage) return;
|
|
47
|
+
if (lastMessage.role === 'user') return regenerateUserMessage(lastMessage.id);
|
|
48
|
+
|
|
49
|
+
return regenerateAssistantMessage(lastMessage.id);
|
|
50
|
+
},
|
|
43
51
|
{
|
|
44
52
|
enableOnContentEditable: true,
|
|
45
53
|
enabled: !disable,
|
|
@@ -49,7 +57,7 @@ export const useRegenerateMessageHotkey = () => {
|
|
|
49
57
|
|
|
50
58
|
export const useDeleteAndRegenerateMessageHotkey = () => {
|
|
51
59
|
const delAndRegenerateMessage = useChatStore((s) => s.delAndRegenerateMessage);
|
|
52
|
-
const lastMessage = useChatStore(
|
|
60
|
+
const lastMessage = useChatStore((s) => displayMessageSelectors.mainAIChats(s).at(-1), isEqual);
|
|
53
61
|
|
|
54
62
|
const disable = !lastMessage || lastMessage.id === 'default' || lastMessage.role === 'system';
|
|
55
63
|
|
|
@@ -65,7 +73,7 @@ export const useDeleteAndRegenerateMessageHotkey = () => {
|
|
|
65
73
|
|
|
66
74
|
export const useDeleteLastMessageHotkey = () => {
|
|
67
75
|
const deleteMessage = useChatStore((s) => s.deleteMessage);
|
|
68
|
-
const lastMessage = useChatStore(
|
|
76
|
+
const lastMessage = useChatStore((s) => displayMessageSelectors.mainAIChats(s).at(-1), isEqual);
|
|
69
77
|
|
|
70
78
|
const disable = !lastMessage || lastMessage.id === 'default' || lastMessage.role === 'system';
|
|
71
79
|
|
|
@@ -358,32 +358,6 @@ describe('Message Router Integration Tests', () => {
|
|
|
358
358
|
expect(result).toHaveLength(1);
|
|
359
359
|
expect(result[0].id).toBe(msg1.id);
|
|
360
360
|
});
|
|
361
|
-
|
|
362
|
-
it('should support useGroup parameter', async () => {
|
|
363
|
-
const caller = messageRouter.createCaller(createTestContext(userId));
|
|
364
|
-
|
|
365
|
-
// 创建多个消息
|
|
366
|
-
await caller.createMessage({
|
|
367
|
-
content: 'Message 1',
|
|
368
|
-
role: 'assistant',
|
|
369
|
-
sessionId: testSessionId,
|
|
370
|
-
});
|
|
371
|
-
|
|
372
|
-
await caller.createMessage({
|
|
373
|
-
content: 'Message 2',
|
|
374
|
-
role: 'assistant',
|
|
375
|
-
sessionId: testSessionId,
|
|
376
|
-
});
|
|
377
|
-
|
|
378
|
-
// useGroup 参数应该影响消息分组展示
|
|
379
|
-
const result = await caller.getMessages({
|
|
380
|
-
sessionId: testSessionId,
|
|
381
|
-
useGroup: true,
|
|
382
|
-
});
|
|
383
|
-
|
|
384
|
-
expect(result).toBeDefined();
|
|
385
|
-
expect(Array.isArray(result)).toBe(true);
|
|
386
|
-
});
|
|
387
361
|
});
|
|
388
362
|
|
|
389
363
|
describe('removeMessages', () => {
|
|
@@ -96,6 +96,7 @@ export const aiChatRouter = router({
|
|
|
96
96
|
const userMessageItem = await ctx.messageModel.create({
|
|
97
97
|
content: input.newUserMessage.content,
|
|
98
98
|
files: input.newUserMessage.files,
|
|
99
|
+
parentId: input.newUserMessage.parentId,
|
|
99
100
|
role: 'user',
|
|
100
101
|
sessionId: input.sessionId!,
|
|
101
102
|
threadId: input.threadId,
|
|
@@ -113,9 +114,9 @@ export const aiChatRouter = router({
|
|
|
113
114
|
);
|
|
114
115
|
const assistantMessageItem = await ctx.messageModel.create({
|
|
115
116
|
content: LOADING_FLAT,
|
|
116
|
-
|
|
117
|
-
fromProvider: input.newAssistantMessage.provider,
|
|
117
|
+
model: input.newAssistantMessage.model,
|
|
118
118
|
parentId: messageId,
|
|
119
|
+
provider: input.newAssistantMessage.provider,
|
|
119
120
|
role: 'assistant',
|
|
120
121
|
sessionId: input.sessionId!,
|
|
121
122
|
threadId: input.threadId,
|
|
@@ -55,10 +55,9 @@ export const messageRouter = router({
|
|
|
55
55
|
}),
|
|
56
56
|
|
|
57
57
|
createMessage: messageProcedure
|
|
58
|
-
.input(CreateNewMessageParamsSchema
|
|
58
|
+
.input(CreateNewMessageParamsSchema)
|
|
59
59
|
.mutation(async ({ input, ctx }) => {
|
|
60
|
-
|
|
61
|
-
return ctx.messageService.createMessage(params as any, { useGroup });
|
|
60
|
+
return ctx.messageService.createMessage(input as any);
|
|
62
61
|
}),
|
|
63
62
|
|
|
64
63
|
getHeatmaps: messageProcedure.query(async ({ ctx }) => {
|
|
@@ -74,20 +73,17 @@ export const messageRouter = router({
|
|
|
74
73
|
pageSize: z.number().optional(),
|
|
75
74
|
sessionId: z.string().nullable().optional(),
|
|
76
75
|
topicId: z.string().nullable().optional(),
|
|
77
|
-
useGroup: z.boolean().optional(),
|
|
78
76
|
}),
|
|
79
77
|
)
|
|
80
78
|
.query(async ({ input, ctx }) => {
|
|
81
79
|
if (!ctx.userId) return [];
|
|
82
80
|
const serverDB = await getServerDB();
|
|
83
81
|
|
|
84
|
-
const { useGroup, ...queryParams } = input;
|
|
85
|
-
|
|
86
82
|
const messageModel = new MessageModel(serverDB, ctx.userId);
|
|
87
83
|
const fileService = new FileService(serverDB, ctx.userId);
|
|
88
84
|
|
|
89
|
-
return messageModel.query(
|
|
90
|
-
groupAssistantMessages:
|
|
85
|
+
return messageModel.query(input, {
|
|
86
|
+
groupAssistantMessages: false,
|
|
91
87
|
postProcessUrl: (path) => fileService.getFullFileUrl(path),
|
|
92
88
|
});
|
|
93
89
|
}),
|
|
@@ -106,7 +102,6 @@ export const messageRouter = router({
|
|
|
106
102
|
id: z.string(),
|
|
107
103
|
sessionId: z.string().nullable().optional(),
|
|
108
104
|
topicId: z.string().nullable().optional(),
|
|
109
|
-
useGroup: z.boolean().optional(),
|
|
110
105
|
}),
|
|
111
106
|
)
|
|
112
107
|
.mutation(async ({ input, ctx }) => {
|
|
@@ -126,7 +121,6 @@ export const messageRouter = router({
|
|
|
126
121
|
ids: z.array(z.string()),
|
|
127
122
|
sessionId: z.string().nullable().optional(),
|
|
128
123
|
topicId: z.string().nullable().optional(),
|
|
129
|
-
useGroup: z.boolean().optional(),
|
|
130
124
|
}),
|
|
131
125
|
)
|
|
132
126
|
.mutation(async ({ input, ctx }) => {
|
|
@@ -173,7 +167,6 @@ export const messageRouter = router({
|
|
|
173
167
|
id: z.string(),
|
|
174
168
|
sessionId: z.string().nullable().optional(),
|
|
175
169
|
topicId: z.string().nullable().optional(),
|
|
176
|
-
useGroup: z.boolean().optional(),
|
|
177
170
|
value: UpdateMessageParamsSchema,
|
|
178
171
|
}),
|
|
179
172
|
)
|
|
@@ -198,7 +191,6 @@ export const messageRouter = router({
|
|
|
198
191
|
UpdateMessageRAGParamsSchema.extend({
|
|
199
192
|
sessionId: z.string().nullable().optional(),
|
|
200
193
|
topicId: z.string().nullable().optional(),
|
|
201
|
-
useGroup: z.boolean().optional(),
|
|
202
194
|
}),
|
|
203
195
|
)
|
|
204
196
|
.mutation(async ({ input, ctx }) => {
|
|
@@ -210,11 +202,14 @@ export const messageRouter = router({
|
|
|
210
202
|
.input(
|
|
211
203
|
z.object({
|
|
212
204
|
id: z.string(),
|
|
205
|
+
sessionId: z.string().nullable().optional(),
|
|
206
|
+
topicId: z.string().nullable().optional(),
|
|
213
207
|
value: z.object({}).passthrough(),
|
|
214
208
|
}),
|
|
215
209
|
)
|
|
216
210
|
.mutation(async ({ input, ctx }) => {
|
|
217
|
-
|
|
211
|
+
const { id, value, ...options } = input;
|
|
212
|
+
return ctx.messageService.updateMetadata(id, value, options);
|
|
218
213
|
}),
|
|
219
214
|
|
|
220
215
|
updatePluginError: messageProcedure
|
|
@@ -223,7 +218,6 @@ export const messageRouter = router({
|
|
|
223
218
|
id: z.string(),
|
|
224
219
|
sessionId: z.string().nullable().optional(),
|
|
225
220
|
topicId: z.string().nullable().optional(),
|
|
226
|
-
useGroup: z.boolean().optional(),
|
|
227
221
|
value: z.object({}).passthrough().nullable(),
|
|
228
222
|
}),
|
|
229
223
|
)
|
|
@@ -238,7 +232,6 @@ export const messageRouter = router({
|
|
|
238
232
|
id: z.string(),
|
|
239
233
|
sessionId: z.string().nullable().optional(),
|
|
240
234
|
topicId: z.string().nullable().optional(),
|
|
241
|
-
useGroup: z.boolean().optional(),
|
|
242
235
|
value: z.object({}).passthrough(),
|
|
243
236
|
}),
|
|
244
237
|
)
|
|
@@ -267,7 +260,6 @@ export const messageRouter = router({
|
|
|
267
260
|
|
|
268
261
|
return ctx.messageModel.updateTTS(input.id, input.value);
|
|
269
262
|
}),
|
|
270
|
-
|
|
271
263
|
updateTranslate: messageProcedure
|
|
272
264
|
.input(
|
|
273
265
|
z.object({
|
|
@@ -26,6 +26,7 @@ describe('MessageService', () => {
|
|
|
26
26
|
update: vi.fn(),
|
|
27
27
|
updateMessagePlugin: vi.fn(),
|
|
28
28
|
updateMessageRAG: vi.fn(),
|
|
29
|
+
updateMetadata: vi.fn(),
|
|
29
30
|
updatePluginState: vi.fn(),
|
|
30
31
|
} as any;
|
|
31
32
|
|
|
@@ -222,36 +223,51 @@ describe('MessageService', () => {
|
|
|
222
223
|
});
|
|
223
224
|
});
|
|
224
225
|
|
|
225
|
-
describe('
|
|
226
|
-
it('should
|
|
226
|
+
describe('updateMetadata', () => {
|
|
227
|
+
it('should update metadata and return { success: true } when no sessionId/topicId provided', async () => {
|
|
228
|
+
const messageId = 'msg-1';
|
|
229
|
+
const metadata = { someKey: 'someValue', count: 42 };
|
|
230
|
+
|
|
231
|
+
const result = await messageService.updateMetadata(messageId, metadata);
|
|
232
|
+
|
|
233
|
+
expect(mockMessageModel.updateMetadata).toHaveBeenCalledWith(messageId, metadata);
|
|
234
|
+
expect(result).toEqual({ success: true });
|
|
235
|
+
expect(mockMessageModel.query).not.toHaveBeenCalled();
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it('should update metadata and return message list when sessionId provided', async () => {
|
|
239
|
+
const messageId = 'msg-1';
|
|
240
|
+
const metadata = { someKey: 'someValue', count: 42 };
|
|
227
241
|
const mockMessages = [{ id: 'msg-1', content: 'test' }];
|
|
228
242
|
vi.mocked(mockMessageModel.query).mockResolvedValue(mockMessages as any);
|
|
229
243
|
|
|
230
|
-
await messageService.
|
|
244
|
+
const result = await messageService.updateMetadata(messageId, metadata, {
|
|
231
245
|
sessionId: 'session-1',
|
|
232
|
-
useGroup: true,
|
|
233
246
|
});
|
|
234
247
|
|
|
235
|
-
expect(mockMessageModel.
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
groupAssistantMessages: true,
|
|
239
|
-
}),
|
|
240
|
-
);
|
|
248
|
+
expect(mockMessageModel.updateMetadata).toHaveBeenCalledWith(messageId, metadata);
|
|
249
|
+
expect(mockMessageModel.query).toHaveBeenCalled();
|
|
250
|
+
expect(result).toEqual({ messages: mockMessages, success: true });
|
|
241
251
|
});
|
|
242
252
|
|
|
243
|
-
it('should
|
|
253
|
+
it('should update metadata and return message list when topicId provided', async () => {
|
|
254
|
+
const messageId = 'msg-1';
|
|
255
|
+
const metadata = { key: 'value' };
|
|
244
256
|
const mockMessages = [{ id: 'msg-1', content: 'test' }];
|
|
245
257
|
vi.mocked(mockMessageModel.query).mockResolvedValue(mockMessages as any);
|
|
246
258
|
|
|
247
|
-
await messageService.
|
|
259
|
+
const result = await messageService.updateMetadata(messageId, metadata, {
|
|
260
|
+
topicId: 'topic-1',
|
|
261
|
+
});
|
|
248
262
|
|
|
263
|
+
expect(mockMessageModel.updateMetadata).toHaveBeenCalledWith(messageId, metadata);
|
|
249
264
|
expect(mockMessageModel.query).toHaveBeenCalledWith(
|
|
250
|
-
|
|
265
|
+
{ groupId: undefined, sessionId: undefined, topicId: 'topic-1' },
|
|
251
266
|
expect.objectContaining({
|
|
252
267
|
groupAssistantMessages: false,
|
|
253
268
|
}),
|
|
254
269
|
);
|
|
270
|
+
expect(result).toEqual({ messages: mockMessages, success: true });
|
|
255
271
|
});
|
|
256
272
|
});
|
|
257
273
|
|
|
@@ -289,32 +305,6 @@ describe('MessageService', () => {
|
|
|
289
305
|
});
|
|
290
306
|
});
|
|
291
307
|
|
|
292
|
-
it('should create message with useGroup option', async () => {
|
|
293
|
-
const params = {
|
|
294
|
-
content: 'Hello',
|
|
295
|
-
role: 'assistant' as const,
|
|
296
|
-
sessionId: 'session-1',
|
|
297
|
-
};
|
|
298
|
-
const createdMessage = { id: 'msg-1', ...params };
|
|
299
|
-
const mockMessages = [createdMessage];
|
|
300
|
-
|
|
301
|
-
vi.mocked(mockMessageModel.create).mockResolvedValue(createdMessage as any);
|
|
302
|
-
vi.mocked(mockMessageModel.query).mockResolvedValue(mockMessages as any);
|
|
303
|
-
|
|
304
|
-
const result = await messageService.createMessage(params as any, { useGroup: true });
|
|
305
|
-
|
|
306
|
-
expect(mockMessageModel.query).toHaveBeenCalledWith(
|
|
307
|
-
expect.anything(),
|
|
308
|
-
expect.objectContaining({
|
|
309
|
-
groupAssistantMessages: true,
|
|
310
|
-
}),
|
|
311
|
-
);
|
|
312
|
-
expect(result).toEqual({
|
|
313
|
-
id: 'msg-1',
|
|
314
|
-
messages: mockMessages,
|
|
315
|
-
});
|
|
316
|
-
});
|
|
317
|
-
|
|
318
308
|
it('should create message with topicId and groupId', async () => {
|
|
319
309
|
const params = {
|
|
320
310
|
content: 'Hello',
|
|
@@ -9,7 +9,6 @@ interface QueryOptions {
|
|
|
9
9
|
groupId?: string | null;
|
|
10
10
|
sessionId?: string | null;
|
|
11
11
|
topicId?: string | null;
|
|
12
|
-
useGroup?: boolean;
|
|
13
12
|
}
|
|
14
13
|
|
|
15
14
|
interface CreateMessageResult {
|
|
@@ -42,9 +41,9 @@ export class MessageService {
|
|
|
42
41
|
/**
|
|
43
42
|
* Unified query options
|
|
44
43
|
*/
|
|
45
|
-
private getQueryOptions(
|
|
44
|
+
private getQueryOptions() {
|
|
46
45
|
return {
|
|
47
|
-
groupAssistantMessages:
|
|
46
|
+
groupAssistantMessages: false,
|
|
48
47
|
postProcessUrl: this.postProcessUrl,
|
|
49
48
|
};
|
|
50
49
|
}
|
|
@@ -61,12 +60,45 @@ export class MessageService {
|
|
|
61
60
|
|
|
62
61
|
const messages = await this.messageModel.query(
|
|
63
62
|
{ groupId, sessionId, topicId },
|
|
64
|
-
this.getQueryOptions(
|
|
63
|
+
this.getQueryOptions(),
|
|
65
64
|
);
|
|
66
65
|
|
|
67
66
|
return { messages, success: true };
|
|
68
67
|
}
|
|
69
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Create a new message and return the complete message list
|
|
71
|
+
* Pattern: create + query
|
|
72
|
+
*
|
|
73
|
+
* This method combines message creation and querying into a single operation,
|
|
74
|
+
* reducing the need for separate refresh calls and improving performance.
|
|
75
|
+
*/
|
|
76
|
+
async createMessage(params: CreateMessageParams): Promise<CreateMessageResult> {
|
|
77
|
+
// 1. Create the message
|
|
78
|
+
const item = await this.messageModel.create(params);
|
|
79
|
+
|
|
80
|
+
// 2. Query all messages for this session/topic
|
|
81
|
+
const messages = await this.messageModel.query(
|
|
82
|
+
{
|
|
83
|
+
current: 0,
|
|
84
|
+
groupId: params.groupId,
|
|
85
|
+
pageSize: 9999,
|
|
86
|
+
sessionId: params.sessionId,
|
|
87
|
+
topicId: params.topicId,
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
groupAssistantMessages: false,
|
|
91
|
+
postProcessUrl: this.postProcessUrl,
|
|
92
|
+
},
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
// 3. Return the result
|
|
96
|
+
return {
|
|
97
|
+
id: item.id,
|
|
98
|
+
messages,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
70
102
|
/**
|
|
71
103
|
* Remove messages with optional message list return
|
|
72
104
|
* Pattern: delete + conditional query
|
|
@@ -122,38 +154,11 @@ export class MessageService {
|
|
|
122
154
|
}
|
|
123
155
|
|
|
124
156
|
/**
|
|
125
|
-
*
|
|
126
|
-
* Pattern:
|
|
127
|
-
*
|
|
128
|
-
* This method combines message creation and querying into a single operation,
|
|
129
|
-
* reducing the need for separate refresh calls and improving performance.
|
|
157
|
+
* Update message metadata with optional message list return
|
|
158
|
+
* Pattern: update + conditional query
|
|
130
159
|
*/
|
|
131
|
-
async
|
|
132
|
-
|
|
133
|
-
options
|
|
134
|
-
): Promise<CreateMessageResult> {
|
|
135
|
-
// 1. Create the message
|
|
136
|
-
const item = await this.messageModel.create(params);
|
|
137
|
-
|
|
138
|
-
// 2. Query all messages for this session/topic
|
|
139
|
-
const messages = await this.messageModel.query(
|
|
140
|
-
{
|
|
141
|
-
current: 0,
|
|
142
|
-
groupId: params.groupId,
|
|
143
|
-
pageSize: 9999,
|
|
144
|
-
sessionId: params.sessionId,
|
|
145
|
-
topicId: params.topicId,
|
|
146
|
-
},
|
|
147
|
-
{
|
|
148
|
-
groupAssistantMessages: options?.useGroup ?? false,
|
|
149
|
-
postProcessUrl: this.postProcessUrl,
|
|
150
|
-
},
|
|
151
|
-
);
|
|
152
|
-
|
|
153
|
-
// 3. Return the result
|
|
154
|
-
return {
|
|
155
|
-
id: item.id,
|
|
156
|
-
messages,
|
|
157
|
-
};
|
|
160
|
+
async updateMetadata(id: string, value: any, options?: QueryOptions) {
|
|
161
|
+
await this.messageModel.updateMetadata(id, value);
|
|
162
|
+
return this.queryWithSuccess(options);
|
|
158
163
|
}
|
|
159
164
|
}
|
|
@@ -5,13 +5,13 @@ import {
|
|
|
5
5
|
} from '@lobechat/electron-client-ipc';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* Desktop notification service
|
|
9
9
|
*/
|
|
10
10
|
export class DesktopNotificationService {
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
13
|
-
* @param params
|
|
14
|
-
* @returns
|
|
12
|
+
* Show desktop notification (only when window is hidden)
|
|
13
|
+
* @param params Notification parameters
|
|
14
|
+
* @returns Notification result
|
|
15
15
|
*/
|
|
16
16
|
async showNotification(
|
|
17
17
|
params: ShowDesktopNotificationParams,
|
|
@@ -20,8 +20,8 @@ export class DesktopNotificationService {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
|
-
*
|
|
24
|
-
* @returns
|
|
23
|
+
* Check if main window is hidden
|
|
24
|
+
* @returns Whether it is hidden
|
|
25
25
|
*/
|
|
26
26
|
async isMainWindowHidden(): Promise<boolean> {
|
|
27
27
|
return dispatch('isMainWindowHidden');
|
|
@@ -2,15 +2,15 @@ import { dispatch } from '@lobechat/electron-client-ipc';
|
|
|
2
2
|
import { FileMetadata } from '@lobechat/types';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* Desktop application file API client service
|
|
6
6
|
*/
|
|
7
7
|
class DesktopFileAPI {
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
10
|
-
* @param file
|
|
11
|
-
* @param hash
|
|
12
|
-
* @param path
|
|
13
|
-
* @returns
|
|
9
|
+
* Upload file to desktop application
|
|
10
|
+
* @param file File object
|
|
11
|
+
* @param hash File hash
|
|
12
|
+
* @param path File storage path
|
|
13
|
+
* @returns Upload result
|
|
14
14
|
*/
|
|
15
15
|
async uploadFile(
|
|
16
16
|
file: File,
|
|
@@ -13,9 +13,9 @@ export class BrowserS3Storage {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
17
|
-
* @param key
|
|
18
|
-
* @param file File
|
|
16
|
+
* Upload file
|
|
17
|
+
* @param key File hash
|
|
18
|
+
* @param file File object
|
|
19
19
|
*/
|
|
20
20
|
putObject = async (key: string, file: File): Promise<void> => {
|
|
21
21
|
try {
|
|
@@ -27,9 +27,9 @@ export class BrowserS3Storage {
|
|
|
27
27
|
};
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
|
-
*
|
|
31
|
-
* @param key
|
|
32
|
-
* @returns File
|
|
30
|
+
* Get file
|
|
31
|
+
* @param key File hash
|
|
32
|
+
* @returns File object
|
|
33
33
|
*/
|
|
34
34
|
getObject = async (key: string): Promise<File | undefined> => {
|
|
35
35
|
try {
|
|
@@ -44,8 +44,8 @@ export class BrowserS3Storage {
|
|
|
44
44
|
};
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
|
-
*
|
|
48
|
-
* @param key
|
|
47
|
+
* Delete file
|
|
48
|
+
* @param key File hash
|
|
49
49
|
*/
|
|
50
50
|
deleteObject = async (key: string): Promise<void> => {
|
|
51
51
|
try {
|