@lobehub/chat 0.115.12 → 0.116.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 +50 -0
- package/README.md +10 -7
- package/README.zh-CN.md +10 -7
- package/package.json +1 -1
- package/src/const/message.ts +2 -2
- package/src/database/models/message.ts +2 -5
- package/src/database/schemas/message.ts +1 -1
- package/src/services/__tests__/chat.test.ts +73 -57
- package/src/services/__tests__/message.test.ts +0 -60
- package/src/services/chat.ts +2 -3
- package/src/services/message.ts +1 -24
- package/src/store/chat/slices/enchance/action.test.ts +4 -22
- package/src/store/chat/slices/enchance/action.ts +19 -15
- package/src/store/chat/slices/message/action.test.ts +2 -2
- package/src/store/chat/slices/message/action.ts +5 -7
- package/src/store/chat/slices/tool/action.test.ts +35 -11
- package/src/store/chat/slices/tool/action.ts +14 -14
- package/src/store/tool/selectors/tool.test.ts +28 -3
- package/src/store/tool/selectors/tool.ts +3 -3
- package/src/types/message/index.ts +4 -8
- package/src/types/message/tools.ts +6 -0
- package/src/types/openai/chat.ts +14 -1
- package/src/types/openai/functionCall.ts +6 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## [Version 0.116.0](https://github.com/lobehub/lobe-chat/compare/v0.115.13...v0.116.0)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2023-12-26**</sup>
|
|
8
|
+
|
|
9
|
+
#### ✨ Features
|
|
10
|
+
|
|
11
|
+
- **misc**: Support OpenAI tool calls.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### What's improved
|
|
19
|
+
|
|
20
|
+
- **misc**: Support OpenAI tool calls ([9681fdc](https://github.com/lobehub/lobe-chat/commit/9681fdc))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
### [Version 0.115.13](https://github.com/lobehub/lobe-chat/compare/v0.115.12...v0.115.13)
|
|
31
|
+
|
|
32
|
+
<sup>Released on **2023-12-26**</sup>
|
|
33
|
+
|
|
34
|
+
#### 🐛 Bug Fixes
|
|
35
|
+
|
|
36
|
+
- **misc**: Fix remove tts and translate not working.
|
|
37
|
+
|
|
38
|
+
<br/>
|
|
39
|
+
|
|
40
|
+
<details>
|
|
41
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
42
|
+
|
|
43
|
+
#### What's fixed
|
|
44
|
+
|
|
45
|
+
- **misc**: Fix remove tts and translate not working, closes [#818](https://github.com/lobehub/lobe-chat/issues/818) ([4a275e9](https://github.com/lobehub/lobe-chat/commit/4a275e9))
|
|
46
|
+
|
|
47
|
+
</details>
|
|
48
|
+
|
|
49
|
+
<div align="right">
|
|
50
|
+
|
|
51
|
+
[](#readme-top)
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
5
55
|
### [Version 0.115.12](https://github.com/lobehub/lobe-chat/compare/v0.115.11...v0.115.12)
|
|
6
56
|
|
|
7
57
|
<sup>Released on **2023-12-25**</sup>
|
package/README.md
CHANGED
|
@@ -36,6 +36,7 @@ Supports one-click free deployment of your private ChatGPT/LLM web application.
|
|
|
36
36
|
[![][share-whatsapp-shield]][share-whatsapp-link]
|
|
37
37
|
[![][share-reddit-shield]][share-reddit-link]
|
|
38
38
|
[![][share-weibo-shield]][share-weibo-link]
|
|
39
|
+
[![][share-mastodon-shield]][share-mastodon-link]
|
|
39
40
|
|
|
40
41
|
<sup>Pioneering the new age of thinking and creating. Built for you, the Super Individual.</sup>
|
|
41
42
|
|
|
@@ -206,14 +207,14 @@ Our marketplace is not just a showcase platform but also a collaborative space.
|
|
|
206
207
|
|
|
207
208
|
<!-- AGENT LIST -->
|
|
208
209
|
|
|
209
|
-
| Recent Submits
|
|
210
|
-
|
|
|
211
|
-
| [
|
|
212
|
-
| [
|
|
213
|
-
| [
|
|
214
|
-
| [
|
|
210
|
+
| Recent Submits | Description |
|
|
211
|
+
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
212
|
+
| [Academic Proofreading Expert](https://chat-preview.lobehub.com/market?agent=academic-paragraph-refiner)<br/><sup>By **[Feliks151450](https://github.com/Feliks151450)** on **2023-12-26**</sup> | Highly skilled in advanced research proofreading and language editing, specializing in multiple research fields and proficient in academic English.<br/>`proofreading` `writing` `research` |
|
|
213
|
+
| [Flutter Maestro](https://chat-preview.lobehub.com/market?agent=flutter-dev)<br/><sup>By **[kamaravichow](https://github.com/kamaravichow)** on **2023-12-25**</sup> | A developer expert in Flutter framework and Dart programming language.<br/>`flutter` `development` `dart` `programming` `widgets` |
|
|
214
|
+
| [Facebook Ads Expert](https://chat-preview.lobehub.com/market?agent=facebook-ads-expert)<br/><sup>By **[alissonryan](https://github.com/alissonryan)** on **2023-12-20**</sup> | Create a Facebook Ads with a expert<br/>`copywriting` `facebook-ads` `lead-generation` |
|
|
215
|
+
| [Dream Painter](https://chat-preview.lobehub.com/market?agent=dream-painter)<br/><sup>By **[ccdanpian](https://github.com/ccdanpian)** on **2023-12-19**</sup> | A dream artist who can bring your dreams into reality.<br/>`txt-2-img` `painter` |
|
|
215
216
|
|
|
216
|
-
> 📊 Total agents: [<kbd>**
|
|
217
|
+
> 📊 Total agents: [<kbd>**79**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
|
|
217
218
|
|
|
218
219
|
<!-- AGENT LIST -->
|
|
219
220
|
|
|
@@ -625,6 +626,8 @@ This project is [MIT](./LICENSE) licensed.
|
|
|
625
626
|
[pr-welcome-link]: https://github.com/lobehub/lobe-chat/pulls
|
|
626
627
|
[pr-welcome-shield]: https://img.shields.io/badge/🤯_pr_welcome-%E2%86%92-ffcb47?labelColor=black&style=for-the-badge
|
|
627
628
|
[profile-link]: https://github.com/lobehub
|
|
629
|
+
[share-mastodon-link]: https://mastodon.social/share?text=Check%20this%20GitHub%20repository%20out%20%F0%9F%A4%AF%20LobeChat%20-%20An%20open-source,%20extensible%20(Function%20Calling),%20high-performance%20chatbot%20framework.%20It%20supports%20one-click%20free%20deployment%20of%20your%20private%20ChatGPT/LLM%20web%20application.%20https://github.com/lobehub/lobe-chat%20#chatbot%20#chatGPT%20#openAI
|
|
630
|
+
[share-mastodon-shield]: https://img.shields.io/badge/-share%20on%20mastodon-black?labelColor=black&logo=mastodon&logoColor=white&style=flat-square
|
|
628
631
|
[share-reddit-link]: https://www.reddit.com/submit?title=Check%20this%20GitHub%20repository%20out%20%F0%9F%A4%AF%20LobeChat%20-%20An%20open-source%2C%20extensible%20%28Function%20Calling%29%2C%20high-performance%20chatbot%20framework.%20It%20supports%20one-click%20free%20deployment%20of%20your%20private%20ChatGPT%2FLLM%20web%20application.%20%23chatbot%20%23chatGPT%20%23openAI&url=https%3A%2F%2Fgithub.com%2Flobehub%2Flobe-chat
|
|
629
632
|
[share-reddit-shield]: https://img.shields.io/badge/-share%20on%20reddit-black?labelColor=black&logo=reddit&logoColor=white&style=flat-square
|
|
630
633
|
[share-telegram-link]: https://t.me/share/url"?text=Check%20this%20GitHub%20repository%20out%20%F0%9F%A4%AF%20LobeChat%20-%20An%20open-source%2C%20extensible%20%28Function%20Calling%29%2C%20high-performance%20chatbot%20framework.%20It%20supports%20one-click%20free%20deployment%20of%20your%20private%20ChatGPT%2FLLM%20web%20application.%20%23chatbot%20%23chatGPT%20%23openAI&url=https%3A%2F%2Fgithub.com%2Flobehub%2Flobe-chat
|
package/README.zh-CN.md
CHANGED
|
@@ -35,6 +35,7 @@ LobeChat 是开源的高性能聊天机器人框架,支持语音合成、多
|
|
|
35
35
|
[![][share-whatsapp-shield]][share-whatsapp-link]
|
|
36
36
|
[![][share-reddit-shield]][share-reddit-link]
|
|
37
37
|
[![][share-weibo-shield]][share-weibo-link]
|
|
38
|
+
[![][share-mastodon-shield]][share-mastodon-link]
|
|
38
39
|
|
|
39
40
|

|
|
40
41
|
|
|
@@ -183,14 +184,14 @@ LobeChat 的插件生态系统是其核心功能的重要扩展,它极大地
|
|
|
183
184
|
|
|
184
185
|
<!-- AGENT LIST -->
|
|
185
186
|
|
|
186
|
-
| 最近新增
|
|
187
|
-
|
|
|
188
|
-
| [
|
|
189
|
-
| [
|
|
190
|
-
| [
|
|
191
|
-
| [
|
|
187
|
+
| 最近新增 | 助手说明 |
|
|
188
|
+
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
|
|
189
|
+
| [学术润色专家](https://chat-preview.lobehub.com/market?agent=academic-paragraph-refiner)<br/><sup>By **[Feliks151450](https://github.com/Feliks151450)** on **2023-12-26**</sup> | 高级研究校对及语言编辑,专业于多个研究领域,精通学术英语。<br/>`校对` `写作` `研究` |
|
|
190
|
+
| [Flutter 开发专家](https://chat-preview.lobehub.com/market?agent=flutter-dev)<br/><sup>By **[kamaravichow](https://github.com/kamaravichow)** on **2023-12-25**</sup> | 一位精通 Flutter 框架和 Dart 编程语言的开发者<br/>`flutter` `development` `dart` `programming` `widgets` |
|
|
191
|
+
| [Facebook 广告专家](https://chat-preview.lobehub.com/market?agent=facebook-ads-expert)<br/><sup>By **[alissonryan](https://github.com/alissonryan)** on **2023-12-20**</sup> | 与专家一起创建 Facebook 广告<br/>`文案撰写` `facebook广告` `潜在客户生成` |
|
|
192
|
+
| [梦境画家](https://chat-preview.lobehub.com/market?agent=dream-painter)<br/><sup>By **[ccdanpian](https://github.com/ccdanpian)** on **2023-12-19**</sup> | 一位能将你的梦想变成现实的梦境艺术家。<br/>`txt-2-img` `painter` |
|
|
192
193
|
|
|
193
|
-
> 📊 Total agents: [<kbd>**
|
|
194
|
+
> 📊 Total agents: [<kbd>**79**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
|
|
194
195
|
|
|
195
196
|
<!-- AGENT LIST -->
|
|
196
197
|
|
|
@@ -597,6 +598,8 @@ This project is [MIT](./LICENSE) licensed.
|
|
|
597
598
|
[pr-welcome-link]: https://github.com/lobehub/lobe-chat/pulls
|
|
598
599
|
[pr-welcome-shield]: https://img.shields.io/badge/🤯_pr_welcome-%E2%86%92-ffcb47?labelColor=black&style=for-the-badge
|
|
599
600
|
[profile-link]: https://github.com/lobehub
|
|
601
|
+
[share-mastodon-link]: https://mastodon.social/share?text=Check%20this%20GitHub%20repository%20out%20%F0%9F%A4%AF%20LobeChat%20-%20An%20open-source,%20extensible%20(Function%20Calling),%20high-performance%20chatbot%20framework.%20It%20supports%20one-click%20free%20deployment%20of%20your%20private%20ChatGPT/LLM%20web%20application.%20https://github.com/lobehub/lobe-chat%20#chatbot%20#chatGPT%20#openAI
|
|
602
|
+
[share-mastodon-shield]: https://img.shields.io/badge/-share%20on%20mastodon-black?labelColor=black&logo=mastodon&logoColor=white&style=flat-square
|
|
600
603
|
[share-reddit-link]: https://www.reddit.com/submit?title=%E6%8E%A8%E8%8D%90%E4%B8%80%E4%B8%AA%20GitHub%20%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%20%F0%9F%A4%AF%20LobeChat%20-%20%E5%BC%80%E6%BA%90%E7%9A%84%E3%80%81%E5%8F%AF%E6%89%A9%E5%B1%95%E7%9A%84%EF%BC%88Function%20Calling%EF%BC%89%E9%AB%98%E6%80%A7%E8%83%BD%E8%81%8A%E5%A4%A9%E6%9C%BA%E5%99%A8%E4%BA%BA%E6%A1%86%E6%9E%B6%E3%80%82%0A%E5%AE%83%E6%94%AF%E6%8C%81%E4%B8%80%E9%94%AE%E5%85%8D%E8%B4%B9%E9%83%A8%E7%BD%B2%E7%A7%81%E4%BA%BA%20ChatGPT%2FLLM%20%E7%BD%91%E9%A1%B5%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%20%23chatbot%20%23chatGPT%20%23openAI&url=https%3A%2F%2Fgithub.com%2Flobehub%2Flobe-chat
|
|
601
604
|
[share-reddit-shield]: https://img.shields.io/badge/-share%20on%20reddit-black?labelColor=black&logo=reddit&logoColor=white&style=flat-square
|
|
602
605
|
[share-telegram-link]: https://t.me/share/url"?text=%E6%8E%A8%E8%8D%90%E4%B8%80%E4%B8%AA%20GitHub%20%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%20%F0%9F%A4%AF%20LobeChat%20-%20%E5%BC%80%E6%BA%90%E7%9A%84%E3%80%81%E5%8F%AF%E6%89%A9%E5%B1%95%E7%9A%84%EF%BC%88Function%20Calling%EF%BC%89%E9%AB%98%E6%80%A7%E8%83%BD%E8%81%8A%E5%A4%A9%E6%9C%BA%E5%99%A8%E4%BA%BA%E6%A1%86%E6%9E%B6%E3%80%82%0A%E5%AE%83%E6%94%AF%E6%8C%81%E4%B8%80%E9%94%AE%E5%85%8D%E8%B4%B9%E9%83%A8%E7%BD%B2%E7%A7%81%E4%BA%BA%20ChatGPT%2FLLM%20%E7%BD%91%E9%A1%B5%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%20%23chatbot%20%23chatGPT%20%23openAI&url=https%3A%2F%2Fgithub.com%2Flobehub%2Flobe-chat
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.116.0",
|
|
4
4
|
"description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
package/src/const/message.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export const LOADING_FLAT = '...';
|
|
2
2
|
|
|
3
|
-
//
|
|
4
|
-
export const FUNCTION_MESSAGE_FLAG = '{"
|
|
3
|
+
// start with this,it should be a function message
|
|
4
|
+
export const FUNCTION_MESSAGE_FLAG = '{"tool_calls"';
|
|
5
5
|
|
|
6
6
|
export const FUNCTION_LOADING = 'FUNCTION_LOADING';
|
|
@@ -9,6 +9,7 @@ import { nanoid } from '@/utils/uuid';
|
|
|
9
9
|
export interface CreateMessageParams
|
|
10
10
|
extends Partial<Omit<ChatMessage, 'content' | 'role'>>,
|
|
11
11
|
Pick<ChatMessage, 'content' | 'role'> {
|
|
12
|
+
fromModel?: string;
|
|
12
13
|
sessionId: string;
|
|
13
14
|
}
|
|
14
15
|
|
|
@@ -179,11 +180,7 @@ class _MessageModel extends BaseModel {
|
|
|
179
180
|
tts,
|
|
180
181
|
...item
|
|
181
182
|
}: DBModel<DB_Message>): ChatMessage => {
|
|
182
|
-
return {
|
|
183
|
-
...item,
|
|
184
|
-
extra: { fromModel: fromModel, translate: translate, tts: tts },
|
|
185
|
-
meta: {},
|
|
186
|
-
};
|
|
183
|
+
return { ...item, extra: { fromModel, translate, tts }, meta: {} };
|
|
187
184
|
};
|
|
188
185
|
}
|
|
189
186
|
|
|
@@ -24,7 +24,7 @@ export const DB_MessageSchema = z.object({
|
|
|
24
24
|
plugin: PluginSchema.optional(),
|
|
25
25
|
pluginState: z.any().optional(),
|
|
26
26
|
fromModel: z.string().optional(),
|
|
27
|
-
translate: TranslateSchema.optional().or(z.
|
|
27
|
+
translate: TranslateSchema.optional().or(z.literal(false)),
|
|
28
28
|
tts: z.any().optional(),
|
|
29
29
|
|
|
30
30
|
// foreign keys
|
|
@@ -57,7 +57,14 @@ describe('ChatService', () => {
|
|
|
57
57
|
|
|
58
58
|
expect(getChatCompletionSpy).toHaveBeenCalledWith(
|
|
59
59
|
expect.objectContaining({
|
|
60
|
-
|
|
60
|
+
tools: expect.arrayContaining([
|
|
61
|
+
{
|
|
62
|
+
type: 'function',
|
|
63
|
+
function: {
|
|
64
|
+
name: 'plugin1____api1',
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
]),
|
|
61
68
|
messages: expect.anything(),
|
|
62
69
|
}),
|
|
63
70
|
undefined,
|
|
@@ -77,7 +84,7 @@ describe('ChatService', () => {
|
|
|
77
84
|
|
|
78
85
|
expect(getChatCompletionSpy).toHaveBeenCalledWith(
|
|
79
86
|
expect.objectContaining({
|
|
80
|
-
|
|
87
|
+
tools: undefined,
|
|
81
88
|
model: modelInWhitelist,
|
|
82
89
|
}),
|
|
83
90
|
undefined,
|
|
@@ -307,14 +314,17 @@ describe('ChatService', () => {
|
|
|
307
314
|
{
|
|
308
315
|
model: 'gpt-3.5-turbo-1106',
|
|
309
316
|
top_p: 1,
|
|
310
|
-
|
|
317
|
+
tools: [
|
|
311
318
|
{
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
319
|
+
type: 'function',
|
|
320
|
+
function: {
|
|
321
|
+
description: 'Get data from users',
|
|
322
|
+
name: 'seo____getData',
|
|
323
|
+
parameters: {
|
|
324
|
+
properties: { keyword: { type: 'string' }, url: { type: 'string' } },
|
|
325
|
+
required: ['keyword', 'url'],
|
|
326
|
+
type: 'object',
|
|
327
|
+
},
|
|
318
328
|
},
|
|
319
329
|
},
|
|
320
330
|
],
|
|
@@ -411,14 +421,17 @@ Get data from users`,
|
|
|
411
421
|
{
|
|
412
422
|
model: 'gpt-3.5-turbo-1106',
|
|
413
423
|
top_p: 1,
|
|
414
|
-
|
|
424
|
+
tools: [
|
|
415
425
|
{
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
426
|
+
type: 'function',
|
|
427
|
+
function: {
|
|
428
|
+
description: 'Get data from users',
|
|
429
|
+
name: 'seo____getData',
|
|
430
|
+
parameters: {
|
|
431
|
+
properties: { keyword: { type: 'string' }, url: { type: 'string' } },
|
|
432
|
+
required: ['keyword', 'url'],
|
|
433
|
+
type: 'object',
|
|
434
|
+
},
|
|
422
435
|
},
|
|
423
436
|
},
|
|
424
437
|
],
|
|
@@ -509,50 +522,53 @@ Get data from users`,
|
|
|
509
522
|
{
|
|
510
523
|
model: 'gpt-3.5-turbo-1106',
|
|
511
524
|
top_p: 1,
|
|
512
|
-
|
|
525
|
+
tools: [
|
|
513
526
|
{
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
'
|
|
550
|
-
|
|
551
|
-
|
|
527
|
+
type: 'function',
|
|
528
|
+
function: {
|
|
529
|
+
description: 'Create images from a text-only prompt.',
|
|
530
|
+
name: 'dalle3____text2image____builtin',
|
|
531
|
+
parameters: {
|
|
532
|
+
properties: {
|
|
533
|
+
prompts: {
|
|
534
|
+
description:
|
|
535
|
+
"The user's original image description, potentially modified to abide by the dalle policies. If the user does not suggest a number of captions to create, create four of them. If creating multiple captions, make them as diverse as possible. If the user requested modifications to previous images, the captions should not simply be longer, but rather it should be refactored to integrate the suggestions into each of the captions. Generate no more than 4 images, even if the user requests more.",
|
|
536
|
+
items: { type: 'string' },
|
|
537
|
+
maxItems: 4,
|
|
538
|
+
minItems: 1,
|
|
539
|
+
type: 'array',
|
|
540
|
+
},
|
|
541
|
+
quality: {
|
|
542
|
+
default: 'standard',
|
|
543
|
+
description:
|
|
544
|
+
'The quality of the image that will be generated. hd creates images with finer details and greater consistency across the image.',
|
|
545
|
+
enum: ['standard', 'hd'],
|
|
546
|
+
type: 'string',
|
|
547
|
+
},
|
|
548
|
+
seeds: {
|
|
549
|
+
description:
|
|
550
|
+
'A list of seeds to use for each prompt. If the user asks to modify a previous image, populate this field with the seed used to generate that image from the image dalle metadata.',
|
|
551
|
+
items: { type: 'integer' },
|
|
552
|
+
type: 'array',
|
|
553
|
+
},
|
|
554
|
+
size: {
|
|
555
|
+
default: '1024x1024',
|
|
556
|
+
description:
|
|
557
|
+
'The resolution of the requested image, which can be wide, square, or tall. Use 1024x1024 (square) as the default unless the prompt suggests a wide image, 1792x1024, or a full-body portrait, in which case 1024x1792 (tall) should be used instead. Always include this parameter in the request.',
|
|
558
|
+
enum: ['1792x1024', '1024x1024', '1024x1792'],
|
|
559
|
+
type: 'string',
|
|
560
|
+
},
|
|
561
|
+
style: {
|
|
562
|
+
default: 'vivid',
|
|
563
|
+
description:
|
|
564
|
+
'The style of the generated images. Must be one of vivid or natural. Vivid causes the model to lean towards generating hyper-real and dramatic images. Natural causes the model to produce more natural, less hyper-real looking images.',
|
|
565
|
+
enum: ['vivid', 'natural'],
|
|
566
|
+
type: 'string',
|
|
567
|
+
},
|
|
552
568
|
},
|
|
569
|
+
required: ['prompts'],
|
|
570
|
+
type: 'object',
|
|
553
571
|
},
|
|
554
|
-
required: ['prompts'],
|
|
555
|
-
type: 'object',
|
|
556
572
|
},
|
|
557
573
|
},
|
|
558
574
|
],
|
|
@@ -153,21 +153,6 @@ describe('MessageService', () => {
|
|
|
153
153
|
});
|
|
154
154
|
});
|
|
155
155
|
|
|
156
|
-
describe('updateMessageContent', () => {
|
|
157
|
-
it('should update the content of a message', async () => {
|
|
158
|
-
// Setup
|
|
159
|
-
const newContent = 'Updated message content';
|
|
160
|
-
(MessageModel.update as Mock).mockResolvedValue({ ...mockMessage, content: newContent });
|
|
161
|
-
|
|
162
|
-
// Execute
|
|
163
|
-
const result = await messageService.updateMessageContent(mockMessageId, newContent);
|
|
164
|
-
|
|
165
|
-
// Assert
|
|
166
|
-
expect(MessageModel.update).toHaveBeenCalledWith(mockMessageId, { content: newContent });
|
|
167
|
-
expect(result).toEqual({ ...mockMessage, content: newContent });
|
|
168
|
-
});
|
|
169
|
-
});
|
|
170
|
-
|
|
171
156
|
describe('removeMessages', () => {
|
|
172
157
|
it('should batch remove messages by assistantId and topicId', async () => {
|
|
173
158
|
// Setup
|
|
@@ -243,51 +228,6 @@ describe('MessageService', () => {
|
|
|
243
228
|
});
|
|
244
229
|
});
|
|
245
230
|
|
|
246
|
-
describe('updateMessageTranslate', () => {
|
|
247
|
-
it('should update the translate field of a message', async () => {
|
|
248
|
-
// Setup
|
|
249
|
-
const newTranslate = { content: 'Translated text', to: 'es' } as ChatTranslate;
|
|
250
|
-
(MessageModel.update as Mock).mockResolvedValue({ ...mockMessage, translate: newTranslate });
|
|
251
|
-
|
|
252
|
-
// Execute
|
|
253
|
-
const result = await messageService.updateMessageTranslate(mockMessageId, newTranslate);
|
|
254
|
-
|
|
255
|
-
// Assert
|
|
256
|
-
expect(MessageModel.update).toHaveBeenCalledWith(mockMessageId, { translate: newTranslate });
|
|
257
|
-
expect(result).toEqual({ ...mockMessage, translate: newTranslate });
|
|
258
|
-
});
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
describe('updateMessageTTS', () => {
|
|
262
|
-
it('should update the tts field of a message', async () => {
|
|
263
|
-
// Setup
|
|
264
|
-
const newTTS = { init: false } as ChatTTS;
|
|
265
|
-
(MessageModel.update as Mock).mockResolvedValue({ ...mockMessage, tts: newTTS });
|
|
266
|
-
|
|
267
|
-
// Execute
|
|
268
|
-
const result = await messageService.updateMessageTTS(mockMessageId, newTTS);
|
|
269
|
-
|
|
270
|
-
// Assert
|
|
271
|
-
expect(MessageModel.update).toHaveBeenCalledWith(mockMessageId, { tts: newTTS });
|
|
272
|
-
expect(result).toEqual({ ...mockMessage, tts: newTTS });
|
|
273
|
-
});
|
|
274
|
-
});
|
|
275
|
-
|
|
276
|
-
describe('updateMessageRole', () => {
|
|
277
|
-
it('should update the role of a message', async () => {
|
|
278
|
-
// Setup
|
|
279
|
-
const newRole = 'user';
|
|
280
|
-
(MessageModel.update as Mock).mockResolvedValue({ ...mockMessage, role: newRole });
|
|
281
|
-
|
|
282
|
-
// Execute
|
|
283
|
-
const result = await messageService.updateMessageRole(mockMessageId, newRole);
|
|
284
|
-
|
|
285
|
-
// Assert
|
|
286
|
-
expect(MessageModel.update).toHaveBeenCalledWith(mockMessageId, { role: newRole });
|
|
287
|
-
expect(result).toEqual({ ...mockMessage, role: newRole });
|
|
288
|
-
});
|
|
289
|
-
});
|
|
290
|
-
|
|
291
231
|
describe('updateMessagePlugin', () => {
|
|
292
232
|
it('should update the plugin payload of a message', async () => {
|
|
293
233
|
// Setup
|
package/src/services/chat.ts
CHANGED
|
@@ -55,10 +55,9 @@ class ChatService {
|
|
|
55
55
|
// 2. model is not in vision white list, because vision model can't use tools
|
|
56
56
|
// TODO: we need to find some method to let vision model use tools
|
|
57
57
|
const shouldUseTools = filterTools.length > 0 && !isVisionModel(payload.model);
|
|
58
|
+
const tools = shouldUseTools ? filterTools : undefined;
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
return this.getChatCompletion({ ...params, functions, messages: oaiMessages }, options);
|
|
60
|
+
return this.getChatCompletion({ ...params, messages: oaiMessages, tools }, options);
|
|
62
61
|
};
|
|
63
62
|
|
|
64
63
|
getChatCompletion = (params: Partial<OpenAIChatStreamPayload>, options?: FetchOptions) => {
|
package/src/services/message.ts
CHANGED
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
import { CreateMessageParams, MessageModel } from '@/database/models/message';
|
|
2
2
|
import { DB_Message } from '@/database/schemas/message';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
ChatMessage,
|
|
6
|
-
ChatMessageError,
|
|
7
|
-
ChatPluginPayload,
|
|
8
|
-
ChatTTS,
|
|
9
|
-
ChatTranslate,
|
|
10
|
-
} from '@/types/message';
|
|
3
|
+
import { ChatMessage, ChatMessageError, ChatPluginPayload } from '@/types/message';
|
|
11
4
|
|
|
12
5
|
export class MessageService {
|
|
13
6
|
async create(data: CreateMessageParams) {
|
|
@@ -37,22 +30,10 @@ export class MessageService {
|
|
|
37
30
|
return MessageModel.queryBySessionId(sessionId);
|
|
38
31
|
}
|
|
39
32
|
|
|
40
|
-
async updateMessageContent(id: string, content: string) {
|
|
41
|
-
return MessageModel.update(id, { content });
|
|
42
|
-
}
|
|
43
|
-
|
|
44
33
|
async updateMessageError(id: string, error: ChatMessageError) {
|
|
45
34
|
return MessageModel.update(id, { error });
|
|
46
35
|
}
|
|
47
36
|
|
|
48
|
-
async updateMessageTranslate(id: string, data: Partial<ChatTranslate> | null) {
|
|
49
|
-
return MessageModel.update(id, { translate: data as ChatTranslate });
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
async updateMessageTTS(id: string, data: Partial<ChatTTS> | null) {
|
|
53
|
-
return MessageModel.update(id, { tts: data as ChatTTS });
|
|
54
|
-
}
|
|
55
|
-
|
|
56
37
|
async removeMessages(assistantId: string, topicId?: string) {
|
|
57
38
|
return MessageModel.batchDelete(assistantId, topicId);
|
|
58
39
|
}
|
|
@@ -69,10 +50,6 @@ export class MessageService {
|
|
|
69
50
|
return MessageModel.update(id, message);
|
|
70
51
|
}
|
|
71
52
|
|
|
72
|
-
async updateMessageRole(id: string, role: LLMRoleType) {
|
|
73
|
-
return MessageModel.update(id, { role });
|
|
74
|
-
}
|
|
75
|
-
|
|
76
53
|
async updateMessagePlugin(id: string, plugin: ChatPluginPayload) {
|
|
77
54
|
return MessageModel.update(id, { plugin });
|
|
78
55
|
}
|
|
@@ -12,7 +12,7 @@ import { useChatStore } from '../../store';
|
|
|
12
12
|
vi.mock('@/services/message', () => ({
|
|
13
13
|
messageService: {
|
|
14
14
|
updateMessageTTS: vi.fn(),
|
|
15
|
-
|
|
15
|
+
updateMessage: vi.fn(),
|
|
16
16
|
},
|
|
17
17
|
}));
|
|
18
18
|
|
|
@@ -59,7 +59,7 @@ describe('ChatEnhanceAction', () => {
|
|
|
59
59
|
await result.current.clearTTS(messageId);
|
|
60
60
|
});
|
|
61
61
|
|
|
62
|
-
expect(messageService.
|
|
62
|
+
expect(messageService.updateMessage).toHaveBeenCalledWith(messageId, { tts: false });
|
|
63
63
|
});
|
|
64
64
|
});
|
|
65
65
|
|
|
@@ -102,7 +102,7 @@ describe('ChatEnhanceAction', () => {
|
|
|
102
102
|
await result.current.translateMessage(messageId, targetLang);
|
|
103
103
|
});
|
|
104
104
|
|
|
105
|
-
expect(messageService.
|
|
105
|
+
expect(messageService.updateMessage).toHaveBeenCalled();
|
|
106
106
|
});
|
|
107
107
|
});
|
|
108
108
|
|
|
@@ -115,25 +115,7 @@ describe('ChatEnhanceAction', () => {
|
|
|
115
115
|
await result.current.clearTranslate(messageId);
|
|
116
116
|
});
|
|
117
117
|
|
|
118
|
-
expect(messageService.
|
|
119
|
-
});
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
describe('ttsMessage', () => {
|
|
123
|
-
it('should update TTS state for a message and refresh messages', async () => {
|
|
124
|
-
const { result } = renderHook(() => useChatStore());
|
|
125
|
-
const messageId = 'message-id';
|
|
126
|
-
const ttsState = {
|
|
127
|
-
contentMd5: 'some-md5',
|
|
128
|
-
file: 'path-to-tts-file',
|
|
129
|
-
voice: 'voice-type',
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
await act(async () => {
|
|
133
|
-
await result.current.ttsMessage(messageId, ttsState);
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
expect(messageService.updateMessageTTS).toHaveBeenCalledWith(messageId, ttsState);
|
|
118
|
+
expect(messageService.updateMessage).toHaveBeenCalledWith(messageId, { translate: false });
|
|
137
119
|
});
|
|
138
120
|
});
|
|
139
121
|
});
|
|
@@ -11,6 +11,7 @@ import { imageGenerationService } from '@/services/imageGeneration';
|
|
|
11
11
|
import { messageService } from '@/services/message';
|
|
12
12
|
import { chatSelectors } from '@/store/chat/selectors';
|
|
13
13
|
import { ChatStore } from '@/store/chat/store';
|
|
14
|
+
import { ChatTTS, ChatTranslate } from '@/types/message';
|
|
14
15
|
import { DallEImageItem } from '@/types/tool/dalle';
|
|
15
16
|
import { setNamespace } from '@/utils/storeDebug';
|
|
16
17
|
|
|
@@ -31,6 +32,8 @@ export interface ChatEnhanceAction {
|
|
|
31
32
|
state?: { contentMd5?: string; file?: string; voice?: string },
|
|
32
33
|
) => Promise<void>;
|
|
33
34
|
updateImageItem: (id: string, updater: (data: DallEImageItem[]) => void) => Promise<void>;
|
|
35
|
+
updateMessageTTS: (id: string, data: Partial<ChatTTS> | false) => Promise<void>;
|
|
36
|
+
updateMessageTranslate: (id: string, data: Partial<ChatTranslate> | false) => Promise<void>;
|
|
34
37
|
}
|
|
35
38
|
|
|
36
39
|
export const chatEnhance: StateCreator<
|
|
@@ -40,13 +43,11 @@ export const chatEnhance: StateCreator<
|
|
|
40
43
|
ChatEnhanceAction
|
|
41
44
|
> = (set, get) => ({
|
|
42
45
|
clearTTS: async (id) => {
|
|
43
|
-
await
|
|
44
|
-
await get().refreshMessages();
|
|
46
|
+
await get().updateMessageTTS(id, false);
|
|
45
47
|
},
|
|
46
48
|
|
|
47
49
|
clearTranslate: async (id) => {
|
|
48
|
-
await
|
|
49
|
-
await get().refreshMessages();
|
|
50
|
+
await get().updateMessageTranslate(id, false);
|
|
50
51
|
},
|
|
51
52
|
|
|
52
53
|
generateImageFromPrompts: async (items, messageId) => {
|
|
@@ -94,16 +95,14 @@ export const chatEnhance: StateCreator<
|
|
|
94
95
|
n('toggleDallEImageLoading'),
|
|
95
96
|
);
|
|
96
97
|
},
|
|
97
|
-
|
|
98
98
|
translateMessage: async (id, targetLang) => {
|
|
99
|
-
const { toggleChatLoading,
|
|
99
|
+
const { toggleChatLoading, updateMessageTranslate, dispatchMessage } = get();
|
|
100
100
|
|
|
101
101
|
const message = chatSelectors.getMessageById(id)(get());
|
|
102
102
|
if (!message) return;
|
|
103
103
|
|
|
104
104
|
// create translate extra
|
|
105
|
-
await
|
|
106
|
-
await refreshMessages();
|
|
105
|
+
await updateMessageTranslate(id, { content: '', from: '', to: targetLang });
|
|
107
106
|
|
|
108
107
|
toggleChatLoading(true, id, n('translateMessage(start)', { id }) as string);
|
|
109
108
|
|
|
@@ -118,8 +117,7 @@ export const chatEnhance: StateCreator<
|
|
|
118
117
|
.then(async (data) => {
|
|
119
118
|
if (data && supportLocales.includes(data)) from = data;
|
|
120
119
|
|
|
121
|
-
await
|
|
122
|
-
await refreshMessages();
|
|
120
|
+
await updateMessageTranslate(id, { content, from, to: targetLang });
|
|
123
121
|
});
|
|
124
122
|
|
|
125
123
|
// translate to target language
|
|
@@ -138,15 +136,13 @@ export const chatEnhance: StateCreator<
|
|
|
138
136
|
params: chainTranslate(message.content, targetLang),
|
|
139
137
|
});
|
|
140
138
|
|
|
141
|
-
await
|
|
142
|
-
await refreshMessages();
|
|
139
|
+
await updateMessageTranslate(id, { content, from, to: targetLang });
|
|
143
140
|
|
|
144
141
|
toggleChatLoading(false);
|
|
145
142
|
},
|
|
146
143
|
|
|
147
144
|
ttsMessage: async (id, state = {}) => {
|
|
148
|
-
await
|
|
149
|
-
await get().refreshMessages();
|
|
145
|
+
await get().updateMessageTTS(id, state);
|
|
150
146
|
},
|
|
151
147
|
|
|
152
148
|
updateImageItem: async (id, updater) => {
|
|
@@ -156,7 +152,15 @@ export const chatEnhance: StateCreator<
|
|
|
156
152
|
const data: DallEImageItem[] = JSON.parse(message.content);
|
|
157
153
|
|
|
158
154
|
const nextContent = produce(data, updater);
|
|
159
|
-
await
|
|
155
|
+
await get().updateMessageContent(id, JSON.stringify(nextContent));
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
updateMessageTTS: async (id, data) => {
|
|
159
|
+
await messageService.updateMessage(id, { tts: data as ChatTTS });
|
|
160
|
+
await get().refreshMessages();
|
|
161
|
+
},
|
|
162
|
+
updateMessageTranslate: async (id, data) => {
|
|
163
|
+
await messageService.updateMessage(id, { translate: data as ChatTranslate });
|
|
160
164
|
await get().refreshMessages();
|
|
161
165
|
},
|
|
162
166
|
});
|
|
@@ -20,7 +20,7 @@ vi.mock('@/services/message', () => ({
|
|
|
20
20
|
createAssistantMessage: vi.fn(() => Promise.resolve('content-content-content')),
|
|
21
21
|
removeMessages: vi.fn(() => Promise.resolve()),
|
|
22
22
|
create: vi.fn(() => Promise.resolve('new-message-id')),
|
|
23
|
-
|
|
23
|
+
updateMessage: vi.fn(),
|
|
24
24
|
clearAllMessage: vi.fn(() => Promise.resolve()),
|
|
25
25
|
},
|
|
26
26
|
}));
|
|
@@ -303,7 +303,7 @@ describe('chatMessage actions', () => {
|
|
|
303
303
|
await result.current.updateMessageContent(messageId, newContent);
|
|
304
304
|
});
|
|
305
305
|
|
|
306
|
-
expect(messageService.
|
|
306
|
+
expect(messageService.updateMessage).toHaveBeenCalledWith(messageId, { content: newContent });
|
|
307
307
|
});
|
|
308
308
|
|
|
309
309
|
it('should dispatch message update action', async () => {
|
|
@@ -204,7 +204,7 @@ export const chatMessage: StateCreator<
|
|
|
204
204
|
// refs: https://medium.com/@kyledeguzmanx/what-are-optimistic-updates-483662c3e171
|
|
205
205
|
dispatchMessage({ id, key: 'content', type: 'updateMessage', value: content });
|
|
206
206
|
|
|
207
|
-
await messageService.
|
|
207
|
+
await messageService.updateMessage(id, { content });
|
|
208
208
|
await refreshMessages();
|
|
209
209
|
},
|
|
210
210
|
useFetchMessages: (sessionId, activeTopicId) =>
|
|
@@ -265,7 +265,7 @@ export const chatMessage: StateCreator<
|
|
|
265
265
|
if (functionCallAtEnd) {
|
|
266
266
|
// create a new separate message and remove the function call from the prev message
|
|
267
267
|
|
|
268
|
-
await
|
|
268
|
+
await get().updateMessageContent(mid, content.replace(functionCallContent, ''));
|
|
269
269
|
|
|
270
270
|
const functionMessage: CreateMessageParams = {
|
|
271
271
|
role: 'function',
|
|
@@ -294,7 +294,7 @@ export const chatMessage: StateCreator<
|
|
|
294
294
|
set({ messages }, false, n(`dispatchMessage/${payload.type}`, payload));
|
|
295
295
|
},
|
|
296
296
|
fetchAIChatMessage: async (messages, assistantId) => {
|
|
297
|
-
const { toggleChatLoading, refreshMessages } = get();
|
|
297
|
+
const { toggleChatLoading, refreshMessages, updateMessageContent } = get();
|
|
298
298
|
|
|
299
299
|
const abortController = toggleChatLoading(
|
|
300
300
|
true,
|
|
@@ -369,14 +369,12 @@ export const chatMessage: StateCreator<
|
|
|
369
369
|
},
|
|
370
370
|
onFinish: async (content) => {
|
|
371
371
|
// update the content after fetch result
|
|
372
|
-
await
|
|
373
|
-
await refreshMessages();
|
|
372
|
+
await updateMessageContent(assistantId, content);
|
|
374
373
|
},
|
|
375
374
|
onMessageHandle: async (text) => {
|
|
376
375
|
output += text;
|
|
377
376
|
|
|
378
|
-
await
|
|
379
|
-
await refreshMessages();
|
|
377
|
+
await updateMessageContent(assistantId, output);
|
|
380
378
|
|
|
381
379
|
// is this message is just a function call
|
|
382
380
|
if (isFunctionMessageAtStart(output)) isFunctionCall = true;
|
|
@@ -58,7 +58,7 @@ describe('ChatPluginAction', () => {
|
|
|
58
58
|
});
|
|
59
59
|
|
|
60
60
|
// 验证 messageService.updateMessageContent 是否被正确调用
|
|
61
|
-
expect(messageService.
|
|
61
|
+
expect(messageService.updateMessage).toHaveBeenCalledWith(messageId, { content: newContent });
|
|
62
62
|
|
|
63
63
|
// 验证 refreshMessages 是否被调用
|
|
64
64
|
expect(result.current.refreshMessages).toHaveBeenCalled();
|
|
@@ -95,10 +95,9 @@ describe('ChatPluginAction', () => {
|
|
|
95
95
|
expect.any(String),
|
|
96
96
|
);
|
|
97
97
|
expect(chatService.runPluginApi).toHaveBeenCalledWith(pluginPayload, { signal: undefined });
|
|
98
|
-
expect(messageService.
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
);
|
|
98
|
+
expect(messageService.updateMessage).toHaveBeenCalledWith(messageId, {
|
|
99
|
+
content: pluginApiResponse,
|
|
100
|
+
});
|
|
102
101
|
expect(initialState.refreshMessages).toHaveBeenCalled();
|
|
103
102
|
expect(initialState.coreProcessMessage).toHaveBeenCalled();
|
|
104
103
|
expect(initialState.toggleChatLoading).toHaveBeenCalledWith(false);
|
|
@@ -140,7 +139,18 @@ describe('ChatPluginAction', () => {
|
|
|
140
139
|
describe('triggerFunctionCall', () => {
|
|
141
140
|
it('should trigger a function call and update the plugin message accordingly', async () => {
|
|
142
141
|
const messageId = 'message-id';
|
|
143
|
-
const messageContent =
|
|
142
|
+
const messageContent = JSON.stringify({
|
|
143
|
+
tool_calls: [
|
|
144
|
+
{
|
|
145
|
+
id: 'call_sbca',
|
|
146
|
+
type: 'function',
|
|
147
|
+
function: {
|
|
148
|
+
name: `pluginName${PLUGIN_SCHEMA_SEPARATOR}apiName`,
|
|
149
|
+
arguments: { key: 'value' },
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
],
|
|
153
|
+
});
|
|
144
154
|
const messagePluginPayload = {
|
|
145
155
|
apiName: 'apiName',
|
|
146
156
|
identifier: 'pluginName',
|
|
@@ -184,7 +194,16 @@ describe('ChatPluginAction', () => {
|
|
|
184
194
|
const id = 'pluginIdentifier';
|
|
185
195
|
const md5ApiName = PLUGIN_SCHEMA_API_MD5_PREFIX + Md5.hashStr(apiName).toString();
|
|
186
196
|
const messageContent = JSON.stringify({
|
|
187
|
-
|
|
197
|
+
tool_calls: [
|
|
198
|
+
{
|
|
199
|
+
id: 'call_sbca',
|
|
200
|
+
type: 'function',
|
|
201
|
+
function: {
|
|
202
|
+
name: id + PLUGIN_SCHEMA_SEPARATOR + md5ApiName,
|
|
203
|
+
arguments: {},
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
],
|
|
188
207
|
});
|
|
189
208
|
|
|
190
209
|
const plugin = { identifier: id, manifest: { api: [{ name: apiName }] } } as LobeTool;
|
|
@@ -223,10 +242,15 @@ describe('ChatPluginAction', () => {
|
|
|
223
242
|
it('should handle standalone plugin type', async () => {
|
|
224
243
|
const messageId = 'message-id';
|
|
225
244
|
const messageContent = JSON.stringify({
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
245
|
+
tool_calls: [
|
|
246
|
+
{
|
|
247
|
+
id: 'call_scv',
|
|
248
|
+
function: {
|
|
249
|
+
name: `pluginName${PLUGIN_SCHEMA_SEPARATOR}apiName${PLUGIN_SCHEMA_SEPARATOR}standalone`,
|
|
250
|
+
arguments: {},
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
],
|
|
230
254
|
});
|
|
231
255
|
|
|
232
256
|
useChatStore.setState({
|
|
@@ -8,7 +8,7 @@ import { ChatStore } from '@/store/chat/store';
|
|
|
8
8
|
import { useToolStore } from '@/store/tool';
|
|
9
9
|
import { pluginSelectors } from '@/store/tool/selectors';
|
|
10
10
|
import { ChatPluginPayload } from '@/types/message';
|
|
11
|
-
import {
|
|
11
|
+
import { OpenAIToolCall } from '@/types/openai/functionCall';
|
|
12
12
|
import { setNamespace } from '@/utils/storeDebug';
|
|
13
13
|
|
|
14
14
|
import { chatSelectors } from '../../selectors';
|
|
@@ -30,24 +30,22 @@ export const chatPlugin: StateCreator<
|
|
|
30
30
|
ChatPluginAction
|
|
31
31
|
> = (set, get) => ({
|
|
32
32
|
fillPluginMessageContent: async (id, content) => {
|
|
33
|
-
const { coreProcessMessage,
|
|
33
|
+
const { coreProcessMessage, updateMessageContent } = get();
|
|
34
34
|
|
|
35
|
-
await
|
|
36
|
-
await refreshMessages();
|
|
35
|
+
await updateMessageContent(id, content);
|
|
37
36
|
|
|
38
37
|
const chats = chatSelectors.currentChats(get());
|
|
39
38
|
await coreProcessMessage(chats, id);
|
|
40
39
|
},
|
|
41
40
|
invokeBuiltinTool: async (id, payload) => {
|
|
42
|
-
const { toggleChatLoading,
|
|
41
|
+
const { toggleChatLoading, updateMessageContent } = get();
|
|
43
42
|
const params = JSON.parse(payload.arguments);
|
|
44
43
|
toggleChatLoading(true, id, n('invokeBuiltinTool') as string);
|
|
45
44
|
const data = await useToolStore.getState().invokeBuiltinTool(payload.apiName, params);
|
|
46
45
|
toggleChatLoading(false);
|
|
47
46
|
|
|
48
47
|
if (data) {
|
|
49
|
-
await
|
|
50
|
-
await refreshMessages();
|
|
48
|
+
await updateMessageContent(id, data);
|
|
51
49
|
}
|
|
52
50
|
|
|
53
51
|
// postToolCalling
|
|
@@ -58,7 +56,7 @@ export const chatPlugin: StateCreator<
|
|
|
58
56
|
await action(id, JSON.parse(data));
|
|
59
57
|
},
|
|
60
58
|
invokeDefaultTypePlugin: async (id, payload) => {
|
|
61
|
-
const { refreshMessages, coreProcessMessage, toggleChatLoading } = get();
|
|
59
|
+
const { updateMessageContent, refreshMessages, coreProcessMessage, toggleChatLoading } = get();
|
|
62
60
|
let data: string;
|
|
63
61
|
|
|
64
62
|
try {
|
|
@@ -79,27 +77,28 @@ export const chatPlugin: StateCreator<
|
|
|
79
77
|
// 如果报错则结束了
|
|
80
78
|
if (!data) return;
|
|
81
79
|
|
|
82
|
-
await
|
|
83
|
-
await refreshMessages();
|
|
80
|
+
await updateMessageContent(id, data);
|
|
84
81
|
|
|
85
82
|
const chats = chatSelectors.currentChats(get());
|
|
86
83
|
await coreProcessMessage(chats, id);
|
|
87
84
|
},
|
|
88
85
|
triggerFunctionCall: async (id) => {
|
|
89
|
-
const { invokeDefaultTypePlugin, invokeBuiltinTool, refreshMessages } = get();
|
|
90
|
-
|
|
91
86
|
const message = chatSelectors.getMessageById(id)(get());
|
|
92
87
|
if (!message) return;
|
|
93
88
|
|
|
89
|
+
const { invokeDefaultTypePlugin, invokeBuiltinTool, refreshMessages } = get();
|
|
90
|
+
|
|
94
91
|
let payload = { apiName: '', identifier: '' } as ChatPluginPayload;
|
|
95
92
|
|
|
96
93
|
// 识别到内容是 function_call 的情况下
|
|
97
94
|
// 将 function_call 转换为 plugin request payload
|
|
98
95
|
if (message.content) {
|
|
99
|
-
const {
|
|
100
|
-
|
|
96
|
+
const { tool_calls } = JSON.parse(message.content) as {
|
|
97
|
+
tool_calls: OpenAIToolCall[];
|
|
101
98
|
};
|
|
102
99
|
|
|
100
|
+
const function_call = tool_calls[0].function;
|
|
101
|
+
|
|
103
102
|
const [identifier, apiName, type] = function_call.name.split(PLUGIN_SCHEMA_SEPARATOR);
|
|
104
103
|
|
|
105
104
|
payload = {
|
|
@@ -145,6 +144,7 @@ export const chatPlugin: StateCreator<
|
|
|
145
144
|
}
|
|
146
145
|
}
|
|
147
146
|
},
|
|
147
|
+
|
|
148
148
|
updatePluginState: async (id, key, value) => {
|
|
149
149
|
const { refreshMessages } = get();
|
|
150
150
|
|
|
@@ -61,7 +61,20 @@ describe('toolSelectors', () => {
|
|
|
61
61
|
describe('enabledSchema', () => {
|
|
62
62
|
it('enabledSchema should return correct ChatCompletionFunctions array', () => {
|
|
63
63
|
const result = toolSelectors.enabledSchema(['plugin-1', 'plugin-2'])(mockState);
|
|
64
|
-
expect(result).toEqual([
|
|
64
|
+
expect(result).toEqual([
|
|
65
|
+
{
|
|
66
|
+
type: 'function',
|
|
67
|
+
function: {
|
|
68
|
+
name: 'plugin-1____api-1',
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
type: 'function',
|
|
73
|
+
function: {
|
|
74
|
+
name: 'plugin-2____api-2',
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
]);
|
|
65
78
|
});
|
|
66
79
|
|
|
67
80
|
it('enabledSchema should return with standalone plugin', () => {
|
|
@@ -80,7 +93,14 @@ describe('toolSelectors', () => {
|
|
|
80
93
|
},
|
|
81
94
|
],
|
|
82
95
|
} as ToolStoreState);
|
|
83
|
-
expect(result).toEqual([
|
|
96
|
+
expect(result).toEqual([
|
|
97
|
+
{
|
|
98
|
+
type: 'function',
|
|
99
|
+
function: {
|
|
100
|
+
name: 'plugin-4____api-4____standalone',
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
]);
|
|
84
104
|
});
|
|
85
105
|
|
|
86
106
|
it('enabledSchema should return md5 hash apiName', () => {
|
|
@@ -99,7 +119,12 @@ describe('toolSelectors', () => {
|
|
|
99
119
|
],
|
|
100
120
|
} as ToolStoreState);
|
|
101
121
|
expect(result).toEqual([
|
|
102
|
-
{
|
|
122
|
+
{
|
|
123
|
+
type: 'function',
|
|
124
|
+
function: {
|
|
125
|
+
name: 'long-long-plugin-with-id____MD5HASH_396eae4c671da3fb642c49ad2b9e8790',
|
|
126
|
+
},
|
|
127
|
+
},
|
|
103
128
|
]);
|
|
104
129
|
});
|
|
105
130
|
|
|
@@ -4,7 +4,7 @@ import { Md5 } from 'ts-md5';
|
|
|
4
4
|
|
|
5
5
|
import { PLUGIN_SCHEMA_API_MD5_PREFIX, PLUGIN_SCHEMA_SEPARATOR } from '@/const/plugin';
|
|
6
6
|
import { MetaData } from '@/types/meta';
|
|
7
|
-
import {
|
|
7
|
+
import { ChatCompletionTool } from '@/types/openai/chat';
|
|
8
8
|
import { LobeToolMeta } from '@/types/tool/tool';
|
|
9
9
|
|
|
10
10
|
import { pluginHelpers } from '../helpers';
|
|
@@ -32,7 +32,7 @@ const getAPIName = (identifier: string, name: string, type?: string) => {
|
|
|
32
32
|
|
|
33
33
|
const enabledSchema =
|
|
34
34
|
(tools: string[] = []) =>
|
|
35
|
-
(s: ToolStoreState):
|
|
35
|
+
(s: ToolStoreState): ChatCompletionTool[] => {
|
|
36
36
|
const list = pluginSelectors
|
|
37
37
|
.installedPluginManifestList(s)
|
|
38
38
|
.concat(s.builtinTools.map((b) => b.manifest as LobeChatPluginManifest))
|
|
@@ -45,7 +45,7 @@ const enabledSchema =
|
|
|
45
45
|
})),
|
|
46
46
|
);
|
|
47
47
|
|
|
48
|
-
return uniqBy(list, 'name');
|
|
48
|
+
return uniqBy(list, 'name').map((i) => ({ function: i, type: 'function' }));
|
|
49
49
|
};
|
|
50
50
|
|
|
51
51
|
const enabledSystemRoles =
|
|
@@ -3,6 +3,7 @@ import { Translate } from '@/types/translate';
|
|
|
3
3
|
|
|
4
4
|
import { LLMRoleType } from '../llm';
|
|
5
5
|
import { BaseDataModel } from '../meta';
|
|
6
|
+
import { ChatPluginPayload } from './tools';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* 聊天消息错误对象
|
|
@@ -23,12 +24,7 @@ export interface ChatTTS {
|
|
|
23
24
|
voice?: string;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
export
|
|
27
|
-
apiName: string;
|
|
28
|
-
arguments: string;
|
|
29
|
-
identifier: string;
|
|
30
|
-
type: 'standalone' | 'default' | 'builtin';
|
|
31
|
-
}
|
|
27
|
+
export * from './tools';
|
|
32
28
|
|
|
33
29
|
export interface ChatMessage extends BaseDataModel {
|
|
34
30
|
content: string;
|
|
@@ -37,7 +33,7 @@ export interface ChatMessage extends BaseDataModel {
|
|
|
37
33
|
extra?: {
|
|
38
34
|
fromModel?: string;
|
|
39
35
|
// 翻译
|
|
40
|
-
translate?: ChatTranslate |
|
|
36
|
+
translate?: ChatTranslate | false;
|
|
41
37
|
// TTS
|
|
42
38
|
tts?: ChatTTS;
|
|
43
39
|
} & Record<string, any>;
|
|
@@ -45,8 +41,8 @@ export interface ChatMessage extends BaseDataModel {
|
|
|
45
41
|
files?: string[];
|
|
46
42
|
parentId?: string;
|
|
47
43
|
plugin?: ChatPluginPayload;
|
|
48
|
-
|
|
49
44
|
pluginState?: any;
|
|
45
|
+
|
|
50
46
|
// 引用
|
|
51
47
|
quotaId?: string;
|
|
52
48
|
/**
|
package/src/types/openai/chat.ts
CHANGED
|
@@ -46,6 +46,9 @@ export interface OpenAIChatStreamPayload {
|
|
|
46
46
|
* @default 0
|
|
47
47
|
*/
|
|
48
48
|
frequency_penalty?: number;
|
|
49
|
+
/**
|
|
50
|
+
* @deprecated
|
|
51
|
+
*/
|
|
49
52
|
functions?: ChatCompletionFunctions[];
|
|
50
53
|
/**
|
|
51
54
|
* @title 生成文本的最大长度
|
|
@@ -82,7 +85,8 @@ export interface OpenAIChatStreamPayload {
|
|
|
82
85
|
* @default 0.5
|
|
83
86
|
*/
|
|
84
87
|
temperature: number;
|
|
85
|
-
|
|
88
|
+
tool_choice?: string;
|
|
89
|
+
tools?: ChatCompletionTool[];
|
|
86
90
|
/**
|
|
87
91
|
* @title 控制生成文本中最高概率的单个令牌
|
|
88
92
|
* @default 1
|
|
@@ -112,3 +116,12 @@ export interface ChatCompletionFunctions {
|
|
|
112
116
|
[key: string]: any;
|
|
113
117
|
};
|
|
114
118
|
}
|
|
119
|
+
|
|
120
|
+
export interface ChatCompletionTool {
|
|
121
|
+
function: ChatCompletionFunctions;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* The type of the tool. Currently, only `function` is supported.
|
|
125
|
+
*/
|
|
126
|
+
type: 'function';
|
|
127
|
+
}
|