@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 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
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#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
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#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 | Description |
210
- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
211
- | [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` |
212
- | [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` |
213
- | [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` |
214
- | [News Hub](https://chat-preview.lobehub.com/market?agent=news-hub)<br/><sup>By **[ccdanpian](https://github.com/ccdanpian)** on **2023-12-19**</sup> | News Search Assistant, proficient in locating and presenting relevant news based on user requests. Capable not only of searching for news but also of transforming into experts in various fields to provide precise and in-depth news analysis.<br/>`news` `search` `helper` |
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>**78**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
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
  ![](https://gw.alipayobjects.com/zos/kitchen/RKnWrrfuMl/welcome.webp)
40
41
 
@@ -183,14 +184,14 @@ LobeChat 的插件生态系统是其核心功能的重要扩展,它极大地
183
184
 
184
185
  <!-- AGENT LIST -->
185
186
 
186
- | 最近新增 | 助手说明 |
187
- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
188
- | [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` |
189
- | [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广告` `潜在客户生成` |
190
- | [梦境画家](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` |
191
- | [新闻搜索助手](https://chat-preview.lobehub.com/market?agent=news-hub)<br/><sup>By **[ccdanpian](https://github.com/ccdanpian)** on **2023-12-19**</sup> | 新闻搜索助手,精通根据用户需求查找和呈现相关新闻。不仅能够搜索新闻,还可以根据用户的要求转变为不同领域的专家,提供精确深入的新闻解读<br/>`新闻` `搜索` `助手` |
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>**78**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
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.115.12",
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",
@@ -1,6 +1,6 @@
1
1
  export const LOADING_FLAT = '...';
2
2
 
3
- // 只要 start with 这个,就可以判断为 function message
4
- export const FUNCTION_MESSAGE_FLAG = '{"function';
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.null()),
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
- functions: expect.arrayContaining([{ name: 'plugin1____api1' }]),
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
- functions: undefined,
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
- functions: [
317
+ tools: [
311
318
  {
312
- description: 'Get data from users',
313
- name: 'seo____getData',
314
- parameters: {
315
- properties: { keyword: { type: 'string' }, url: { type: 'string' } },
316
- required: ['keyword', 'url'],
317
- type: 'object',
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
- functions: [
424
+ tools: [
415
425
  {
416
- description: 'Get data from users',
417
- name: 'seo____getData',
418
- parameters: {
419
- properties: { keyword: { type: 'string' }, url: { type: 'string' } },
420
- required: ['keyword', 'url'],
421
- type: 'object',
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
- functions: [
525
+ tools: [
513
526
  {
514
- description: 'Create images from a text-only prompt.',
515
- name: 'dalle3____text2image____builtin',
516
- parameters: {
517
- properties: {
518
- prompts: {
519
- description:
520
- "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.",
521
- items: { type: 'string' },
522
- maxItems: 4,
523
- minItems: 1,
524
- type: 'array',
525
- },
526
- quality: {
527
- default: 'standard',
528
- description:
529
- 'The quality of the image that will be generated. hd creates images with finer details and greater consistency across the image.',
530
- enum: ['standard', 'hd'],
531
- type: 'string',
532
- },
533
- seeds: {
534
- description:
535
- '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.',
536
- items: { type: 'integer' },
537
- type: 'array',
538
- },
539
- size: {
540
- default: '1024x1024',
541
- description:
542
- '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.',
543
- enum: ['1792x1024', '1024x1024', '1024x1792'],
544
- type: 'string',
545
- },
546
- style: {
547
- default: 'vivid',
548
- description:
549
- '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.',
550
- enum: ['vivid', 'natural'],
551
- type: 'string',
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
@@ -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
- const functions = shouldUseTools ? filterTools : undefined;
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) => {
@@ -1,13 +1,6 @@
1
1
  import { CreateMessageParams, MessageModel } from '@/database/models/message';
2
2
  import { DB_Message } from '@/database/schemas/message';
3
- import { LLMRoleType } from '@/types/llm';
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
- updateMessageTranslate: vi.fn(),
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.updateMessageTTS).toHaveBeenCalledWith(messageId, null);
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.updateMessageTranslate).toHaveBeenCalled();
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.updateMessageTranslate).toHaveBeenCalledWith(messageId, null);
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 messageService.updateMessageTTS(id, null);
44
- await get().refreshMessages();
46
+ await get().updateMessageTTS(id, false);
45
47
  },
46
48
 
47
49
  clearTranslate: async (id) => {
48
- await messageService.updateMessageTranslate(id, null);
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, dispatchMessage, refreshMessages } = get();
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 messageService.updateMessageTranslate(id, { content: '', from: '', to: targetLang });
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 messageService.updateMessageTranslate(id, { content, from, to: targetLang });
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 messageService.updateMessageTranslate(id, { content, from, to: targetLang });
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 messageService.updateMessageTTS(id, state);
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 messageService.updateMessageContent(id, JSON.stringify(nextContent));
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
- updateMessageContent: vi.fn(),
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.updateMessageContent).toHaveBeenCalledWith(messageId, newContent);
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.updateMessageContent(id, content);
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 messageService.updateMessageContent(mid, content.replace(functionCallContent, ''));
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 messageService.updateMessageContent(assistantId, content);
373
- await refreshMessages();
372
+ await updateMessageContent(assistantId, content);
374
373
  },
375
374
  onMessageHandle: async (text) => {
376
375
  output += text;
377
376
 
378
- await messageService.updateMessageContent(assistantId, output);
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.updateMessageContent).toHaveBeenCalledWith(messageId, newContent);
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.updateMessageContent).toHaveBeenCalledWith(
99
- messageId,
100
- pluginApiResponse,
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 = `{"function_call": {"name": "pluginName${PLUGIN_SCHEMA_SEPARATOR}apiName", "arguments": {"key": "value"}}}`;
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
- function_call: { name: id + PLUGIN_SCHEMA_SEPARATOR + md5ApiName, arguments: {} },
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
- function_call: {
227
- name: `pluginName${PLUGIN_SCHEMA_SEPARATOR}apiName${PLUGIN_SCHEMA_SEPARATOR}standalone`,
228
- arguments: {},
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 { OpenAIFunctionCall } from '@/types/openai/functionCall';
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, refreshMessages } = get();
33
+ const { coreProcessMessage, updateMessageContent } = get();
34
34
 
35
- await messageService.updateMessageContent(id, content);
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, refreshMessages } = get();
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 messageService.updateMessageContent(id, data);
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 messageService.updateMessageContent(id, data);
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 { function_call } = JSON.parse(message.content) as {
100
- function_call: OpenAIFunctionCall;
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([{ name: 'plugin-1____api-1' }, { name: 'plugin-2____api-2' }]);
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([{ name: 'plugin-4____api-4____standalone' }]);
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
- { name: 'long-long-plugin-with-id____MD5HASH_396eae4c671da3fb642c49ad2b9e8790' },
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 { ChatCompletionFunctions } from '@/types/openai/chat';
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): ChatCompletionFunctions[] => {
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 interface ChatPluginPayload {
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 | null;
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
  /**
@@ -0,0 +1,6 @@
1
+ export interface ChatPluginPayload {
2
+ apiName: string;
3
+ arguments: string;
4
+ identifier: string;
5
+ type: 'standalone' | 'default' | 'builtin';
6
+ }
@@ -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
+ }
@@ -2,3 +2,9 @@ export interface OpenAIFunctionCall {
2
2
  arguments: string;
3
3
  name: string;
4
4
  }
5
+
6
+ export interface OpenAIToolCall {
7
+ function: OpenAIFunctionCall;
8
+ id: string;
9
+ type: 'function';
10
+ }