@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
|
@@ -15,6 +15,10 @@ export interface ChatMessageState {
|
|
|
15
15
|
* Derived from session.type, used for caching to avoid repeated lookups
|
|
16
16
|
*/
|
|
17
17
|
activeSessionType?: 'agent' | 'group';
|
|
18
|
+
/**
|
|
19
|
+
* Raw messages from database (flat structure)
|
|
20
|
+
*/
|
|
21
|
+
dbMessagesMap: Record<string, UIChatMessage[]>;
|
|
18
22
|
/**
|
|
19
23
|
* Group agents maps by group ID
|
|
20
24
|
*/
|
|
@@ -40,7 +44,14 @@ export interface ChatMessageState {
|
|
|
40
44
|
* whether messages have fetched
|
|
41
45
|
*/
|
|
42
46
|
messagesInit: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Parsed messages for display (includes assistantGroup from conversation-flow)
|
|
49
|
+
*/
|
|
43
50
|
messagesMap: Record<string, UIChatMessage[]>;
|
|
51
|
+
/**
|
|
52
|
+
* is the message is regenerating (used for disable regenerate button)
|
|
53
|
+
*/
|
|
54
|
+
regeneratingIds: string[];
|
|
44
55
|
/**
|
|
45
56
|
* Supervisor decision debounce timers by group ID
|
|
46
57
|
*/
|
|
@@ -62,6 +73,7 @@ export interface ChatMessageState {
|
|
|
62
73
|
export const initialMessageState: ChatMessageState = {
|
|
63
74
|
activeId: 'inbox',
|
|
64
75
|
activeSessionType: undefined,
|
|
76
|
+
dbMessagesMap: {},
|
|
65
77
|
groupAgentMaps: {},
|
|
66
78
|
groupMaps: {},
|
|
67
79
|
groupsInit: false,
|
|
@@ -70,6 +82,7 @@ export const initialMessageState: ChatMessageState = {
|
|
|
70
82
|
messageLoadingIds: [],
|
|
71
83
|
messagesInit: false,
|
|
72
84
|
messagesMap: {},
|
|
85
|
+
regeneratingIds: [],
|
|
73
86
|
supervisorDebounceTimers: {},
|
|
74
87
|
supervisorDecisionAbortControllers: {},
|
|
75
88
|
supervisorDecisionLoading: [],
|
|
@@ -56,133 +56,6 @@ describe('messagesReducer', () => {
|
|
|
56
56
|
|
|
57
57
|
expect(newState).toEqual(initialState);
|
|
58
58
|
});
|
|
59
|
-
|
|
60
|
-
it('should update a block in group message children when id matches a block', () => {
|
|
61
|
-
const stateWithGroup: UIChatMessage[] = [
|
|
62
|
-
...initialState,
|
|
63
|
-
{
|
|
64
|
-
id: 'group1',
|
|
65
|
-
role: 'group',
|
|
66
|
-
content: '',
|
|
67
|
-
createdAt: 1629264000000,
|
|
68
|
-
updatedAt: 1629264000000,
|
|
69
|
-
meta: {},
|
|
70
|
-
children: [
|
|
71
|
-
{
|
|
72
|
-
id: 'block1',
|
|
73
|
-
content: 'Original block content',
|
|
74
|
-
tools: [
|
|
75
|
-
{
|
|
76
|
-
id: 'tool1',
|
|
77
|
-
identifier: 'search',
|
|
78
|
-
apiName: 'search',
|
|
79
|
-
type: 'builtin',
|
|
80
|
-
arguments: '{"query": "test"}',
|
|
81
|
-
},
|
|
82
|
-
],
|
|
83
|
-
},
|
|
84
|
-
],
|
|
85
|
-
} as UIChatMessage,
|
|
86
|
-
];
|
|
87
|
-
|
|
88
|
-
const payload: MessageDispatch = {
|
|
89
|
-
type: 'updateMessage',
|
|
90
|
-
id: 'block1',
|
|
91
|
-
value: { content: 'Updated block content' },
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
const newState = messagesReducer(stateWithGroup, payload);
|
|
95
|
-
const groupMessage = newState.find((m) => m.id === 'group1');
|
|
96
|
-
const block = groupMessage?.children?.find((b) => b.id === 'block1');
|
|
97
|
-
|
|
98
|
-
expect(block?.content).toBe('Updated block content');
|
|
99
|
-
expect(groupMessage?.updatedAt).toBeGreaterThan(1629264000000);
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it('should update block tools in group message children', () => {
|
|
103
|
-
const stateWithGroup: UIChatMessage[] = [
|
|
104
|
-
...initialState,
|
|
105
|
-
{
|
|
106
|
-
id: 'group1',
|
|
107
|
-
role: 'group',
|
|
108
|
-
content: '',
|
|
109
|
-
createdAt: 1629264000000,
|
|
110
|
-
updatedAt: 1629264000000,
|
|
111
|
-
meta: {},
|
|
112
|
-
children: [
|
|
113
|
-
{
|
|
114
|
-
id: 'block1',
|
|
115
|
-
content: 'Block content',
|
|
116
|
-
tools: [
|
|
117
|
-
{
|
|
118
|
-
id: 'tool1',
|
|
119
|
-
identifier: 'search',
|
|
120
|
-
apiName: 'search',
|
|
121
|
-
type: 'builtin',
|
|
122
|
-
arguments: '{"query": "test"}',
|
|
123
|
-
},
|
|
124
|
-
],
|
|
125
|
-
},
|
|
126
|
-
],
|
|
127
|
-
} as UIChatMessage,
|
|
128
|
-
];
|
|
129
|
-
|
|
130
|
-
const newTools = [
|
|
131
|
-
{
|
|
132
|
-
id: 'tool1',
|
|
133
|
-
identifier: 'search',
|
|
134
|
-
apiName: 'search',
|
|
135
|
-
type: 'builtin',
|
|
136
|
-
arguments: '{"query": "updated"}',
|
|
137
|
-
result: {
|
|
138
|
-
id: 'result1',
|
|
139
|
-
content: 'Search result',
|
|
140
|
-
},
|
|
141
|
-
},
|
|
142
|
-
];
|
|
143
|
-
|
|
144
|
-
const payload: MessageDispatch = {
|
|
145
|
-
type: 'updateMessage',
|
|
146
|
-
id: 'block1',
|
|
147
|
-
value: { tools: newTools as any },
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
const newState = messagesReducer(stateWithGroup, payload);
|
|
151
|
-
const groupMessage = newState.find((m) => m.id === 'group1');
|
|
152
|
-
const block = groupMessage?.children?.find((b) => b.id === 'block1');
|
|
153
|
-
|
|
154
|
-
expect(block?.tools).toEqual(newTools);
|
|
155
|
-
expect(groupMessage?.updatedAt).toBeGreaterThan(1629264000000);
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
it('should not modify state when updating non-existent block in group message', () => {
|
|
159
|
-
const stateWithGroup: UIChatMessage[] = [
|
|
160
|
-
...initialState,
|
|
161
|
-
{
|
|
162
|
-
id: 'group1',
|
|
163
|
-
role: 'group',
|
|
164
|
-
content: '',
|
|
165
|
-
createdAt: 1629264000000,
|
|
166
|
-
updatedAt: 1629264000000,
|
|
167
|
-
meta: {},
|
|
168
|
-
children: [
|
|
169
|
-
{
|
|
170
|
-
id: 'block1',
|
|
171
|
-
content: 'Block content',
|
|
172
|
-
},
|
|
173
|
-
],
|
|
174
|
-
} as UIChatMessage,
|
|
175
|
-
];
|
|
176
|
-
|
|
177
|
-
const payload: MessageDispatch = {
|
|
178
|
-
type: 'updateMessage',
|
|
179
|
-
id: 'nonexistentBlock',
|
|
180
|
-
value: { content: 'Updated content' },
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
const newState = messagesReducer(stateWithGroup, payload);
|
|
184
|
-
expect(newState).toEqual(stateWithGroup);
|
|
185
|
-
});
|
|
186
59
|
});
|
|
187
60
|
|
|
188
61
|
describe('unimplemented type', () => {
|
|
@@ -254,6 +127,54 @@ describe('messagesReducer', () => {
|
|
|
254
127
|
});
|
|
255
128
|
});
|
|
256
129
|
|
|
130
|
+
describe('updateMessageMetadata', () => {
|
|
131
|
+
it('should merge update the metadata field of a message', () => {
|
|
132
|
+
const payload: MessageDispatch = {
|
|
133
|
+
type: 'updateMessageMetadata',
|
|
134
|
+
id: 'message1',
|
|
135
|
+
value: { activeBranchIndex: 1 },
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const newState = messagesReducer(initialState, payload);
|
|
139
|
+
const updatedMessage = newState.find((m) => m.id === 'message1');
|
|
140
|
+
|
|
141
|
+
expect(updatedMessage?.metadata).toEqual({ activeBranchIndex: 1 });
|
|
142
|
+
expect(updatedMessage?.updatedAt).toBeGreaterThan(initialState[0].updatedAt);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('should merge update the metadata field if metadata already exists', () => {
|
|
146
|
+
const state = [
|
|
147
|
+
{
|
|
148
|
+
...initialState[0],
|
|
149
|
+
metadata: { activeBranchIndex: 0 },
|
|
150
|
+
},
|
|
151
|
+
];
|
|
152
|
+
|
|
153
|
+
const payload: MessageDispatch = {
|
|
154
|
+
type: 'updateMessageMetadata',
|
|
155
|
+
id: 'message1',
|
|
156
|
+
value: { activeBranchIndex: 2 },
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const newState = messagesReducer(state, payload);
|
|
160
|
+
const updatedMessage = newState.find((m) => m.id === 'message1');
|
|
161
|
+
|
|
162
|
+
expect(updatedMessage?.metadata).toEqual({ activeBranchIndex: 2 });
|
|
163
|
+
expect(updatedMessage?.updatedAt).toBeGreaterThan(initialState[0].updatedAt);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('should not modify state if message is not found', () => {
|
|
167
|
+
const payload: MessageDispatch = {
|
|
168
|
+
type: 'updateMessageMetadata',
|
|
169
|
+
id: 'nonexistent',
|
|
170
|
+
value: { activeBranchIndex: 1 },
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
const newState = messagesReducer(initialState, payload);
|
|
174
|
+
expect(newState).toEqual(initialState);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
|
|
257
178
|
describe('updatePluginState', () => {
|
|
258
179
|
it('should update the plugin state of a message', () => {
|
|
259
180
|
const payload: MessageDispatch = {
|
|
@@ -617,247 +538,4 @@ describe('messagesReducer', () => {
|
|
|
617
538
|
expect(newState).toEqual(initialState);
|
|
618
539
|
});
|
|
619
540
|
});
|
|
620
|
-
|
|
621
|
-
describe('updateGroupBlockToolResult', () => {
|
|
622
|
-
it('should update a tool result in a group message block', () => {
|
|
623
|
-
const stateWithGroup: UIChatMessage[] = [
|
|
624
|
-
...initialState,
|
|
625
|
-
{
|
|
626
|
-
id: 'group1',
|
|
627
|
-
role: 'group',
|
|
628
|
-
content: '',
|
|
629
|
-
createdAt: 1629264000000,
|
|
630
|
-
updatedAt: 1629264000000,
|
|
631
|
-
meta: {},
|
|
632
|
-
children: [
|
|
633
|
-
{
|
|
634
|
-
id: 'block1',
|
|
635
|
-
content: 'Assistant response',
|
|
636
|
-
tools: [
|
|
637
|
-
{
|
|
638
|
-
id: 'tool1',
|
|
639
|
-
identifier: 'search',
|
|
640
|
-
apiName: 'search',
|
|
641
|
-
type: 'builtin',
|
|
642
|
-
arguments: '{"query": "test"}',
|
|
643
|
-
result: {
|
|
644
|
-
id: 'result1',
|
|
645
|
-
content: 'Initial result',
|
|
646
|
-
},
|
|
647
|
-
},
|
|
648
|
-
],
|
|
649
|
-
},
|
|
650
|
-
],
|
|
651
|
-
} as UIChatMessage,
|
|
652
|
-
];
|
|
653
|
-
|
|
654
|
-
const payload: MessageDispatch = {
|
|
655
|
-
type: 'updateGroupBlockToolResult',
|
|
656
|
-
groupMessageId: 'group1',
|
|
657
|
-
blockId: 'block1',
|
|
658
|
-
toolId: 'tool1',
|
|
659
|
-
toolResult: {
|
|
660
|
-
id: 'result1',
|
|
661
|
-
content: 'Updated result content',
|
|
662
|
-
state: { foo: 'bar' },
|
|
663
|
-
},
|
|
664
|
-
};
|
|
665
|
-
|
|
666
|
-
const newState = messagesReducer(stateWithGroup, payload);
|
|
667
|
-
const groupMessage = newState.find((m) => m.id === 'group1');
|
|
668
|
-
const block = groupMessage?.children?.find((b) => b.id === 'block1');
|
|
669
|
-
const tool = block?.tools?.find((t) => t.id === 'tool1');
|
|
670
|
-
|
|
671
|
-
expect(tool?.result).toEqual({
|
|
672
|
-
id: 'result1',
|
|
673
|
-
content: 'Updated result content',
|
|
674
|
-
state: { foo: 'bar' },
|
|
675
|
-
});
|
|
676
|
-
expect(groupMessage?.updatedAt).toBeGreaterThan(1629264000000);
|
|
677
|
-
});
|
|
678
|
-
|
|
679
|
-
it('should not modify state if group message is not found', () => {
|
|
680
|
-
const payload: MessageDispatch = {
|
|
681
|
-
type: 'updateGroupBlockToolResult',
|
|
682
|
-
groupMessageId: 'nonexistent',
|
|
683
|
-
blockId: 'block1',
|
|
684
|
-
toolId: 'tool1',
|
|
685
|
-
toolResult: {
|
|
686
|
-
id: 'result1',
|
|
687
|
-
content: 'Updated result',
|
|
688
|
-
},
|
|
689
|
-
};
|
|
690
|
-
|
|
691
|
-
const newState = messagesReducer(initialState, payload);
|
|
692
|
-
expect(newState).toEqual(initialState);
|
|
693
|
-
});
|
|
694
|
-
|
|
695
|
-
it('should not modify state if block is not found', () => {
|
|
696
|
-
const stateWithGroup: UIChatMessage[] = [
|
|
697
|
-
...initialState,
|
|
698
|
-
{
|
|
699
|
-
id: 'group1',
|
|
700
|
-
role: 'group',
|
|
701
|
-
content: '',
|
|
702
|
-
createdAt: 1629264000000,
|
|
703
|
-
updatedAt: 1629264000000,
|
|
704
|
-
meta: {},
|
|
705
|
-
children: [
|
|
706
|
-
{
|
|
707
|
-
id: 'block1',
|
|
708
|
-
content: 'Assistant response',
|
|
709
|
-
tools: [],
|
|
710
|
-
},
|
|
711
|
-
],
|
|
712
|
-
} as UIChatMessage,
|
|
713
|
-
];
|
|
714
|
-
|
|
715
|
-
const payload: MessageDispatch = {
|
|
716
|
-
type: 'updateGroupBlockToolResult',
|
|
717
|
-
groupMessageId: 'group1',
|
|
718
|
-
blockId: 'nonexistentBlock',
|
|
719
|
-
toolId: 'tool1',
|
|
720
|
-
toolResult: {
|
|
721
|
-
id: 'result1',
|
|
722
|
-
content: 'Updated result',
|
|
723
|
-
},
|
|
724
|
-
};
|
|
725
|
-
|
|
726
|
-
const newState = messagesReducer(stateWithGroup, payload);
|
|
727
|
-
expect(newState).toEqual(stateWithGroup);
|
|
728
|
-
});
|
|
729
|
-
|
|
730
|
-
it('should not modify state if tool is not found', () => {
|
|
731
|
-
const stateWithGroup: UIChatMessage[] = [
|
|
732
|
-
...initialState,
|
|
733
|
-
{
|
|
734
|
-
id: 'group1',
|
|
735
|
-
role: 'group',
|
|
736
|
-
content: '',
|
|
737
|
-
createdAt: 1629264000000,
|
|
738
|
-
updatedAt: 1629264000000,
|
|
739
|
-
meta: {},
|
|
740
|
-
children: [
|
|
741
|
-
{
|
|
742
|
-
id: 'block1',
|
|
743
|
-
content: 'Assistant response',
|
|
744
|
-
tools: [
|
|
745
|
-
{
|
|
746
|
-
id: 'tool1',
|
|
747
|
-
identifier: 'search',
|
|
748
|
-
apiName: 'search',
|
|
749
|
-
type: 'builtin',
|
|
750
|
-
arguments: '{"query": "test"}',
|
|
751
|
-
},
|
|
752
|
-
],
|
|
753
|
-
},
|
|
754
|
-
],
|
|
755
|
-
} as UIChatMessage,
|
|
756
|
-
];
|
|
757
|
-
|
|
758
|
-
const payload: MessageDispatch = {
|
|
759
|
-
type: 'updateGroupBlockToolResult',
|
|
760
|
-
groupMessageId: 'group1',
|
|
761
|
-
blockId: 'block1',
|
|
762
|
-
toolId: 'nonexistentTool',
|
|
763
|
-
toolResult: {
|
|
764
|
-
id: 'result1',
|
|
765
|
-
content: 'Updated result',
|
|
766
|
-
},
|
|
767
|
-
};
|
|
768
|
-
|
|
769
|
-
const newState = messagesReducer(stateWithGroup, payload);
|
|
770
|
-
expect(newState).toEqual(stateWithGroup);
|
|
771
|
-
});
|
|
772
|
-
});
|
|
773
|
-
|
|
774
|
-
describe('addGroupBlock', () => {
|
|
775
|
-
it('should add a new block to group message children', () => {
|
|
776
|
-
const stateWithGroup: UIChatMessage[] = [
|
|
777
|
-
...initialState,
|
|
778
|
-
{
|
|
779
|
-
id: 'group1',
|
|
780
|
-
role: 'group',
|
|
781
|
-
content: '',
|
|
782
|
-
createdAt: 1629264000000,
|
|
783
|
-
updatedAt: 1629264000000,
|
|
784
|
-
meta: {},
|
|
785
|
-
children: [
|
|
786
|
-
{
|
|
787
|
-
id: 'block1',
|
|
788
|
-
content: 'First block',
|
|
789
|
-
},
|
|
790
|
-
],
|
|
791
|
-
} as UIChatMessage,
|
|
792
|
-
];
|
|
793
|
-
|
|
794
|
-
const payload: MessageDispatch = {
|
|
795
|
-
type: 'addGroupBlock',
|
|
796
|
-
groupMessageId: 'group1',
|
|
797
|
-
blockId: 'block2',
|
|
798
|
-
value: {
|
|
799
|
-
id: 'block2',
|
|
800
|
-
content: 'Second block',
|
|
801
|
-
},
|
|
802
|
-
};
|
|
803
|
-
|
|
804
|
-
const newState = messagesReducer(stateWithGroup, payload);
|
|
805
|
-
const groupMessage = newState.find((m) => m.id === 'group1');
|
|
806
|
-
|
|
807
|
-
expect(groupMessage?.children).toHaveLength(2);
|
|
808
|
-
expect(groupMessage?.children?.[1]).toEqual({
|
|
809
|
-
id: 'block2',
|
|
810
|
-
content: 'Second block',
|
|
811
|
-
});
|
|
812
|
-
expect(groupMessage?.updatedAt).toBeGreaterThan(1629264000000);
|
|
813
|
-
});
|
|
814
|
-
|
|
815
|
-
it('should not modify state if group message is not found', () => {
|
|
816
|
-
const stateWithGroup: UIChatMessage[] = [
|
|
817
|
-
...initialState,
|
|
818
|
-
{
|
|
819
|
-
id: 'group1',
|
|
820
|
-
role: 'group',
|
|
821
|
-
content: '',
|
|
822
|
-
createdAt: 1629264000000,
|
|
823
|
-
updatedAt: 1629264000000,
|
|
824
|
-
meta: {},
|
|
825
|
-
children: [
|
|
826
|
-
{
|
|
827
|
-
id: 'block1',
|
|
828
|
-
content: 'First block',
|
|
829
|
-
},
|
|
830
|
-
],
|
|
831
|
-
} as UIChatMessage,
|
|
832
|
-
];
|
|
833
|
-
|
|
834
|
-
const payload: MessageDispatch = {
|
|
835
|
-
type: 'addGroupBlock',
|
|
836
|
-
groupMessageId: 'nonexistentGroup',
|
|
837
|
-
blockId: 'block2',
|
|
838
|
-
value: {
|
|
839
|
-
id: 'block2',
|
|
840
|
-
content: 'Second block',
|
|
841
|
-
},
|
|
842
|
-
};
|
|
843
|
-
|
|
844
|
-
const newState = messagesReducer(stateWithGroup, payload);
|
|
845
|
-
expect(newState).toEqual(stateWithGroup);
|
|
846
|
-
});
|
|
847
|
-
|
|
848
|
-
it('should not modify state if message is not a group message', () => {
|
|
849
|
-
const payload: MessageDispatch = {
|
|
850
|
-
type: 'addGroupBlock',
|
|
851
|
-
groupMessageId: 'message1',
|
|
852
|
-
blockId: 'block2',
|
|
853
|
-
value: {
|
|
854
|
-
id: 'block2',
|
|
855
|
-
content: 'Second block',
|
|
856
|
-
},
|
|
857
|
-
};
|
|
858
|
-
|
|
859
|
-
const newState = messagesReducer(initialState, payload);
|
|
860
|
-
expect(newState).toEqual(initialState);
|
|
861
|
-
});
|
|
862
|
-
});
|
|
863
541
|
});
|
|
@@ -75,27 +75,10 @@ interface UpdateMessageExtra {
|
|
|
75
75
|
value: any;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
interface
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
toolResult: {
|
|
83
|
-
content: string;
|
|
84
|
-
error?: any;
|
|
85
|
-
id: string;
|
|
86
|
-
state?: any;
|
|
87
|
-
};
|
|
88
|
-
type: 'updateGroupBlockToolResult';
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
interface AddGroupBlock {
|
|
92
|
-
blockId: string;
|
|
93
|
-
groupMessageId: string;
|
|
94
|
-
type: 'addGroupBlock';
|
|
95
|
-
value: {
|
|
96
|
-
content: string;
|
|
97
|
-
id: string;
|
|
98
|
-
};
|
|
78
|
+
interface UpdateMessageMetadata {
|
|
79
|
+
id: string;
|
|
80
|
+
type: 'updateMessageMetadata';
|
|
81
|
+
value: Partial<UIChatMessage['metadata']>;
|
|
99
82
|
}
|
|
100
83
|
|
|
101
84
|
export type MessageDispatch =
|
|
@@ -104,14 +87,13 @@ export type MessageDispatch =
|
|
|
104
87
|
| UpdateMessages
|
|
105
88
|
| UpdatePluginState
|
|
106
89
|
| UpdateMessageExtra
|
|
90
|
+
| UpdateMessageMetadata
|
|
107
91
|
| DeleteMessage
|
|
108
92
|
| UpdateMessagePlugin
|
|
109
93
|
| UpdateMessageTools
|
|
110
94
|
| AddMessageTool
|
|
111
95
|
| DeleteMessageTool
|
|
112
|
-
| DeleteMessages
|
|
113
|
-
| UpdateGroupBlockToolResult
|
|
114
|
-
| AddGroupBlock;
|
|
96
|
+
| DeleteMessages;
|
|
115
97
|
|
|
116
98
|
export const messagesReducer = (
|
|
117
99
|
state: UIChatMessage[],
|
|
@@ -122,25 +104,9 @@ export const messagesReducer = (
|
|
|
122
104
|
return produce(state, (draftState) => {
|
|
123
105
|
const { id, value } = payload;
|
|
124
106
|
|
|
125
|
-
// First, try to find in top-level messages
|
|
126
107
|
const index = draftState.findIndex((i) => i.id === id);
|
|
127
108
|
if (index >= 0) {
|
|
128
109
|
draftState[index] = merge(draftState[index], { ...value, updatedAt: Date.now() });
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// If not found, search in group message children (blocks)
|
|
133
|
-
for (const message of draftState) {
|
|
134
|
-
if (message.role === 'group' && message.children) {
|
|
135
|
-
const blockIndex = message.children.findIndex((block) => block.id === id);
|
|
136
|
-
if (blockIndex >= 0) {
|
|
137
|
-
message.children[blockIndex] = merge(message.children[blockIndex], {
|
|
138
|
-
...value,
|
|
139
|
-
});
|
|
140
|
-
message.updatedAt = Date.now();
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
110
|
}
|
|
145
111
|
});
|
|
146
112
|
}
|
|
@@ -161,6 +127,17 @@ export const messagesReducer = (
|
|
|
161
127
|
});
|
|
162
128
|
}
|
|
163
129
|
|
|
130
|
+
case 'updateMessageMetadata': {
|
|
131
|
+
return produce(state, (draftState) => {
|
|
132
|
+
const { id, value } = payload;
|
|
133
|
+
const message = draftState.find((i) => i.id === id);
|
|
134
|
+
if (!message) return;
|
|
135
|
+
|
|
136
|
+
message.metadata = merge(message.metadata, value);
|
|
137
|
+
message.updatedAt = Date.now();
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
164
141
|
case 'updatePluginState': {
|
|
165
142
|
return produce(state, (draftState) => {
|
|
166
143
|
const { id, key, value } = payload;
|
|
@@ -269,47 +246,6 @@ export const messagesReducer = (
|
|
|
269
246
|
});
|
|
270
247
|
}
|
|
271
248
|
|
|
272
|
-
case 'updateGroupBlockToolResult': {
|
|
273
|
-
return produce(state, (draftState) => {
|
|
274
|
-
const { groupMessageId, blockId, toolId, toolResult } = payload;
|
|
275
|
-
|
|
276
|
-
// Find the group message
|
|
277
|
-
const msg = draftState.find((m) => m.id === groupMessageId);
|
|
278
|
-
if (!msg || msg.role !== 'group' || !msg.children) return;
|
|
279
|
-
|
|
280
|
-
// Find the block within children
|
|
281
|
-
const block = msg.children.find((b) => b.id === blockId);
|
|
282
|
-
if (!block || !block.tools) return;
|
|
283
|
-
|
|
284
|
-
// Find the tool and update its result
|
|
285
|
-
const tool = block.tools.find((t) => t.id === toolId);
|
|
286
|
-
if (!tool) return;
|
|
287
|
-
|
|
288
|
-
// Update tool result (optimistic update)
|
|
289
|
-
tool.result = toolResult;
|
|
290
|
-
|
|
291
|
-
msg.updatedAt = Date.now();
|
|
292
|
-
});
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
case 'addGroupBlock': {
|
|
296
|
-
return produce(state, (draftState) => {
|
|
297
|
-
const { groupMessageId, blockId, value } = payload;
|
|
298
|
-
|
|
299
|
-
// Find the group message
|
|
300
|
-
const msg = draftState.find((m) => m.id === groupMessageId);
|
|
301
|
-
if (!msg || msg.role !== 'group' || !msg.children) return;
|
|
302
|
-
|
|
303
|
-
// Add new block to children
|
|
304
|
-
msg.children.push({
|
|
305
|
-
content: value.content,
|
|
306
|
-
id: blockId,
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
msg.updatedAt = Date.now();
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
|
|
313
249
|
default: {
|
|
314
250
|
throw new Error('暂未实现的 type,请检查 reducer');
|
|
315
251
|
}
|