@lobehub/chat 0.26.0 → 0.27.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 +58 -0
- package/package.json +1 -1
- package/src/const/message.ts +2 -0
- package/src/locales/default/common.ts +3 -0
- package/src/locales/default/plugin.ts +19 -1
- package/src/pages/api/openai.ts +7 -4
- package/src/pages/api/plugins.api.ts +16 -38
- package/src/pages/chat/[id]/Conversation/ChatList/MessageExtra.tsx +28 -26
- package/src/pages/chat/[id]/Conversation/ChatList/Plugins/FunctionCall.tsx +60 -0
- package/src/pages/chat/[id]/Conversation/ChatList/Plugins/PluginMessage.tsx +45 -0
- package/src/pages/chat/[id]/Conversation/ChatList/Plugins/PluginResultRender.tsx +51 -0
- package/src/pages/chat/[id]/Conversation/ChatList/Plugins/style.ts +25 -0
- package/src/pages/chat/[id]/Conversation/ChatList/index.tsx +34 -9
- package/src/pages/chat/[id]/edit/AgentPlugin/index.tsx +2 -2
- package/src/pages/setting/index.page.tsx +11 -28
- package/src/pages/setting/layout.tsx +35 -0
- package/src/plugins/Render.ts +11 -0
- package/src/plugins/index.ts +7 -3
- package/src/plugins/searchEngine/Render.tsx +85 -0
- package/src/plugins/searchEngine/index.ts +4 -1
- package/src/plugins/searchEngine/runner.ts +7 -73
- package/src/plugins/searchEngine/type.ts +82 -0
- package/src/plugins/type.ts +17 -0
- package/src/plugins/weather/Render.tsx +53 -0
- package/src/plugins/weather/index.ts +9 -1
- package/src/plugins/weather/runner.ts +12 -7
- package/src/plugins/weather/type.ts +36 -0
- package/src/plugins/webCrawler/index.ts +4 -1
- package/src/plugins/webCrawler/runner.ts +3 -27
- package/src/plugins/webCrawler/type.ts +32 -0
- package/src/services/chatModel.ts +1 -2
- package/src/services/plugin.ts +30 -0
- package/src/store/session/slices/chat/actions/message.ts +59 -40
- package/src/store/session/slices/chat/selectors/utils.test.ts +3 -2
- package/src/store/session/slices/chat/selectors/utils.ts +4 -3
- package/src/types/chatMessage.ts +5 -1
- package/src/types/openai.ts +3 -0
- package/src/types/plugin.ts +4 -0
- package/src/utils/message.ts +16 -0
- package/src/pages/chat/[id]/Conversation/ChatList/FunctionMessage.tsx +0 -31
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { StateCreator } from 'zustand/vanilla';
|
|
2
2
|
|
|
3
3
|
import { fetchChatModel } from '@/services/chatModel';
|
|
4
|
+
import { fetchPlugin } from '@/services/plugin';
|
|
4
5
|
import { SessionStore, agentSelectors, chatSelectors, sessionSelectors } from '@/store/session';
|
|
5
|
-
import { ChatMessage } from '@/types/chatMessage';
|
|
6
|
+
import { ChatMessage, OpenAIFunctionCall } from '@/types/chatMessage';
|
|
6
7
|
import { fetchSSE } from '@/utils/fetch';
|
|
7
8
|
import { isFunctionMessage } from '@/utils/message';
|
|
8
9
|
import { nanoid } from '@/utils/uuid';
|
|
@@ -42,8 +43,7 @@ export interface ChatMessageAction {
|
|
|
42
43
|
generateMessage: (
|
|
43
44
|
messages: ChatMessage[],
|
|
44
45
|
assistantMessageId: string,
|
|
45
|
-
|
|
46
|
-
) => Promise<{ isFunctionCall: boolean; output: string }>;
|
|
46
|
+
) => Promise<{ isFunctionCall: boolean }>;
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
49
|
* 实际获取 AI 响应
|
|
@@ -63,6 +63,7 @@ export interface ChatMessageAction {
|
|
|
63
63
|
* @param text - 消息文本
|
|
64
64
|
*/
|
|
65
65
|
sendMessage: (text: string) => Promise<void>;
|
|
66
|
+
triggerFunctionCall: (id: string) => Promise<void>;
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
export const chatMessage: StateCreator<
|
|
@@ -108,16 +109,13 @@ export const chatMessage: StateCreator<
|
|
|
108
109
|
get().dispatchSession({ chats, id: activeId, type: 'updateSessionChat' });
|
|
109
110
|
},
|
|
110
111
|
|
|
111
|
-
generateMessage: async (messages, assistantId
|
|
112
|
+
generateMessage: async (messages, assistantId) => {
|
|
112
113
|
const { dispatchMessage } = get();
|
|
113
114
|
set({ chatLoadingId: assistantId });
|
|
114
115
|
const config = agentSelectors.currentAgentConfigSafe(get());
|
|
115
116
|
|
|
116
117
|
const fetcher = () =>
|
|
117
|
-
fetchChatModel(
|
|
118
|
-
{ messages, model: config.model, ...config.params, plugins: config.plugins },
|
|
119
|
-
{ withPlugin },
|
|
120
|
-
);
|
|
118
|
+
fetchChatModel({ messages, model: config.model, ...config.params, plugins: config.plugins });
|
|
121
119
|
|
|
122
120
|
let output = '';
|
|
123
121
|
let isFunctionCall = false;
|
|
@@ -139,13 +137,6 @@ export const chatMessage: StateCreator<
|
|
|
139
137
|
// 如果是 function call
|
|
140
138
|
if (isFunctionMessage(output)) {
|
|
141
139
|
isFunctionCall = true;
|
|
142
|
-
// 设为 function
|
|
143
|
-
dispatchMessage({
|
|
144
|
-
id: assistantId,
|
|
145
|
-
key: 'role',
|
|
146
|
-
type: 'updateMessage',
|
|
147
|
-
value: 'function',
|
|
148
|
-
});
|
|
149
140
|
}
|
|
150
141
|
|
|
151
142
|
// 滚动到最后一条消息
|
|
@@ -158,11 +149,11 @@ export const chatMessage: StateCreator<
|
|
|
158
149
|
|
|
159
150
|
set({ chatLoadingId: undefined });
|
|
160
151
|
|
|
161
|
-
return { isFunctionCall
|
|
152
|
+
return { isFunctionCall };
|
|
162
153
|
},
|
|
163
154
|
|
|
164
155
|
realFetchAIResponse: async (messages, userMessageId) => {
|
|
165
|
-
const { dispatchMessage, generateMessage, activeTopicId } = get();
|
|
156
|
+
const { dispatchMessage, generateMessage, triggerFunctionCall, activeTopicId } = get();
|
|
166
157
|
|
|
167
158
|
// 添加 systemRole
|
|
168
159
|
const { systemRole, model } = agentSelectors.currentAgentConfigSafe(get());
|
|
@@ -191,31 +182,11 @@ export const chatMessage: StateCreator<
|
|
|
191
182
|
dispatchMessage({ id: mid, key: 'fromModel', type: 'updateMessageExtra', value: model });
|
|
192
183
|
|
|
193
184
|
// 生成 ai message
|
|
194
|
-
const {
|
|
185
|
+
const { isFunctionCall } = await generateMessage(messages, mid);
|
|
195
186
|
|
|
196
187
|
// 如果是 function,则发送函数调用方法
|
|
197
188
|
if (isFunctionCall) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
dispatchMessage({
|
|
201
|
-
id: mid,
|
|
202
|
-
key: 'function_call',
|
|
203
|
-
type: 'updateMessage',
|
|
204
|
-
value: function_call,
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
await generateMessage(
|
|
208
|
-
[...messages, { content: '', function_call, id: mid, role: 'assistant' } as ChatMessage],
|
|
209
|
-
mid,
|
|
210
|
-
true,
|
|
211
|
-
);
|
|
212
|
-
|
|
213
|
-
dispatchMessage({
|
|
214
|
-
id: mid,
|
|
215
|
-
key: 'role',
|
|
216
|
-
type: 'updateMessage',
|
|
217
|
-
value: 'assistant',
|
|
218
|
-
});
|
|
189
|
+
triggerFunctionCall(mid);
|
|
219
190
|
}
|
|
220
191
|
},
|
|
221
192
|
|
|
@@ -245,7 +216,6 @@ export const chatMessage: StateCreator<
|
|
|
245
216
|
|
|
246
217
|
await realFetchAIResponse(histories, latestMsg.id);
|
|
247
218
|
},
|
|
248
|
-
|
|
249
219
|
sendMessage: async (message) => {
|
|
250
220
|
const { dispatchMessage, realFetchAIResponse, autocompleteSessionAgentMeta, activeTopicId } =
|
|
251
221
|
get();
|
|
@@ -270,4 +240,53 @@ export const chatMessage: StateCreator<
|
|
|
270
240
|
autocompleteSessionAgentMeta(session.id);
|
|
271
241
|
}
|
|
272
242
|
},
|
|
243
|
+
|
|
244
|
+
triggerFunctionCall: async (id) => {
|
|
245
|
+
const { dispatchMessage, generateMessage } = get();
|
|
246
|
+
const session = sessionSelectors.currentSession(get());
|
|
247
|
+
|
|
248
|
+
if (!session) return;
|
|
249
|
+
|
|
250
|
+
const message = session.chats[id];
|
|
251
|
+
if (!message) return;
|
|
252
|
+
|
|
253
|
+
let payload: OpenAIFunctionCall = { name: '' };
|
|
254
|
+
if (message.content) {
|
|
255
|
+
const { function_call } = JSON.parse(message.content);
|
|
256
|
+
dispatchMessage({ id, key: 'function_call', type: 'updateMessage', value: function_call });
|
|
257
|
+
dispatchMessage({ id, key: 'content', type: 'updateMessage', value: '' });
|
|
258
|
+
payload = function_call;
|
|
259
|
+
} else {
|
|
260
|
+
if (message.function_call) {
|
|
261
|
+
payload = message.function_call;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (!payload.name) return;
|
|
266
|
+
|
|
267
|
+
// const fid = nanoid();
|
|
268
|
+
dispatchMessage({ id, key: 'role', type: 'updateMessage', value: 'function' });
|
|
269
|
+
dispatchMessage({ id, key: 'name', type: 'updateMessage', value: payload.name });
|
|
270
|
+
dispatchMessage({ id, key: 'function_call', type: 'updateMessage', value: payload });
|
|
271
|
+
|
|
272
|
+
// dispatchMessage({
|
|
273
|
+
// id: id,
|
|
274
|
+
// message: FUNCTION_LOADING,
|
|
275
|
+
// parentId: message.,
|
|
276
|
+
// role: 'function',
|
|
277
|
+
// type: 'addMessage',
|
|
278
|
+
// });
|
|
279
|
+
|
|
280
|
+
const data = await fetchPlugin(payload);
|
|
281
|
+
|
|
282
|
+
dispatchMessage({ id, key: 'content', type: 'updateMessage', value: data });
|
|
283
|
+
|
|
284
|
+
const mid = nanoid();
|
|
285
|
+
|
|
286
|
+
dispatchMessage({ id: mid, message: LOADING_FLAT, role: 'assistant', type: 'addMessage' });
|
|
287
|
+
|
|
288
|
+
const chats = chatSelectors.currentChats(get());
|
|
289
|
+
|
|
290
|
+
await generateMessage(chats, mid);
|
|
291
|
+
},
|
|
273
292
|
});
|
|
@@ -295,7 +295,7 @@ describe('organizeChats', () => {
|
|
|
295
295
|
const result = organizeChats(session, avatar);
|
|
296
296
|
const meta = result[0].meta;
|
|
297
297
|
|
|
298
|
-
expect(meta.avatar).toBe(avatar
|
|
298
|
+
expect(meta.avatar).toBe('assistant-avatar');
|
|
299
299
|
expect(meta.title).toBeUndefined();
|
|
300
300
|
});
|
|
301
301
|
|
|
@@ -329,6 +329,7 @@ describe('organizeChats', () => {
|
|
|
329
329
|
function_call: {
|
|
330
330
|
name: 'realtimeWeather',
|
|
331
331
|
},
|
|
332
|
+
name: 'realtimeWeather',
|
|
332
333
|
} as ChatMessage;
|
|
333
334
|
|
|
334
335
|
session.chats[message.id] = message;
|
|
@@ -336,7 +337,7 @@ describe('organizeChats', () => {
|
|
|
336
337
|
const result = organizeChats(session, avatar);
|
|
337
338
|
const meta = result[3].meta;
|
|
338
339
|
|
|
339
|
-
expect(meta.avatar).toBe('
|
|
340
|
+
expect(meta.avatar).toBe('🧩');
|
|
340
341
|
expect(meta.title).toBe('realtimeWeather');
|
|
341
342
|
});
|
|
342
343
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { PluginsMap } from '@/plugins';
|
|
2
2
|
import { ChatMessage } from '@/types/chatMessage';
|
|
3
3
|
import { LobeAgentSession } from '@/types/session';
|
|
4
4
|
|
|
@@ -27,9 +27,10 @@ export const organizeChats = (
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
case 'function': {
|
|
30
|
-
const plugin =
|
|
30
|
+
const plugin = PluginsMap[message.name || ''];
|
|
31
|
+
|
|
31
32
|
return {
|
|
32
|
-
avatar:
|
|
33
|
+
avatar: '🧩',
|
|
33
34
|
title: plugin?.name || 'plugin-unknown',
|
|
34
35
|
};
|
|
35
36
|
}
|
package/src/types/chatMessage.ts
CHANGED
|
@@ -11,6 +11,10 @@ export interface ChatMessageError {
|
|
|
11
11
|
message: string;
|
|
12
12
|
type: ErrorType;
|
|
13
13
|
}
|
|
14
|
+
export interface OpenAIFunctionCall {
|
|
15
|
+
arguments?: string;
|
|
16
|
+
name: string;
|
|
17
|
+
}
|
|
14
18
|
|
|
15
19
|
export interface ChatMessage extends BaseDataModel {
|
|
16
20
|
/**
|
|
@@ -29,7 +33,7 @@ export interface ChatMessage extends BaseDataModel {
|
|
|
29
33
|
};
|
|
30
34
|
} & Record<string, any>;
|
|
31
35
|
|
|
32
|
-
function_call?:
|
|
36
|
+
function_call?: OpenAIFunctionCall;
|
|
33
37
|
name?: string;
|
|
34
38
|
|
|
35
39
|
parentId?: string;
|
package/src/types/openai.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { OpenAIFunctionCall } from '@/types/chatMessage';
|
|
1
2
|
import { LLMRoleType } from '@/types/llm';
|
|
2
3
|
|
|
3
4
|
export interface OpenAIChatMessage {
|
|
@@ -7,6 +8,8 @@ export interface OpenAIChatMessage {
|
|
|
7
8
|
*/
|
|
8
9
|
content: string;
|
|
9
10
|
|
|
11
|
+
function_call?: OpenAIFunctionCall;
|
|
12
|
+
name?: string;
|
|
10
13
|
/**
|
|
11
14
|
* 角色
|
|
12
15
|
* @description 消息发送者的角色
|
package/src/utils/message.ts
CHANGED
|
@@ -3,3 +3,19 @@ import { FUNCTION_MESSAGE_FLAG } from '@/const/message';
|
|
|
3
3
|
export const isFunctionMessage = (content: string) => {
|
|
4
4
|
return content.startsWith(FUNCTION_MESSAGE_FLAG);
|
|
5
5
|
};
|
|
6
|
+
|
|
7
|
+
// export const createFunctionCallMessage = () => {
|
|
8
|
+
// return [
|
|
9
|
+
// {
|
|
10
|
+
// content: '',
|
|
11
|
+
// function_call: { arguments: '{\n "city": "杭州"\n}', name: 'realtimeWeather' },
|
|
12
|
+
// role: 'assistant',
|
|
13
|
+
// },
|
|
14
|
+
// {
|
|
15
|
+
// content:
|
|
16
|
+
// '{"status":"1","count":"1","info":"OK","infocode":"10000","forecasts":[{"city":"杭州市","adcode":"300","province":"浙江","reporttime":"2023-07-28 20:32:48","casts":[{"date":"2023-07-28","week":"5","dayweather"小雨","nightweather":"小雨-中雨","daytemp":"32","nighttemp":"26","daywind":"东","nightwind":"东","daypower":"6power":"6","daytemp_float":"32.0","nighttemp_float":"26.0"},{"date":"2023-07-29","week":"6","dayweather":"小雨雨","nightweather":"小雨","daytemp":"30","nighttemp":"25","daywind":"东南","nightwind":"东南","daypower":"4","wer":"4","daytemp_float":"30.0","nighttemp_float":"25.0"},{"date":"2023-07-30","week":"7","dayweather":"小雨",ightweather":"雷阵雨","daytemp":"31","nighttemp":"25","daywind":"东南","nightwind":"东南","daypower":"4","nigh:"4","daytemp_float":"31.0","nighttemp_float":"25.0"},{"date":"2023-07-31","week":"1","dayweather":"雷阵雨","ntweather":"雷阵雨","daytemp":"33","nighttemp":"25","daywind":"东","nightwind":"东","daypower":"4","nightpower""daytemp_float":"33.0","nighttemp_float":"25.0"}]}]}',
|
|
17
|
+
// name: 'realtimeWeather',
|
|
18
|
+
// role: 'function',
|
|
19
|
+
// },
|
|
20
|
+
// ];
|
|
21
|
+
// };
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { LoadingOutlined } from '@ant-design/icons';
|
|
2
|
-
import { createStyles } from 'antd-style';
|
|
3
|
-
import { memo } from 'react';
|
|
4
|
-
import { useTranslation } from 'react-i18next';
|
|
5
|
-
import { Flexbox } from 'react-layout-kit';
|
|
6
|
-
|
|
7
|
-
const useStyles = createStyles(({ css, token }) => ({
|
|
8
|
-
container: css`
|
|
9
|
-
padding: 4px 8px;
|
|
10
|
-
|
|
11
|
-
color: ${token.colorTextSecondary};
|
|
12
|
-
|
|
13
|
-
background: ${token.colorFillTertiary};
|
|
14
|
-
border: 1px solid ${token.colorBorder};
|
|
15
|
-
border-radius: 6px;
|
|
16
|
-
`,
|
|
17
|
-
}));
|
|
18
|
-
const FunctionMessage = memo(() => {
|
|
19
|
-
const { t } = useTranslation('plugin');
|
|
20
|
-
const { styles } = useStyles();
|
|
21
|
-
return (
|
|
22
|
-
<Flexbox className={styles.container} gap={8} horizontal>
|
|
23
|
-
<div>
|
|
24
|
-
<LoadingOutlined />
|
|
25
|
-
</div>
|
|
26
|
-
{t('pluginLoading')}
|
|
27
|
-
</Flexbox>
|
|
28
|
-
);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
export default FunctionMessage;
|