@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
|
@@ -1,629 +0,0 @@
|
|
|
1
|
-
/* eslint-disable sort-keys-fix/sort-keys-fix, typescript-sort-keys/interface */
|
|
2
|
-
// Disable the auto sort key eslint rule to make the code more logic and readable
|
|
3
|
-
import {
|
|
4
|
-
ChatErrorType,
|
|
5
|
-
ChatImageItem,
|
|
6
|
-
ChatMessageError,
|
|
7
|
-
ChatMessagePluginError,
|
|
8
|
-
CreateMessageParams,
|
|
9
|
-
GroundingSearch,
|
|
10
|
-
MessageMetadata,
|
|
11
|
-
MessageToolCall,
|
|
12
|
-
ModelReasoning,
|
|
13
|
-
TraceEventPayloads,
|
|
14
|
-
TraceEventType,
|
|
15
|
-
UIChatMessage,
|
|
16
|
-
UpdateMessageRAGParams,
|
|
17
|
-
} from '@lobechat/types';
|
|
18
|
-
import { nanoid } from '@lobechat/utils';
|
|
19
|
-
import { copyToClipboard } from '@lobehub/ui';
|
|
20
|
-
import isEqual from 'fast-deep-equal';
|
|
21
|
-
import { SWRResponse, mutate } from 'swr';
|
|
22
|
-
import { StateCreator } from 'zustand/vanilla';
|
|
23
|
-
|
|
24
|
-
import { useClientDataSWR } from '@/libs/swr';
|
|
25
|
-
import { messageService } from '@/services/message';
|
|
26
|
-
import { topicService } from '@/services/topic';
|
|
27
|
-
import { traceService } from '@/services/trace';
|
|
28
|
-
import { ChatStore } from '@/store/chat/store';
|
|
29
|
-
import { messageMapKey } from '@/store/chat/utils/messageMapKey';
|
|
30
|
-
import { useSessionStore } from '@/store/session';
|
|
31
|
-
import { sessionSelectors } from '@/store/session/selectors';
|
|
32
|
-
import { Action, setNamespace } from '@/utils/storeDebug';
|
|
33
|
-
|
|
34
|
-
import type { ChatStoreState } from '../../initialState';
|
|
35
|
-
import { chatSelectors } from '../../selectors';
|
|
36
|
-
import { preventLeavingFn, toggleBooleanList } from '../../utils';
|
|
37
|
-
import { MessageDispatch, messagesReducer } from './reducer';
|
|
38
|
-
|
|
39
|
-
const n = setNamespace('m');
|
|
40
|
-
|
|
41
|
-
const SWR_USE_FETCH_MESSAGES = 'SWR_USE_FETCH_MESSAGES';
|
|
42
|
-
|
|
43
|
-
export interface ChatMessageAction {
|
|
44
|
-
// create
|
|
45
|
-
addAIMessage: () => Promise<void>;
|
|
46
|
-
addUserMessage: (params: { message: string; fileList?: string[] }) => Promise<void>;
|
|
47
|
-
// delete
|
|
48
|
-
/**
|
|
49
|
-
* clear message on the active session
|
|
50
|
-
*/
|
|
51
|
-
clearMessage: () => Promise<void>;
|
|
52
|
-
deleteMessage: (id: string) => Promise<void>;
|
|
53
|
-
deleteToolMessage: (id: string) => Promise<void>;
|
|
54
|
-
clearAllMessages: () => Promise<void>;
|
|
55
|
-
// update
|
|
56
|
-
updateInputMessage: (message: string) => void;
|
|
57
|
-
modifyMessageContent: (id: string, content: string) => Promise<void>;
|
|
58
|
-
toggleMessageEditing: (id: string, editing: boolean) => void;
|
|
59
|
-
// query
|
|
60
|
-
useFetchMessages: (
|
|
61
|
-
enable: boolean,
|
|
62
|
-
messageContextId: string,
|
|
63
|
-
activeTopicId?: string,
|
|
64
|
-
type?: 'session' | 'group',
|
|
65
|
-
) => SWRResponse<UIChatMessage[]>;
|
|
66
|
-
copyMessage: (id: string, content: string) => Promise<void>;
|
|
67
|
-
refreshMessages: () => Promise<void>;
|
|
68
|
-
replaceMessages: (messages: UIChatMessage[]) => void;
|
|
69
|
-
// ========= ↓ Internal Method ↓ ========== //
|
|
70
|
-
// ========================================== //
|
|
71
|
-
// ========================================== //
|
|
72
|
-
internal_updateMessageRAG: (id: string, input: UpdateMessageRAGParams) => Promise<void>;
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* update message at the frontend
|
|
76
|
-
* this method will not update messages to database
|
|
77
|
-
*/
|
|
78
|
-
internal_dispatchMessage: (
|
|
79
|
-
payload: MessageDispatch,
|
|
80
|
-
context?: { topicId?: string | null; sessionId: string },
|
|
81
|
-
) => void;
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* update the message content with optimistic update
|
|
85
|
-
* a method used by other action
|
|
86
|
-
*/
|
|
87
|
-
internal_updateMessageContent: (
|
|
88
|
-
id: string,
|
|
89
|
-
content: string,
|
|
90
|
-
extra?: {
|
|
91
|
-
toolCalls?: MessageToolCall[];
|
|
92
|
-
reasoning?: ModelReasoning;
|
|
93
|
-
search?: GroundingSearch;
|
|
94
|
-
metadata?: MessageMetadata;
|
|
95
|
-
imageList?: ChatImageItem[];
|
|
96
|
-
model?: string;
|
|
97
|
-
provider?: string;
|
|
98
|
-
},
|
|
99
|
-
) => Promise<void>;
|
|
100
|
-
/**
|
|
101
|
-
* update the message error with optimistic update
|
|
102
|
-
*/
|
|
103
|
-
internal_updateMessageError: (id: string, error: ChatMessageError | null) => Promise<void>;
|
|
104
|
-
internal_updateMessagePluginError: (
|
|
105
|
-
id: string,
|
|
106
|
-
error: ChatMessagePluginError | null,
|
|
107
|
-
) => Promise<void>;
|
|
108
|
-
/**
|
|
109
|
-
* create a message with optimistic update
|
|
110
|
-
* returns the created message ID and updated message list
|
|
111
|
-
*/
|
|
112
|
-
internal_createMessage: (
|
|
113
|
-
params: CreateMessageParams,
|
|
114
|
-
context?: { tempMessageId?: string; skipRefresh?: boolean; groupMessageId?: string },
|
|
115
|
-
) => Promise<{ id: string; messages: UIChatMessage[] } | undefined>;
|
|
116
|
-
/**
|
|
117
|
-
* create a temp message for optimistic update
|
|
118
|
-
* otherwise the message will be too slow to show
|
|
119
|
-
*/
|
|
120
|
-
internal_createTmpMessage: (params: CreateMessageParams) => string;
|
|
121
|
-
/**
|
|
122
|
-
* delete the message content with optimistic update
|
|
123
|
-
*/
|
|
124
|
-
internal_deleteMessage: (id: string) => Promise<void>;
|
|
125
|
-
|
|
126
|
-
internal_fetchMessages: () => Promise<void>;
|
|
127
|
-
internal_traceMessage: (id: string, payload: TraceEventPayloads) => Promise<void>;
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* method to toggle message create loading state
|
|
131
|
-
* the AI message status is creating -> generating
|
|
132
|
-
* other message role like user and tool , only this method need to be called
|
|
133
|
-
*/
|
|
134
|
-
internal_toggleMessageLoading: (loading: boolean, id: string) => void;
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* helper to toggle the loading state of the array,used by these three toggleXXXLoading
|
|
138
|
-
*/
|
|
139
|
-
internal_toggleLoadingArrays: (
|
|
140
|
-
key: keyof ChatStoreState,
|
|
141
|
-
loading: boolean,
|
|
142
|
-
id?: string,
|
|
143
|
-
action?: Action,
|
|
144
|
-
) => AbortController | undefined;
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Update active session type
|
|
148
|
-
*/
|
|
149
|
-
internal_updateActiveSessionType: (sessionType?: 'agent' | 'group') => void;
|
|
150
|
-
/**
|
|
151
|
-
* Update active session ID with cleanup of pending operations
|
|
152
|
-
*/
|
|
153
|
-
internal_updateActiveId: (activeId: string) => void;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
export const chatMessage: StateCreator<
|
|
157
|
-
ChatStore,
|
|
158
|
-
[['zustand/devtools', never]],
|
|
159
|
-
[],
|
|
160
|
-
ChatMessageAction
|
|
161
|
-
> = (set, get) => ({
|
|
162
|
-
deleteMessage: async (id) => {
|
|
163
|
-
const message = chatSelectors.getMessageById(id)(get());
|
|
164
|
-
if (!message) return;
|
|
165
|
-
|
|
166
|
-
let ids = [message.id];
|
|
167
|
-
const allMessages = chatSelectors.activeBaseChats(get());
|
|
168
|
-
|
|
169
|
-
// if the message is a tool calls, then delete all the related tool messages
|
|
170
|
-
if (message.tools) {
|
|
171
|
-
const toolMessageIds = message.tools.flatMap((tool) => {
|
|
172
|
-
const messages = allMessages.filter((m) => m.tool_call_id === tool.id);
|
|
173
|
-
return messages.map((m) => m.id);
|
|
174
|
-
});
|
|
175
|
-
ids = ids.concat(toolMessageIds);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// if the message is a group message, find all children messages (via parentId)
|
|
179
|
-
if (message.role === 'group') {
|
|
180
|
-
const childMessages = allMessages.filter((m) => m.parentId === message.id);
|
|
181
|
-
const childMessageIds = childMessages.map((m) => m.id);
|
|
182
|
-
ids = ids.concat(childMessageIds);
|
|
183
|
-
|
|
184
|
-
// Also delete tool results of children messages
|
|
185
|
-
const childToolMessageIds = childMessages.flatMap((child) => {
|
|
186
|
-
if (!child.tools) return [];
|
|
187
|
-
return child.tools.flatMap((tool) => {
|
|
188
|
-
const toolMessages = allMessages.filter((m) => m.tool_call_id === tool.id);
|
|
189
|
-
return toolMessages.map((m) => m.id);
|
|
190
|
-
});
|
|
191
|
-
});
|
|
192
|
-
ids = ids.concat(childToolMessageIds);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
get().internal_dispatchMessage({ type: 'deleteMessages', ids });
|
|
196
|
-
const result = await messageService.removeMessages(ids, {
|
|
197
|
-
sessionId: get().activeId,
|
|
198
|
-
topicId: get().activeTopicId,
|
|
199
|
-
});
|
|
200
|
-
if (result?.success && result.messages) {
|
|
201
|
-
get().replaceMessages(result.messages);
|
|
202
|
-
}
|
|
203
|
-
},
|
|
204
|
-
|
|
205
|
-
deleteToolMessage: async (id) => {
|
|
206
|
-
const message = chatSelectors.getMessageById(id)(get());
|
|
207
|
-
if (!message || message.role !== 'tool') return;
|
|
208
|
-
|
|
209
|
-
const removeToolInAssistantMessage = async () => {
|
|
210
|
-
if (!message.parentId) return;
|
|
211
|
-
await get().internal_removeToolToAssistantMessage(message.parentId, message.tool_call_id);
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
await Promise.all([
|
|
215
|
-
// 1. remove tool message
|
|
216
|
-
get().internal_deleteMessage(id),
|
|
217
|
-
// 2. remove the tool item in the assistant tools
|
|
218
|
-
removeToolInAssistantMessage(),
|
|
219
|
-
]);
|
|
220
|
-
},
|
|
221
|
-
|
|
222
|
-
clearMessage: async () => {
|
|
223
|
-
const { activeId, activeTopicId, refreshTopic, switchTopic, activeSessionType } = get();
|
|
224
|
-
|
|
225
|
-
// Check if this is a group session - use activeSessionType if available, otherwise check session store
|
|
226
|
-
let isGroupSession = activeSessionType === 'group';
|
|
227
|
-
if (activeSessionType === undefined) {
|
|
228
|
-
// Fallback: check session store directly
|
|
229
|
-
const sessionStore = useSessionStore.getState();
|
|
230
|
-
isGroupSession = sessionSelectors.isCurrentSessionGroupSession(sessionStore);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
// For group sessions, we need to clear group messages using groupId
|
|
234
|
-
// For regular sessions, we clear session messages using sessionId
|
|
235
|
-
if (isGroupSession) {
|
|
236
|
-
// For group chat, activeId is the groupId
|
|
237
|
-
await messageService.removeMessagesByGroup(activeId, activeTopicId);
|
|
238
|
-
} else {
|
|
239
|
-
// For regular session, activeId is the sessionId
|
|
240
|
-
await messageService.removeMessagesByAssistant(activeId, activeTopicId);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
if (activeTopicId) {
|
|
244
|
-
await topicService.removeTopic(activeTopicId);
|
|
245
|
-
}
|
|
246
|
-
await refreshTopic();
|
|
247
|
-
|
|
248
|
-
// Clear messages directly since all messages are deleted
|
|
249
|
-
get().replaceMessages([]);
|
|
250
|
-
|
|
251
|
-
// after remove topic , go back to default topic
|
|
252
|
-
switchTopic();
|
|
253
|
-
},
|
|
254
|
-
clearAllMessages: async () => {
|
|
255
|
-
await messageService.removeAllMessages();
|
|
256
|
-
// Clear messages directly since all messages are deleted
|
|
257
|
-
get().replaceMessages([]);
|
|
258
|
-
},
|
|
259
|
-
addAIMessage: async () => {
|
|
260
|
-
const { internal_createMessage, updateInputMessage, activeTopicId, activeId, inputMessage } =
|
|
261
|
-
get();
|
|
262
|
-
if (!activeId) return;
|
|
263
|
-
|
|
264
|
-
const result = await internal_createMessage({
|
|
265
|
-
content: inputMessage,
|
|
266
|
-
role: 'assistant',
|
|
267
|
-
sessionId: activeId,
|
|
268
|
-
// if there is activeTopicId,then add topicId to message
|
|
269
|
-
topicId: activeTopicId,
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
if (result) {
|
|
273
|
-
updateInputMessage('');
|
|
274
|
-
}
|
|
275
|
-
},
|
|
276
|
-
addUserMessage: async ({ message, fileList }) => {
|
|
277
|
-
const { internal_createMessage, updateInputMessage, activeTopicId, activeId, activeThreadId } =
|
|
278
|
-
get();
|
|
279
|
-
if (!activeId) return;
|
|
280
|
-
|
|
281
|
-
const result = await internal_createMessage({
|
|
282
|
-
content: message,
|
|
283
|
-
files: fileList,
|
|
284
|
-
role: 'user',
|
|
285
|
-
sessionId: activeId,
|
|
286
|
-
// if there is activeTopicId,then add topicId to message
|
|
287
|
-
topicId: activeTopicId,
|
|
288
|
-
threadId: activeThreadId,
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
if (result) {
|
|
292
|
-
updateInputMessage('');
|
|
293
|
-
}
|
|
294
|
-
},
|
|
295
|
-
copyMessage: async (id, content) => {
|
|
296
|
-
await copyToClipboard(content);
|
|
297
|
-
|
|
298
|
-
get().internal_traceMessage(id, { eventType: TraceEventType.CopyMessage });
|
|
299
|
-
},
|
|
300
|
-
toggleMessageEditing: (id, editing) => {
|
|
301
|
-
set(
|
|
302
|
-
{ messageEditingIds: toggleBooleanList(get().messageEditingIds, id, editing) },
|
|
303
|
-
false,
|
|
304
|
-
'toggleMessageEditing',
|
|
305
|
-
);
|
|
306
|
-
},
|
|
307
|
-
|
|
308
|
-
updateInputMessage: (message) => {
|
|
309
|
-
if (isEqual(message, get().inputMessage)) return;
|
|
310
|
-
|
|
311
|
-
set({ inputMessage: message }, false, n('updateInputMessage', message));
|
|
312
|
-
},
|
|
313
|
-
modifyMessageContent: async (id, content) => {
|
|
314
|
-
// tracing the diff of update
|
|
315
|
-
// due to message content will change, so we need send trace before update,or will get wrong data
|
|
316
|
-
get().internal_traceMessage(id, {
|
|
317
|
-
eventType: TraceEventType.ModifyMessage,
|
|
318
|
-
nextContent: content,
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
await get().internal_updateMessageContent(id, content);
|
|
322
|
-
},
|
|
323
|
-
|
|
324
|
-
/**
|
|
325
|
-
* @param enable - whether to enable the fetch
|
|
326
|
-
* @param messageContextId - Can be sessionId or groupId
|
|
327
|
-
*/
|
|
328
|
-
useFetchMessages: (enable, messageContextId, activeTopicId, type = 'session') =>
|
|
329
|
-
useClientDataSWR<UIChatMessage[]>(
|
|
330
|
-
enable ? [SWR_USE_FETCH_MESSAGES, messageContextId, activeTopicId, type] : null,
|
|
331
|
-
async ([, sessionId, topicId, type]: [string, string, string | undefined, string]) =>
|
|
332
|
-
type === 'session'
|
|
333
|
-
? messageService.getMessages(sessionId, topicId)
|
|
334
|
-
: messageService.getGroupMessages(sessionId, topicId),
|
|
335
|
-
{
|
|
336
|
-
onSuccess: (messages, key) => {
|
|
337
|
-
const nextMap = {
|
|
338
|
-
...get().messagesMap,
|
|
339
|
-
[messageMapKey(messageContextId || '', activeTopicId)]: messages,
|
|
340
|
-
};
|
|
341
|
-
|
|
342
|
-
// no need to update map if the messages have been init and the map is the same
|
|
343
|
-
if (get().messagesInit && isEqual(nextMap, get().messagesMap)) return;
|
|
344
|
-
|
|
345
|
-
set(
|
|
346
|
-
{ messagesInit: true, messagesMap: nextMap },
|
|
347
|
-
false,
|
|
348
|
-
n('useFetchMessages', { messages, queryKey: key }),
|
|
349
|
-
);
|
|
350
|
-
},
|
|
351
|
-
},
|
|
352
|
-
),
|
|
353
|
-
// TODO: The mutate should only be called once, but since we haven't merge session and group,
|
|
354
|
-
// we need to call it twice
|
|
355
|
-
refreshMessages: async () => {
|
|
356
|
-
await mutate([SWR_USE_FETCH_MESSAGES, get().activeId, get().activeTopicId, 'session']);
|
|
357
|
-
await mutate([SWR_USE_FETCH_MESSAGES, get().activeId, get().activeTopicId, 'group']);
|
|
358
|
-
},
|
|
359
|
-
replaceMessages: (messages) => {
|
|
360
|
-
set(
|
|
361
|
-
{
|
|
362
|
-
messagesMap: {
|
|
363
|
-
...get().messagesMap,
|
|
364
|
-
[messageMapKey(get().activeId, get().activeTopicId)]: messages,
|
|
365
|
-
},
|
|
366
|
-
},
|
|
367
|
-
false,
|
|
368
|
-
'replaceMessages',
|
|
369
|
-
);
|
|
370
|
-
},
|
|
371
|
-
|
|
372
|
-
internal_updateMessageRAG: async (id, data) => {
|
|
373
|
-
const result = await messageService.updateMessageRAG(id, data, {
|
|
374
|
-
sessionId: get().activeId,
|
|
375
|
-
topicId: get().activeTopicId,
|
|
376
|
-
});
|
|
377
|
-
if (result?.success && result.messages) {
|
|
378
|
-
get().replaceMessages(result.messages);
|
|
379
|
-
}
|
|
380
|
-
},
|
|
381
|
-
|
|
382
|
-
// the internal process method of the AI message
|
|
383
|
-
internal_dispatchMessage: (payload, context) => {
|
|
384
|
-
const activeId = typeof context !== 'undefined' ? context.sessionId : get().activeId;
|
|
385
|
-
const topicId = typeof context !== 'undefined' ? context.topicId : get().activeTopicId;
|
|
386
|
-
|
|
387
|
-
const messagesKey = messageMapKey(activeId, topicId);
|
|
388
|
-
|
|
389
|
-
const messages = messagesReducer(chatSelectors.getBaseChatsByKey(messagesKey)(get()), payload);
|
|
390
|
-
|
|
391
|
-
const nextMap = { ...get().messagesMap, [messagesKey]: messages };
|
|
392
|
-
|
|
393
|
-
if (isEqual(nextMap, get().messagesMap)) return;
|
|
394
|
-
|
|
395
|
-
set({ messagesMap: nextMap }, false, { type: `dispatchMessage/${payload.type}`, payload });
|
|
396
|
-
},
|
|
397
|
-
|
|
398
|
-
internal_updateMessageError: async (id, error) => {
|
|
399
|
-
get().internal_dispatchMessage({ id, type: 'updateMessage', value: { error } });
|
|
400
|
-
const result = await messageService.updateMessage(
|
|
401
|
-
id,
|
|
402
|
-
{ error },
|
|
403
|
-
{ topicId: get().activeTopicId, sessionId: get().activeId },
|
|
404
|
-
);
|
|
405
|
-
if (result?.success && result.messages) {
|
|
406
|
-
get().replaceMessages(result.messages);
|
|
407
|
-
} else {
|
|
408
|
-
await get().refreshMessages();
|
|
409
|
-
}
|
|
410
|
-
},
|
|
411
|
-
|
|
412
|
-
internal_updateMessagePluginError: async (id, error) => {
|
|
413
|
-
const result = await messageService.updateMessagePluginError(id, error, {
|
|
414
|
-
sessionId: get().activeId,
|
|
415
|
-
topicId: get().activeTopicId,
|
|
416
|
-
});
|
|
417
|
-
if (result?.success && result.messages) {
|
|
418
|
-
get().replaceMessages(result.messages);
|
|
419
|
-
}
|
|
420
|
-
},
|
|
421
|
-
|
|
422
|
-
internal_updateMessageContent: async (id, content, extra) => {
|
|
423
|
-
const {
|
|
424
|
-
internal_dispatchMessage,
|
|
425
|
-
refreshMessages,
|
|
426
|
-
internal_transformToolCalls,
|
|
427
|
-
replaceMessages,
|
|
428
|
-
} = get();
|
|
429
|
-
|
|
430
|
-
// Due to the async update method and refresh need about 100ms
|
|
431
|
-
// we need to update the message content at the frontend to avoid the update flick
|
|
432
|
-
// refs: https://medium.com/@kyledeguzmanx/what-are-optimistic-updates-483662c3e171
|
|
433
|
-
if (extra?.toolCalls) {
|
|
434
|
-
internal_dispatchMessage({
|
|
435
|
-
id,
|
|
436
|
-
type: 'updateMessage',
|
|
437
|
-
value: { tools: internal_transformToolCalls(extra?.toolCalls) },
|
|
438
|
-
});
|
|
439
|
-
} else {
|
|
440
|
-
internal_dispatchMessage({
|
|
441
|
-
id,
|
|
442
|
-
type: 'updateMessage',
|
|
443
|
-
value: { content },
|
|
444
|
-
});
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
const result = await messageService.updateMessage(
|
|
448
|
-
id,
|
|
449
|
-
{
|
|
450
|
-
content,
|
|
451
|
-
tools: extra?.toolCalls ? internal_transformToolCalls(extra?.toolCalls) : undefined,
|
|
452
|
-
reasoning: extra?.reasoning,
|
|
453
|
-
search: extra?.search,
|
|
454
|
-
metadata: extra?.metadata,
|
|
455
|
-
model: extra?.model,
|
|
456
|
-
provider: extra?.provider,
|
|
457
|
-
imageList: extra?.imageList,
|
|
458
|
-
},
|
|
459
|
-
{ topicId: get().activeTopicId, sessionId: get().activeId },
|
|
460
|
-
);
|
|
461
|
-
|
|
462
|
-
if (result && result.success && result.messages) {
|
|
463
|
-
replaceMessages(result.messages);
|
|
464
|
-
} else {
|
|
465
|
-
await refreshMessages();
|
|
466
|
-
}
|
|
467
|
-
},
|
|
468
|
-
|
|
469
|
-
internal_fetchMessages: async () => {
|
|
470
|
-
const messages = await messageService.getMessages(get().activeId, get().activeTopicId);
|
|
471
|
-
const nextMap = { ...get().messagesMap, [chatSelectors.currentChatKey(get())]: messages };
|
|
472
|
-
// no need to update map if the messages have been init and the map is the same
|
|
473
|
-
if (get().messagesInit && isEqual(nextMap, get().messagesMap)) return;
|
|
474
|
-
|
|
475
|
-
set(
|
|
476
|
-
{ messagesInit: true, messagesMap: nextMap },
|
|
477
|
-
false,
|
|
478
|
-
n('internal_fetchMessages', { messages }),
|
|
479
|
-
);
|
|
480
|
-
},
|
|
481
|
-
internal_createTmpMessage: (message) => {
|
|
482
|
-
const { internal_dispatchMessage } = get();
|
|
483
|
-
|
|
484
|
-
// use optimistic update to avoid the slow waiting
|
|
485
|
-
const tempId = 'tmp_' + nanoid();
|
|
486
|
-
internal_dispatchMessage({ type: 'createMessage', id: tempId, value: message });
|
|
487
|
-
|
|
488
|
-
return tempId;
|
|
489
|
-
},
|
|
490
|
-
internal_createMessage: async (message, context) => {
|
|
491
|
-
const {
|
|
492
|
-
internal_createTmpMessage,
|
|
493
|
-
internal_toggleMessageLoading,
|
|
494
|
-
internal_dispatchMessage,
|
|
495
|
-
replaceMessages,
|
|
496
|
-
} = get();
|
|
497
|
-
|
|
498
|
-
let tempId = context?.tempMessageId;
|
|
499
|
-
if (!tempId) {
|
|
500
|
-
tempId = 'tmp_' + nanoid();
|
|
501
|
-
|
|
502
|
-
// Check if should add as group block (explicitly controlled by caller)
|
|
503
|
-
if (context?.groupMessageId) {
|
|
504
|
-
internal_dispatchMessage({
|
|
505
|
-
type: 'addGroupBlock',
|
|
506
|
-
groupMessageId: context.groupMessageId,
|
|
507
|
-
blockId: tempId,
|
|
508
|
-
value: {
|
|
509
|
-
id: tempId,
|
|
510
|
-
content: message.content,
|
|
511
|
-
},
|
|
512
|
-
});
|
|
513
|
-
internal_toggleMessageLoading(true, tempId);
|
|
514
|
-
} else {
|
|
515
|
-
// Regular message creation at top level
|
|
516
|
-
tempId = internal_createTmpMessage(message as any);
|
|
517
|
-
internal_toggleMessageLoading(true, tempId);
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
try {
|
|
522
|
-
const result = await messageService.createMessage(message);
|
|
523
|
-
|
|
524
|
-
if (!context?.skipRefresh) {
|
|
525
|
-
// Use the messages returned from createMessage (already grouped)
|
|
526
|
-
replaceMessages(result.messages);
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
internal_toggleMessageLoading(false, tempId);
|
|
530
|
-
return result;
|
|
531
|
-
} catch (e) {
|
|
532
|
-
internal_toggleMessageLoading(false, tempId);
|
|
533
|
-
internal_dispatchMessage({
|
|
534
|
-
id: tempId,
|
|
535
|
-
type: 'updateMessage',
|
|
536
|
-
value: {
|
|
537
|
-
error: {
|
|
538
|
-
type: ChatErrorType.CreateMessageError,
|
|
539
|
-
message: (e as Error).message,
|
|
540
|
-
body: e,
|
|
541
|
-
},
|
|
542
|
-
},
|
|
543
|
-
});
|
|
544
|
-
}
|
|
545
|
-
},
|
|
546
|
-
|
|
547
|
-
internal_deleteMessage: async (id: string) => {
|
|
548
|
-
get().internal_dispatchMessage({ type: 'deleteMessage', id });
|
|
549
|
-
const result = await messageService.removeMessage(id, {
|
|
550
|
-
sessionId: get().activeId,
|
|
551
|
-
topicId: get().activeTopicId,
|
|
552
|
-
});
|
|
553
|
-
if (result?.success && result.messages) {
|
|
554
|
-
get().replaceMessages(result.messages);
|
|
555
|
-
}
|
|
556
|
-
},
|
|
557
|
-
internal_traceMessage: async (id, payload) => {
|
|
558
|
-
// tracing the diff of update
|
|
559
|
-
const message = chatSelectors.getMessageById(id)(get());
|
|
560
|
-
if (!message) return;
|
|
561
|
-
|
|
562
|
-
const traceId = message?.traceId;
|
|
563
|
-
const observationId = message?.observationId;
|
|
564
|
-
|
|
565
|
-
if (traceId && message?.role === 'assistant') {
|
|
566
|
-
traceService
|
|
567
|
-
.traceEvent({ traceId, observationId, content: message.content, ...payload })
|
|
568
|
-
.catch();
|
|
569
|
-
}
|
|
570
|
-
},
|
|
571
|
-
|
|
572
|
-
// ----- Loading ------- //
|
|
573
|
-
internal_toggleMessageLoading: (loading, id) => {
|
|
574
|
-
set(
|
|
575
|
-
{
|
|
576
|
-
messageLoadingIds: toggleBooleanList(get().messageLoadingIds, id, loading),
|
|
577
|
-
},
|
|
578
|
-
false,
|
|
579
|
-
`internal_toggleMessageLoading/${loading ? 'start' : 'end'}`,
|
|
580
|
-
);
|
|
581
|
-
},
|
|
582
|
-
internal_toggleLoadingArrays: (key, loading, id, action) => {
|
|
583
|
-
const abortControllerKey = `${key}AbortController`;
|
|
584
|
-
if (loading) {
|
|
585
|
-
window.addEventListener('beforeunload', preventLeavingFn);
|
|
586
|
-
|
|
587
|
-
const abortController = new AbortController();
|
|
588
|
-
set(
|
|
589
|
-
{
|
|
590
|
-
[abortControllerKey]: abortController,
|
|
591
|
-
[key]: toggleBooleanList(get()[key] as string[], id!, loading),
|
|
592
|
-
},
|
|
593
|
-
false,
|
|
594
|
-
action,
|
|
595
|
-
);
|
|
596
|
-
|
|
597
|
-
return abortController;
|
|
598
|
-
} else {
|
|
599
|
-
if (!id) {
|
|
600
|
-
set({ [abortControllerKey]: undefined, [key]: [] }, false, action);
|
|
601
|
-
} else
|
|
602
|
-
set(
|
|
603
|
-
{
|
|
604
|
-
[abortControllerKey]: undefined,
|
|
605
|
-
[key]: toggleBooleanList(get()[key] as string[], id, loading),
|
|
606
|
-
},
|
|
607
|
-
false,
|
|
608
|
-
action,
|
|
609
|
-
);
|
|
610
|
-
|
|
611
|
-
window.removeEventListener('beforeunload', preventLeavingFn);
|
|
612
|
-
}
|
|
613
|
-
},
|
|
614
|
-
internal_updateActiveSessionType: (sessionType?: 'agent' | 'group') => {
|
|
615
|
-
if (get().activeSessionType === sessionType) return;
|
|
616
|
-
|
|
617
|
-
set({ activeSessionType: sessionType }, false, n('updateActiveSessionType'));
|
|
618
|
-
},
|
|
619
|
-
|
|
620
|
-
internal_updateActiveId: (activeId: string) => {
|
|
621
|
-
const currentActiveId = get().activeId;
|
|
622
|
-
if (currentActiveId === activeId) return;
|
|
623
|
-
|
|
624
|
-
// Before switching sessions, cancel all pending supervisor decisions
|
|
625
|
-
get().internal_cancelAllSupervisorDecisions();
|
|
626
|
-
|
|
627
|
-
set({ activeId }, false, n(`updateActiveId/${activeId}`));
|
|
628
|
-
},
|
|
629
|
-
});
|