@lobehub/chat 0.156.1 → 0.157.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +42 -0
- package/Dockerfile +4 -1
- package/package.json +3 -2
- package/src/config/modelProviders/anthropic.ts +3 -0
- package/src/config/modelProviders/google.ts +3 -0
- package/src/config/modelProviders/groq.ts +5 -1
- package/src/config/modelProviders/minimax.ts +10 -7
- package/src/config/modelProviders/mistral.ts +1 -0
- package/src/config/modelProviders/moonshot.ts +3 -0
- package/src/config/modelProviders/zhipu.ts +2 -6
- package/src/config/server/provider.ts +1 -1
- package/src/database/client/core/db.ts +32 -0
- package/src/database/client/core/schemas.ts +9 -0
- package/src/database/client/models/__tests__/message.test.ts +2 -2
- package/src/database/client/schemas/message.ts +8 -1
- package/src/features/AgentSetting/store/action.ts +15 -6
- package/src/features/Conversation/Actions/Tool.tsx +16 -0
- package/src/features/Conversation/Actions/index.ts +2 -2
- package/src/features/Conversation/Messages/Assistant/ToolCalls/index.tsx +78 -0
- package/src/features/Conversation/Messages/Assistant/ToolCalls/style.ts +25 -0
- package/src/features/Conversation/Messages/Assistant/index.tsx +47 -0
- package/src/features/Conversation/Messages/Default.tsx +4 -1
- package/src/features/Conversation/{Plugins → Messages/Tool}/Inspector/index.tsx +34 -35
- package/src/features/Conversation/Messages/Tool/index.tsx +44 -0
- package/src/features/Conversation/Messages/index.ts +3 -2
- package/src/features/Conversation/Plugins/Render/StandaloneType/Iframe.tsx +1 -1
- package/src/features/Conversation/components/SkeletonList.tsx +2 -2
- package/src/features/Conversation/index.tsx +2 -3
- package/src/libs/agent-runtime/BaseAI.ts +2 -9
- package/src/libs/agent-runtime/anthropic/index.test.ts +195 -0
- package/src/libs/agent-runtime/anthropic/index.ts +71 -15
- package/src/libs/agent-runtime/azureOpenai/index.ts +12 -13
- package/src/libs/agent-runtime/bedrock/index.ts +24 -18
- package/src/libs/agent-runtime/google/index.test.ts +154 -0
- package/src/libs/agent-runtime/google/index.ts +91 -10
- package/src/libs/agent-runtime/groq/index.test.ts +41 -72
- package/src/libs/agent-runtime/groq/index.ts +7 -0
- package/src/libs/agent-runtime/minimax/index.test.ts +2 -2
- package/src/libs/agent-runtime/minimax/index.ts +14 -37
- package/src/libs/agent-runtime/mistral/index.test.ts +0 -53
- package/src/libs/agent-runtime/mistral/index.ts +1 -0
- package/src/libs/agent-runtime/moonshot/index.test.ts +1 -71
- package/src/libs/agent-runtime/ollama/index.test.ts +197 -0
- package/src/libs/agent-runtime/ollama/index.ts +3 -3
- package/src/libs/agent-runtime/openai/index.test.ts +0 -53
- package/src/libs/agent-runtime/openrouter/index.test.ts +1 -53
- package/src/libs/agent-runtime/perplexity/index.test.ts +0 -71
- package/src/libs/agent-runtime/perplexity/index.ts +2 -3
- package/src/libs/agent-runtime/togetherai/__snapshots__/index.test.ts.snap +886 -0
- package/src/libs/agent-runtime/togetherai/fixtures/models.json +8111 -0
- package/src/libs/agent-runtime/togetherai/index.test.ts +16 -54
- package/src/libs/agent-runtime/types/chat.ts +19 -3
- package/src/libs/agent-runtime/utils/anthropicHelpers.test.ts +120 -1
- package/src/libs/agent-runtime/utils/anthropicHelpers.ts +67 -4
- package/src/libs/agent-runtime/utils/debugStream.test.ts +70 -0
- package/src/libs/agent-runtime/utils/debugStream.ts +39 -9
- package/src/libs/agent-runtime/utils/openaiCompatibleFactory/index.test.ts +521 -0
- package/src/libs/agent-runtime/utils/openaiCompatibleFactory/index.ts +76 -5
- package/src/libs/agent-runtime/utils/response.ts +12 -0
- package/src/libs/agent-runtime/utils/streams/anthropic.test.ts +197 -0
- package/src/libs/agent-runtime/utils/streams/anthropic.ts +91 -0
- package/src/libs/agent-runtime/utils/streams/bedrock/claude.ts +21 -0
- package/src/libs/agent-runtime/utils/streams/bedrock/common.ts +32 -0
- package/src/libs/agent-runtime/utils/streams/bedrock/index.ts +3 -0
- package/src/libs/agent-runtime/utils/streams/bedrock/llama.test.ts +196 -0
- package/src/libs/agent-runtime/utils/streams/bedrock/llama.ts +51 -0
- package/src/libs/agent-runtime/utils/streams/google-ai.test.ts +97 -0
- package/src/libs/agent-runtime/utils/streams/google-ai.ts +68 -0
- package/src/libs/agent-runtime/utils/streams/index.ts +7 -0
- package/src/libs/agent-runtime/utils/streams/minimax.ts +39 -0
- package/src/libs/agent-runtime/utils/streams/ollama.test.ts +77 -0
- package/src/libs/agent-runtime/utils/streams/ollama.ts +38 -0
- package/src/libs/agent-runtime/utils/streams/openai.test.ts +263 -0
- package/src/libs/agent-runtime/utils/streams/openai.ts +79 -0
- package/src/libs/agent-runtime/utils/streams/protocol.ts +100 -0
- package/src/libs/agent-runtime/zeroone/index.test.ts +1 -53
- package/src/libs/agent-runtime/zhipu/index.test.ts +1 -1
- package/src/libs/agent-runtime/zhipu/index.ts +3 -2
- package/src/locales/default/plugin.ts +3 -4
- package/src/migrations/FromV4ToV5/fixtures/from-v1-to-v5-output.json +245 -0
- package/src/migrations/FromV4ToV5/fixtures/function-input-v4.json +96 -0
- package/src/migrations/FromV4ToV5/fixtures/function-output-v5.json +120 -0
- package/src/migrations/FromV4ToV5/index.ts +58 -0
- package/src/migrations/FromV4ToV5/migrations.test.ts +49 -0
- package/src/migrations/FromV4ToV5/types/v4.ts +21 -0
- package/src/migrations/FromV4ToV5/types/v5.ts +27 -0
- package/src/migrations/index.ts +8 -1
- package/src/services/__tests__/chat.test.ts +10 -20
- package/src/services/chat.ts +78 -65
- package/src/store/chat/slices/enchance/action.ts +15 -10
- package/src/store/chat/slices/message/action.test.ts +36 -86
- package/src/store/chat/slices/message/action.ts +70 -79
- package/src/store/chat/slices/message/reducer.ts +18 -1
- package/src/store/chat/slices/message/selectors.test.ts +38 -68
- package/src/store/chat/slices/message/selectors.ts +1 -22
- package/src/store/chat/slices/plugin/action.test.ts +147 -203
- package/src/store/chat/slices/plugin/action.ts +96 -82
- package/src/store/chat/slices/share/action.test.ts +3 -3
- package/src/store/chat/slices/share/action.ts +1 -1
- package/src/store/chat/slices/topic/action.ts +7 -2
- package/src/store/tool/selectors/tool.ts +6 -24
- package/src/store/tool/slices/builtin/action.test.ts +90 -0
- package/src/types/llm.ts +1 -1
- package/src/types/message/index.ts +9 -4
- package/src/types/message/tools.ts +57 -0
- package/src/types/openai/chat.ts +6 -0
- package/src/utils/fetch.test.ts +245 -1
- package/src/utils/fetch.ts +120 -44
- package/src/utils/toolCall.ts +21 -0
- package/src/features/Conversation/Messages/Assistant.tsx +0 -26
- package/src/features/Conversation/Messages/Function.tsx +0 -35
- package/src/libs/agent-runtime/ollama/stream.ts +0 -31
- /package/src/features/Conversation/{Plugins → Messages/Tool}/Inspector/PluginResultJSON.tsx +0 -0
- /package/src/features/Conversation/{Plugins → Messages/Tool}/Inspector/Settings.tsx +0 -0
- /package/src/features/Conversation/{Plugins → Messages/Tool}/Inspector/style.ts +0 -0
|
@@ -6,7 +6,7 @@ import { template } from 'lodash-es';
|
|
|
6
6
|
import { SWRResponse, mutate } from 'swr';
|
|
7
7
|
import { StateCreator } from 'zustand/vanilla';
|
|
8
8
|
|
|
9
|
-
import { LOADING_FLAT
|
|
9
|
+
import { LOADING_FLAT } from '@/const/message';
|
|
10
10
|
import { TraceEventType, TraceNameMap } from '@/const/trace';
|
|
11
11
|
import { useClientDataSWR } from '@/libs/swr';
|
|
12
12
|
import { chatService } from '@/services/chat';
|
|
@@ -17,7 +17,7 @@ import { useAgentStore } from '@/store/agent';
|
|
|
17
17
|
import { agentSelectors } from '@/store/agent/selectors';
|
|
18
18
|
import { chatHelpers } from '@/store/chat/helpers';
|
|
19
19
|
import { ChatStore } from '@/store/chat/store';
|
|
20
|
-
import { ChatMessage } from '@/types/message';
|
|
20
|
+
import { ChatMessage, MessageToolCall } from '@/types/message';
|
|
21
21
|
import { TraceEventPayloads } from '@/types/trace';
|
|
22
22
|
import { setNamespace } from '@/utils/storeDebug';
|
|
23
23
|
import { nanoid } from '@/utils/uuid';
|
|
@@ -105,9 +105,6 @@ export interface ChatMessageAction {
|
|
|
105
105
|
assistantMessageId: string,
|
|
106
106
|
params?: ProcessMessageParams,
|
|
107
107
|
) => Promise<{
|
|
108
|
-
content: string;
|
|
109
|
-
functionCallAtEnd: boolean;
|
|
110
|
-
functionCallContent: string;
|
|
111
108
|
isFunctionCall: boolean;
|
|
112
109
|
traceId?: string;
|
|
113
110
|
}>;
|
|
@@ -123,7 +120,11 @@ export interface ChatMessageAction {
|
|
|
123
120
|
* @param id
|
|
124
121
|
* @param content
|
|
125
122
|
*/
|
|
126
|
-
internal_updateMessageContent: (
|
|
123
|
+
internal_updateMessageContent: (
|
|
124
|
+
id: string,
|
|
125
|
+
content: string,
|
|
126
|
+
toolCalls?: MessageToolCall[],
|
|
127
|
+
) => Promise<void>;
|
|
127
128
|
internal_createMessage: (params: CreateMessageParams) => Promise<string>;
|
|
128
129
|
internal_resendMessage: (id: string, traceId?: string) => Promise<void>;
|
|
129
130
|
internal_traceMessage: (id: string, payload: TraceEventPayloads) => Promise<void>;
|
|
@@ -156,8 +157,29 @@ export const chatMessage: StateCreator<
|
|
|
156
157
|
ChatMessageAction
|
|
157
158
|
> = (set, get) => ({
|
|
158
159
|
deleteMessage: async (id) => {
|
|
159
|
-
|
|
160
|
-
|
|
160
|
+
const message = chatSelectors.getMessageById(id)(get());
|
|
161
|
+
if (!message) return;
|
|
162
|
+
|
|
163
|
+
const deleteFn = async (id: string) => {
|
|
164
|
+
get().internal_dispatchMessage({ type: 'deleteMessage', id });
|
|
165
|
+
await messageService.removeMessage(id);
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
// if the message is a tool calls, then delete all the related messages
|
|
169
|
+
// TODO: maybe we need to delete it in the DB?
|
|
170
|
+
if (message.tools) {
|
|
171
|
+
const pools = message.tools
|
|
172
|
+
.flatMap((tool) => {
|
|
173
|
+
const messages = get().messages.filter((m) => m.tool_call_id === tool.id);
|
|
174
|
+
|
|
175
|
+
return messages.map((m) => m.id);
|
|
176
|
+
})
|
|
177
|
+
.map((i) => deleteFn(i));
|
|
178
|
+
|
|
179
|
+
await Promise.all(pools);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
await deleteFn(id);
|
|
161
183
|
await get().refreshMessages();
|
|
162
184
|
},
|
|
163
185
|
delAndRegenerateMessage: async (id) => {
|
|
@@ -310,8 +332,7 @@ export const chatMessage: StateCreator<
|
|
|
310
332
|
|
|
311
333
|
// the internal process method of the AI message
|
|
312
334
|
internal_coreProcessMessage: async (messages, userMessageId, params) => {
|
|
313
|
-
const { internal_fetchAIChatMessage,
|
|
314
|
-
get();
|
|
335
|
+
const { internal_fetchAIChatMessage, triggerToolCalls, refreshMessages, activeTopicId } = get();
|
|
315
336
|
|
|
316
337
|
const { model, provider } = getAgentConfig();
|
|
317
338
|
|
|
@@ -327,39 +348,15 @@ export const chatMessage: StateCreator<
|
|
|
327
348
|
topicId: activeTopicId, // if there is activeTopicId,then add it to topicId
|
|
328
349
|
};
|
|
329
350
|
|
|
330
|
-
const
|
|
351
|
+
const assistantId = await get().internal_createMessage(assistantMessage);
|
|
331
352
|
|
|
332
353
|
// 2. fetch the AI response
|
|
333
|
-
const { isFunctionCall
|
|
334
|
-
await internal_fetchAIChatMessage(messages, mid, params);
|
|
354
|
+
const { isFunctionCall } = await internal_fetchAIChatMessage(messages, assistantId, params);
|
|
335
355
|
|
|
336
356
|
// 3. if it's the function call message, trigger the function method
|
|
337
357
|
if (isFunctionCall) {
|
|
338
|
-
let functionId = mid;
|
|
339
|
-
|
|
340
|
-
// if the function call is at the end of the message, then create a new function message
|
|
341
|
-
if (functionCallAtEnd) {
|
|
342
|
-
// create a new separate message and remove the function call from the prev message
|
|
343
|
-
|
|
344
|
-
await get().internal_updateMessageContent(mid, content.replace(functionCallContent, ''));
|
|
345
|
-
|
|
346
|
-
const functionMessage: CreateMessageParams = {
|
|
347
|
-
role: 'function',
|
|
348
|
-
content: functionCallContent,
|
|
349
|
-
fromModel: model,
|
|
350
|
-
fromProvider: provider,
|
|
351
|
-
|
|
352
|
-
parentId: userMessageId,
|
|
353
|
-
sessionId: get().activeId,
|
|
354
|
-
topicId: activeTopicId,
|
|
355
|
-
traceId,
|
|
356
|
-
};
|
|
357
|
-
|
|
358
|
-
functionId = await get().internal_createMessage(functionMessage);
|
|
359
|
-
}
|
|
360
|
-
|
|
361
358
|
await refreshMessages();
|
|
362
|
-
await
|
|
359
|
+
await triggerToolCalls(assistantId);
|
|
363
360
|
}
|
|
364
361
|
},
|
|
365
362
|
internal_dispatchMessage: (payload) => {
|
|
@@ -369,7 +366,7 @@ export const chatMessage: StateCreator<
|
|
|
369
366
|
|
|
370
367
|
const messages = messagesReducer(get().messages, payload);
|
|
371
368
|
|
|
372
|
-
set({ messages }, false,
|
|
369
|
+
set({ messages }, false, { type: `dispatchMessage/${payload.type}`, payload });
|
|
373
370
|
},
|
|
374
371
|
internal_fetchAIChatMessage: async (messages, assistantId, params) => {
|
|
375
372
|
const {
|
|
@@ -432,10 +429,7 @@ export const chatMessage: StateCreator<
|
|
|
432
429
|
config.params.max_tokens = 2048;
|
|
433
430
|
}
|
|
434
431
|
|
|
435
|
-
let output = '';
|
|
436
432
|
let isFunctionCall = false;
|
|
437
|
-
let functionCallAtEnd = false;
|
|
438
|
-
let functionCallContent = '';
|
|
439
433
|
let msgTraceId: string | undefined;
|
|
440
434
|
|
|
441
435
|
const { startAnimation, stopAnimation, outputQueue, isAnimationActive } =
|
|
@@ -464,7 +458,7 @@ export const chatMessage: StateCreator<
|
|
|
464
458
|
onAbort: async () => {
|
|
465
459
|
stopAnimation();
|
|
466
460
|
},
|
|
467
|
-
onFinish: async (content, { traceId, observationId }) => {
|
|
461
|
+
onFinish: async (content, { traceId, observationId, toolCalls }) => {
|
|
468
462
|
stopAnimation();
|
|
469
463
|
// if there is traceId, update it
|
|
470
464
|
if (traceId) {
|
|
@@ -483,22 +477,24 @@ export const chatMessage: StateCreator<
|
|
|
483
477
|
}
|
|
484
478
|
|
|
485
479
|
// update the content after fetch result
|
|
486
|
-
await internal_updateMessageContent(assistantId, content);
|
|
480
|
+
await internal_updateMessageContent(assistantId, content, toolCalls);
|
|
487
481
|
},
|
|
488
|
-
onMessageHandle: async (
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
482
|
+
onMessageHandle: async (chunk) => {
|
|
483
|
+
switch (chunk.type) {
|
|
484
|
+
case 'text': {
|
|
485
|
+
outputQueue.push(...chunk.text.split(''));
|
|
486
|
+
break;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// is this message is just a tool call
|
|
490
|
+
case 'tool_calls': {
|
|
491
|
+
internal_dispatchMessage({
|
|
492
|
+
id: assistantId,
|
|
493
|
+
type: 'updateMessages',
|
|
494
|
+
value: { tools: get().internal_transformToolCalls(chunk.tool_calls) },
|
|
495
|
+
});
|
|
496
|
+
isFunctionCall = true;
|
|
497
|
+
}
|
|
502
498
|
}
|
|
503
499
|
|
|
504
500
|
// if it's the first time to receive the message,
|
|
@@ -510,23 +506,7 @@ export const chatMessage: StateCreator<
|
|
|
510
506
|
|
|
511
507
|
internal_toggleChatLoading(false, undefined, n('generateMessage(end)') as string);
|
|
512
508
|
|
|
513
|
-
// also exist message like this:
|
|
514
|
-
// 请稍等,我帮您查询一下。{"tool_calls":[{"id":"call_sbca","type":"function","function":{"name":"pluginName____apiName","arguments":{"key":"value"}}}]}
|
|
515
|
-
if (!isFunctionCall) {
|
|
516
|
-
const { content, valid } = testFunctionMessageAtEnd(output);
|
|
517
|
-
|
|
518
|
-
// if fc at end, replace the message
|
|
519
|
-
if (valid) {
|
|
520
|
-
isFunctionCall = true;
|
|
521
|
-
functionCallAtEnd = true;
|
|
522
|
-
functionCallContent = content;
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
|
|
526
509
|
return {
|
|
527
|
-
content: output,
|
|
528
|
-
functionCallAtEnd,
|
|
529
|
-
functionCallContent,
|
|
530
510
|
isFunctionCall,
|
|
531
511
|
traceId: msgTraceId,
|
|
532
512
|
};
|
|
@@ -584,7 +564,7 @@ export const chatMessage: StateCreator<
|
|
|
584
564
|
let contextMessages: ChatMessage[] = [];
|
|
585
565
|
|
|
586
566
|
switch (currentMessage.role) {
|
|
587
|
-
case '
|
|
567
|
+
case 'tool':
|
|
588
568
|
case 'user': {
|
|
589
569
|
contextMessages = chats.slice(0, currentIndex + 1);
|
|
590
570
|
break;
|
|
@@ -610,15 +590,26 @@ export const chatMessage: StateCreator<
|
|
|
610
590
|
await internal_coreProcessMessage(contextMessages, latestMsg.id, { traceId });
|
|
611
591
|
},
|
|
612
592
|
|
|
613
|
-
internal_updateMessageContent: async (id, content) => {
|
|
614
|
-
const { internal_dispatchMessage, refreshMessages } = get();
|
|
593
|
+
internal_updateMessageContent: async (id, content, toolCalls) => {
|
|
594
|
+
const { internal_dispatchMessage, refreshMessages, internal_transformToolCalls } = get();
|
|
615
595
|
|
|
616
596
|
// Due to the async update method and refresh need about 100ms
|
|
617
597
|
// we need to update the message content at the frontend to avoid the update flick
|
|
618
598
|
// refs: https://medium.com/@kyledeguzmanx/what-are-optimistic-updates-483662c3e171
|
|
619
|
-
|
|
599
|
+
if (toolCalls) {
|
|
600
|
+
internal_dispatchMessage({
|
|
601
|
+
id,
|
|
602
|
+
type: 'updateMessages',
|
|
603
|
+
value: { tools: internal_transformToolCalls(toolCalls) },
|
|
604
|
+
});
|
|
605
|
+
} else {
|
|
606
|
+
internal_dispatchMessage({ id, type: 'updateMessages', value: { content } });
|
|
607
|
+
}
|
|
620
608
|
|
|
621
|
-
await messageService.updateMessage(id, {
|
|
609
|
+
await messageService.updateMessage(id, {
|
|
610
|
+
content,
|
|
611
|
+
tools: toolCalls ? internal_transformToolCalls(toolCalls) : undefined,
|
|
612
|
+
});
|
|
622
613
|
await refreshMessages();
|
|
623
614
|
},
|
|
624
615
|
|
|
@@ -685,7 +676,7 @@ export const chatMessage: StateCreator<
|
|
|
685
676
|
buffer += charsToAdd;
|
|
686
677
|
|
|
687
678
|
// 更新消息内容,这里可能需要结合实际情况调整
|
|
688
|
-
internal_dispatchMessage({ id,
|
|
679
|
+
internal_dispatchMessage({ id, type: 'updateMessages', value: { content: buffer } });
|
|
689
680
|
|
|
690
681
|
// 设置下一个字符的延迟
|
|
691
682
|
animationTimeoutId = setTimeout(updateText, 16); // 16 毫秒的延迟模拟打字机效果
|
|
@@ -11,6 +11,13 @@ interface UpdateMessage {
|
|
|
11
11
|
type: 'updateMessage';
|
|
12
12
|
value: ChatMessage[keyof ChatMessage];
|
|
13
13
|
}
|
|
14
|
+
|
|
15
|
+
interface UpdateMessages {
|
|
16
|
+
id: string;
|
|
17
|
+
type: 'updateMessages';
|
|
18
|
+
value: Partial<ChatMessage>;
|
|
19
|
+
}
|
|
20
|
+
|
|
14
21
|
interface CreateMessage {
|
|
15
22
|
id: string;
|
|
16
23
|
type: 'createMessage';
|
|
@@ -37,6 +44,7 @@ interface UpdateMessageExtra {
|
|
|
37
44
|
export type MessageDispatch =
|
|
38
45
|
| CreateMessage
|
|
39
46
|
| UpdateMessage
|
|
47
|
+
| UpdateMessages
|
|
40
48
|
| UpdatePluginState
|
|
41
49
|
| UpdateMessageExtra
|
|
42
50
|
| DeleteMessage;
|
|
@@ -54,6 +62,15 @@ export const messagesReducer = (state: ChatMessage[], payload: MessageDispatch):
|
|
|
54
62
|
message.updatedAt = Date.now();
|
|
55
63
|
});
|
|
56
64
|
}
|
|
65
|
+
case 'updateMessages': {
|
|
66
|
+
return produce(state, (draftState) => {
|
|
67
|
+
const { id, value } = payload;
|
|
68
|
+
const index = draftState.findIndex((i) => i.id === id);
|
|
69
|
+
if (index < 0) return;
|
|
70
|
+
|
|
71
|
+
draftState[index] = merge(draftState[index], { ...value, updatedAt: Date.now() });
|
|
72
|
+
});
|
|
73
|
+
}
|
|
57
74
|
|
|
58
75
|
case 'updateMessageExtra': {
|
|
59
76
|
return produce(state, (draftState) => {
|
|
@@ -67,7 +84,7 @@ export const messagesReducer = (state: ChatMessage[], payload: MessageDispatch):
|
|
|
67
84
|
message.extra[key] = value;
|
|
68
85
|
}
|
|
69
86
|
|
|
70
|
-
message.
|
|
87
|
+
message.updatedAt = Date.now();
|
|
71
88
|
});
|
|
72
89
|
}
|
|
73
90
|
|
|
@@ -35,12 +35,16 @@ const mockMessages = [
|
|
|
35
35
|
{
|
|
36
36
|
id: 'msg3',
|
|
37
37
|
content: 'Function Message',
|
|
38
|
-
role: '
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
role: 'tool',
|
|
39
|
+
tools: [
|
|
40
|
+
{
|
|
41
|
+
arguments: ['arg1', 'arg2'],
|
|
42
|
+
identifier: 'func1',
|
|
43
|
+
apiName: 'ttt',
|
|
44
|
+
type: 'pluginType',
|
|
45
|
+
id: 'abc',
|
|
46
|
+
},
|
|
47
|
+
],
|
|
44
48
|
},
|
|
45
49
|
] as ChatMessage[];
|
|
46
50
|
|
|
@@ -64,16 +68,22 @@ const mockedChats = [
|
|
|
64
68
|
{
|
|
65
69
|
id: 'msg3',
|
|
66
70
|
content: 'Function Message',
|
|
67
|
-
role: '
|
|
71
|
+
role: 'tool',
|
|
68
72
|
meta: {
|
|
69
|
-
avatar: '
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
arguments: ['arg1', 'arg2'],
|
|
74
|
-
identifier: 'func1',
|
|
75
|
-
type: 'pluginType',
|
|
73
|
+
avatar: '🤯',
|
|
74
|
+
backgroundColor: 'rgba(0,0,0,0)',
|
|
75
|
+
description: 'inbox.desc',
|
|
76
|
+
title: 'inbox.title',
|
|
76
77
|
},
|
|
78
|
+
tools: [
|
|
79
|
+
{
|
|
80
|
+
arguments: ['arg1', 'arg2'],
|
|
81
|
+
identifier: 'func1',
|
|
82
|
+
apiName: 'ttt',
|
|
83
|
+
type: 'pluginType',
|
|
84
|
+
id: 'abc',
|
|
85
|
+
},
|
|
86
|
+
],
|
|
77
87
|
},
|
|
78
88
|
] as ChatMessage[];
|
|
79
89
|
|
|
@@ -103,52 +113,6 @@ describe('chatSelectors', () => {
|
|
|
103
113
|
});
|
|
104
114
|
});
|
|
105
115
|
|
|
106
|
-
describe('getFunctionMessageProps', () => {
|
|
107
|
-
it('should return the properties of a function message', () => {
|
|
108
|
-
const state = merge(initialStore, {
|
|
109
|
-
messages: mockMessages,
|
|
110
|
-
chatLoadingIds: ['msg3'], // Assuming this id represents a loading state
|
|
111
|
-
});
|
|
112
|
-
const props = chatSelectors.getFunctionMessageProps(mockMessages[2])(state);
|
|
113
|
-
expect(props).toEqual({
|
|
114
|
-
arguments: ['arg1', 'arg2'],
|
|
115
|
-
command: mockMessages[2].plugin,
|
|
116
|
-
content: 'Function Message',
|
|
117
|
-
id: 'func1',
|
|
118
|
-
loading: true,
|
|
119
|
-
type: 'pluginType',
|
|
120
|
-
});
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
it('should return loading as false if the message id is not the current loading id', () => {
|
|
124
|
-
const state = merge(initialStore, { messages: mockMessages, chatLoadingId: 'msg1' });
|
|
125
|
-
const props = chatSelectors.getFunctionMessageProps(mockMessages[2])(state);
|
|
126
|
-
expect(props.loading).toBe(false);
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
it('should return correct properties when no plugin is present', () => {
|
|
130
|
-
const messageWithoutPlugin = {
|
|
131
|
-
id: 'msg4',
|
|
132
|
-
content: 'No Plugin Message',
|
|
133
|
-
role: 'function',
|
|
134
|
-
// No plugin property
|
|
135
|
-
};
|
|
136
|
-
const state = merge(initialStore, {
|
|
137
|
-
messages: [...mockMessages, messageWithoutPlugin],
|
|
138
|
-
chatLoadingId: 'msg1',
|
|
139
|
-
});
|
|
140
|
-
const props = chatSelectors.getFunctionMessageProps(messageWithoutPlugin)(state);
|
|
141
|
-
expect(props).toEqual({
|
|
142
|
-
arguments: undefined,
|
|
143
|
-
command: undefined,
|
|
144
|
-
content: 'No Plugin Message',
|
|
145
|
-
id: undefined,
|
|
146
|
-
loading: false,
|
|
147
|
-
type: undefined,
|
|
148
|
-
});
|
|
149
|
-
});
|
|
150
|
-
});
|
|
151
|
-
|
|
152
116
|
describe('currentChatsWithHistoryConfig', () => {
|
|
153
117
|
it('should slice the messages according to the current agent config', () => {
|
|
154
118
|
const state = merge(initialStore, { messages: mockMessages });
|
|
@@ -185,16 +149,22 @@ describe('chatSelectors', () => {
|
|
|
185
149
|
{
|
|
186
150
|
id: 'msg3',
|
|
187
151
|
content: 'Function Message',
|
|
188
|
-
role: '
|
|
152
|
+
role: 'tool',
|
|
189
153
|
meta: {
|
|
190
|
-
avatar: '
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
arguments: ['arg1', 'arg2'],
|
|
195
|
-
identifier: 'func1',
|
|
196
|
-
type: 'pluginType',
|
|
154
|
+
avatar: '🤯',
|
|
155
|
+
backgroundColor: 'rgba(0,0,0,0)',
|
|
156
|
+
description: 'inbox.desc',
|
|
157
|
+
title: 'inbox.title',
|
|
197
158
|
},
|
|
159
|
+
tools: [
|
|
160
|
+
{
|
|
161
|
+
apiName: 'ttt',
|
|
162
|
+
arguments: ['arg1', 'arg2'],
|
|
163
|
+
identifier: 'func1',
|
|
164
|
+
id: 'abc',
|
|
165
|
+
type: 'pluginType',
|
|
166
|
+
},
|
|
167
|
+
],
|
|
198
168
|
},
|
|
199
169
|
]);
|
|
200
170
|
});
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { LobePluginType } from '@lobehub/chat-plugin-sdk';
|
|
2
1
|
import { t } from 'i18next';
|
|
3
2
|
|
|
4
3
|
import { DEFAULT_INBOX_AVATAR, DEFAULT_USER_AVATAR } from '@/const/meta';
|
|
@@ -28,17 +27,9 @@ const getMeta = (message: ChatMessage) => {
|
|
|
28
27
|
return message.meta;
|
|
29
28
|
}
|
|
30
29
|
|
|
31
|
-
|
|
30
|
+
default: {
|
|
32
31
|
return sessionMetaSelectors.currentAgentMeta(useSessionStore.getState());
|
|
33
32
|
}
|
|
34
|
-
|
|
35
|
-
case 'function': {
|
|
36
|
-
// TODO: 后续改成将 plugin metadata 写入 message metadata 的方案
|
|
37
|
-
return {
|
|
38
|
-
avatar: '🧩',
|
|
39
|
-
title: 'plugin-unknown',
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
33
|
}
|
|
43
34
|
};
|
|
44
35
|
|
|
@@ -116,17 +107,6 @@ const chatsMessageString = (s: ChatStore): string => {
|
|
|
116
107
|
return chats.map((m) => m.content).join('');
|
|
117
108
|
};
|
|
118
109
|
|
|
119
|
-
const getFunctionMessageProps =
|
|
120
|
-
({ plugin, content, id }: Pick<ChatMessage, 'plugin' | 'content' | 'id'>) =>
|
|
121
|
-
(s: ChatStore) => ({
|
|
122
|
-
arguments: plugin?.arguments,
|
|
123
|
-
command: plugin,
|
|
124
|
-
content,
|
|
125
|
-
id: plugin?.identifier,
|
|
126
|
-
loading: s.chatLoadingIds.includes(id),
|
|
127
|
-
type: plugin?.type as LobePluginType,
|
|
128
|
-
});
|
|
129
|
-
|
|
130
110
|
const getMessageById = (id: string) => (s: ChatStore) => chatHelpers.getMessageById(s.messages, id);
|
|
131
111
|
const getTraceIdByMessageId = (id: string) => (s: ChatStore) => getMessageById(id)(s)?.traceId;
|
|
132
112
|
|
|
@@ -147,7 +127,6 @@ export const chatSelectors = {
|
|
|
147
127
|
currentChats,
|
|
148
128
|
currentChatsWithGuideMessage,
|
|
149
129
|
currentChatsWithHistoryConfig,
|
|
150
|
-
getFunctionMessageProps,
|
|
151
130
|
getMessageById,
|
|
152
131
|
getTraceIdByMessageId,
|
|
153
132
|
isAIGenerating,
|