@lobehub/chat 1.19.35 → 1.20.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 1.20.0](https://github.com/lobehub/lobe-chat/compare/v1.19.36...v1.20.0)
6
+
7
+ <sup>Released on **2024-09-27**</sup>
8
+
9
+ #### ✨ Features
10
+
11
+ - **misc**: Add Hunyuan(Tencent) model provider.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### What's improved
19
+
20
+ - **misc**: Add Hunyuan(Tencent) model provider, closes [#4147](https://github.com/lobehub/lobe-chat/issues/4147) ([8ddb41b](https://github.com/lobehub/lobe-chat/commit/8ddb41b))
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 1.19.36](https://github.com/lobehub/lobe-chat/compare/v1.19.35...v1.19.36)
31
+
32
+ <sup>Released on **2024-09-27**</sup>
33
+
34
+ #### 💄 Styles
35
+
36
+ - **misc**: Add llama3.2 model for openrouter provider.
37
+
38
+ <br/>
39
+
40
+ <details>
41
+ <summary><kbd>Improvements and Fixes</kbd></summary>
42
+
43
+ #### Styles
44
+
45
+ - **misc**: Add llama3.2 model for openrouter provider, closes [#4151](https://github.com/lobehub/lobe-chat/issues/4151) ([6f1a966](https://github.com/lobehub/lobe-chat/commit/6f1a966))
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 1.19.35](https://github.com/lobehub/lobe-chat/compare/v1.19.34...v1.19.35)
6
56
 
7
57
  <sup>Released on **2024-09-27**</sup>
package/Dockerfile CHANGED
@@ -135,6 +135,8 @@ ENV \
135
135
  GOOGLE_API_KEY="" GOOGLE_PROXY_URL="" \
136
136
  # Groq
137
137
  GROQ_API_KEY="" GROQ_MODEL_LIST="" GROQ_PROXY_URL="" \
138
+ # Hunyuan
139
+ HUNYUAN_API_KEY="" HUNYUAN_MODEL_LIST="" \
138
140
  # Minimax
139
141
  MINIMAX_API_KEY="" \
140
142
  # Mistral
@@ -167,6 +167,8 @@ ENV \
167
167
  GOOGLE_API_KEY="" GOOGLE_PROXY_URL="" \
168
168
  # Groq
169
169
  GROQ_API_KEY="" GROQ_MODEL_LIST="" GROQ_PROXY_URL="" \
170
+ # Hunyuan
171
+ HUNYUAN_API_KEY="" HUNYUAN_MODEL_LIST="" \
170
172
  # Minimax
171
173
  MINIMAX_API_KEY="" \
172
174
  # Mistral
package/README.md CHANGED
@@ -253,7 +253,7 @@ In addition, these plugins are not limited to news aggregation, but can also ext
253
253
  | [Savvy Trader AI](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **savvytrader** on **2024-06-27**</sup> | Realtime stock, crypto and other investment data.<br/>`stock` `analyze` |
254
254
  | [Search1API](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **fatwang2** on **2024-05-06**</sup> | Search aggregation service, specifically designed for LLMs<br/>`web` `search` |
255
255
 
256
- > 📊 Total plugins: [<kbd>**50**</kbd>](https://github.com/lobehub/lobe-chat-plugins)
256
+ > 📊 Total plugins: [<kbd>**49**</kbd>](https://github.com/lobehub/lobe-chat-plugins)
257
257
 
258
258
  <!-- PLUGIN LIST -->
259
259
 
package/README.zh-CN.md CHANGED
@@ -245,7 +245,7 @@ LobeChat 的插件生态系统是其核心功能的重要扩展,它极大地
245
245
  | [Savvy Trader AI](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **savvytrader** on **2024-06-27**</sup> | 实时股票、加密货币和其他投资数据。<br/>`股票` `分析` |
246
246
  | [Search1API](https://chat-preview.lobehub.com/settings/agent)<br/><sup>By **fatwang2** on **2024-05-06**</sup> | 搜索聚合服务,专为 LLMs 设计<br/>`web` `search` |
247
247
 
248
- > 📊 Total plugins: [<kbd>**50**</kbd>](https://github.com/lobehub/lobe-chat-plugins)
248
+ > 📊 Total plugins: [<kbd>**49**</kbd>](https://github.com/lobehub/lobe-chat-plugins)
249
249
 
250
250
  <!-- PLUGIN LIST -->
251
251
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "1.19.35",
3
+ "version": "1.20.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",
@@ -9,6 +9,7 @@ import {
9
9
  FireworksAIProviderCard,
10
10
  GoogleProviderCard,
11
11
  GroqProviderCard,
12
+ HunyuanProviderCard,
12
13
  MinimaxProviderCard,
13
14
  MistralProviderCard,
14
15
  MoonshotProviderCard,
@@ -60,6 +61,7 @@ export const useProviderList = (): ProviderItem[] => {
60
61
  Ai21ProviderCard,
61
62
  UpstageProviderCard,
62
63
  QwenProviderCard,
64
+ HunyuanProviderCard,
63
65
  SparkProviderCard,
64
66
  ZhiPuProviderCard,
65
67
  ZeroOneProviderCard,
@@ -244,6 +244,13 @@ const getLlmOptionsFromPayload = (provider: string, payload: JWTPayload) => {
244
244
 
245
245
  const apiKey = apiKeyManager.pick(payload?.apiKey || AI21_API_KEY);
246
246
 
247
+ return { apiKey };
248
+ }
249
+ case ModelProvider.Hunyuan: {
250
+ const { HUNYUAN_API_KEY } = getLLMConfig();
251
+
252
+ const apiKey = apiKeyManager.pick(payload?.apiKey || HUNYUAN_API_KEY);
253
+
247
254
  return { apiKey };
248
255
  }
249
256
  }
package/src/config/llm.ts CHANGED
@@ -117,6 +117,10 @@ export const getLLMConfig = () => {
117
117
 
118
118
  ENABLED_AI21: z.boolean(),
119
119
  AI21_API_KEY: z.string().optional(),
120
+
121
+ ENABLED_HUNYUAN: z.boolean(),
122
+ HUNYUAN_API_KEY: z.string().optional(),
123
+ HUNYUAN_MODEL_LIST: z.string().optional(),
120
124
  },
121
125
  runtimeEnv: {
122
126
  API_KEY_SELECT_MODE: process.env.API_KEY_SELECT_MODE,
@@ -231,6 +235,10 @@ export const getLLMConfig = () => {
231
235
 
232
236
  ENABLED_AI21: !!process.env.AI21_API_KEY,
233
237
  AI21_API_KEY: process.env.AI21_API_KEY,
238
+
239
+ ENABLED_HUNYUAN: !!process.env.HUNYUAN_API_KEY,
240
+ HUNYUAN_API_KEY: process.env.HUNYUAN_API_KEY,
241
+ HUNYUAN_MODEL_LIST: process.env.HUNYUAN_MODEL_LIST,
234
242
  },
235
243
  });
236
244
  };
@@ -0,0 +1,137 @@
1
+ import { ModelProviderCard } from '@/types/llm';
2
+
3
+ // ref https://cloud.tencent.com/document/product/1729/104753
4
+ const Hunyuan: ModelProviderCard = {
5
+ chatModels: [
6
+ {
7
+ description: '升级为 MOE 结构,上下文窗口为 256k ,在 NLP,代码,数学,行业等多项评测集上领先众多开源模型。',
8
+ displayName: 'Hunyuan Lite',
9
+ enabled: true,
10
+ id: 'hunyuan-lite',
11
+ maxOutput: 6000,
12
+ pricing: {
13
+ currency: 'CNY',
14
+ input: 0,
15
+ output: 0,
16
+ },
17
+ tokens: 256_000,
18
+ },
19
+ {
20
+ description: '采用更优的路由策略,同时缓解了负载均衡和专家趋同的问题。长文方面,大海捞针指标达到99.9%。MOE-32K 性价比相对更高,在平衡效果、价格的同时,可对实现对长文本输入的处理。',
21
+ displayName: 'Hunyuan Standard',
22
+ enabled: true,
23
+ id: 'hunyuan-standard',
24
+ maxOutput: 2000,
25
+ pricing: {
26
+ currency: 'CNY',
27
+ input: 4.5,
28
+ output: 5,
29
+ },
30
+ tokens: 32_000,
31
+ },
32
+ {
33
+ description: '采用更优的路由策略,同时缓解了负载均衡和专家趋同的问题。长文方面,大海捞针指标达到99.9%。MOE-256K 在长度和效果上进一步突破,极大的扩展了可输入长度。',
34
+ displayName: 'Hunyuan Standard 256K',
35
+ enabled: true,
36
+ id: 'hunyuan-standard-256K',
37
+ maxOutput: 6000,
38
+ pricing: {
39
+ currency: 'CNY',
40
+ input: 15,
41
+ output: 60,
42
+ },
43
+ tokens: 256_000,
44
+ },
45
+ {
46
+ description: '混元全新一代大语言模型的预览版,采用全新的混合专家模型(MoE)结构,相比hunyuan-pro推理效率更快,效果表现更强。',
47
+ displayName: 'Hunyuan Turbo',
48
+ enabled: true,
49
+ functionCall: true,
50
+ id: 'hunyuan-turbo',
51
+ maxOutput: 4000,
52
+ pricing: {
53
+ currency: 'CNY',
54
+ input: 15,
55
+ output: 50,
56
+ },
57
+ tokens: 32_000,
58
+ },
59
+ {
60
+ description: '万亿级参数规模 MOE-32K 长文模型。在各种 benchmark 上达到绝对领先的水平,复杂指令和推理,具备复杂数学能力,支持 functioncall,在多语言翻译、金融法律医疗等领域应用重点优化。',
61
+ displayName: 'Hunyuan Pro',
62
+ enabled: true,
63
+ functionCall: true,
64
+ id: 'hunyuan-pro',
65
+ maxOutput: 4000,
66
+ pricing: {
67
+ currency: 'CNY',
68
+ input: 30,
69
+ output: 100,
70
+ },
71
+ tokens: 32_000,
72
+ },
73
+ {
74
+ description: '混元最新代码生成模型,经过 200B 高质量代码数据增训基座模型,迭代半年高质量 SFT 数据训练,上下文长窗口长度增大到 8K,五大语言代码生成自动评测指标上位居前列;五大语言10项考量各方面综合代码任务人工高质量评测上,性能处于第一梯队',
75
+ displayName: 'Hunyuan Code',
76
+ enabled: true,
77
+ id: 'hunyuan-code',
78
+ maxOutput: 4000,
79
+ pricing: {
80
+ currency: 'CNY',
81
+ input: 4,
82
+ output: 8,
83
+ },
84
+ tokens: 8000,
85
+ },
86
+ {
87
+ description: '混元最新多模态模型,支持图片+文本输入生成文本内容。',
88
+ displayName: 'Hunyuan Vision',
89
+ enabled: true,
90
+ id: 'hunyuan-vision',
91
+ maxOutput: 4000,
92
+ pricing: {
93
+ currency: 'CNY',
94
+ input: 18,
95
+ output: 18,
96
+ },
97
+ tokens: 8000,
98
+ vision: true,
99
+ },
100
+ {
101
+ description: '混元最新 MOE 架构 FunctionCall 模型,经过高质量的 FunctionCall 数据训练,上下文窗口达 32K,在多个维度的评测指标上处于领先。',
102
+ displayName: 'Hunyuan FunctionCall',
103
+ functionCall: true,
104
+ id: 'hunyuan-functioncall',
105
+ maxOutput: 4000,
106
+ pricing: {
107
+ currency: 'CNY',
108
+ input: 4,
109
+ output: 8,
110
+ },
111
+ tokens: 32_000,
112
+ },
113
+ {
114
+ description: '混元最新版角色扮演模型,混元官方精调训练推出的角色扮演模型,基于混元模型结合角色扮演场景数据集进行增训,在角色扮演场景具有更好的基础效果。',
115
+ displayName: 'Hunyuan Role',
116
+ id: 'hunyuan-role',
117
+ maxOutput: 4000,
118
+ pricing: {
119
+ currency: 'CNY',
120
+ input: 4,
121
+ output: 8,
122
+ },
123
+ tokens: 8000,
124
+ },
125
+ ],
126
+ checkModel: 'hunyuan-lite',
127
+ description:
128
+ '由腾讯研发的大语言模型,具备强大的中文创作能力,复杂语境下的逻辑推理能力,以及可靠的任务执行能力',
129
+ disableBrowserRequest: true,
130
+ id: 'hunyuan',
131
+ modelList: { showModelFetcher: true },
132
+ modelsUrl: 'https://cloud.tencent.com/document/product/1729/104753',
133
+ name: 'Hunyuan',
134
+ url: 'https://hunyuan.tencent.com',
135
+ };
136
+
137
+ export default Hunyuan;
@@ -11,6 +11,7 @@ import FireworksAIProvider from './fireworksai';
11
11
  import GithubProvider from './github';
12
12
  import GoogleProvider from './google';
13
13
  import GroqProvider from './groq';
14
+ import HunyuanProvider from './hunyuan';
14
15
  import MinimaxProvider from './minimax';
15
16
  import MistralProvider from './mistral';
16
17
  import MoonshotProvider from './moonshot';
@@ -57,6 +58,7 @@ export const LOBE_DEFAULT_MODEL_LIST: ChatModelCard[] = [
57
58
  UpstageProvider.chatModels,
58
59
  SparkProvider.chatModels,
59
60
  Ai21Provider.chatModels,
61
+ HunyuanProvider.chatModels,
60
62
  ].flat();
61
63
 
62
64
  export const DEFAULT_MODEL_PROVIDER_LIST = [
@@ -78,6 +80,7 @@ export const DEFAULT_MODEL_PROVIDER_LIST = [
78
80
  Ai21Provider,
79
81
  UpstageProvider,
80
82
  QwenProvider,
83
+ HunyuanProvider,
81
84
  SparkProvider,
82
85
  ZhiPuProvider,
83
86
  ZeroOneProvider,
@@ -110,6 +113,7 @@ export { default as FireworksAIProviderCard } from './fireworksai';
110
113
  export { default as GithubProviderCard } from './github';
111
114
  export { default as GoogleProviderCard } from './google';
112
115
  export { default as GroqProviderCard } from './groq';
116
+ export { default as HunyuanProviderCard } from './hunyuan';
113
117
  export { default as MinimaxProviderCard } from './minimax';
114
118
  export { default as MistralProviderCard } from './mistral';
115
119
  export { default as MoonshotProviderCard } from './moonshot';
@@ -79,8 +79,10 @@ const OpenRouter: ModelProviderCard = {
79
79
  id: 'anthropic/claude-3-haiku',
80
80
  maxOutput: 4096,
81
81
  pricing: {
82
+ cachedInput: 0.025,
82
83
  input: 0.25,
83
84
  output: 1.25,
85
+ writeCacheInput: 0.3125,
84
86
  },
85
87
  releasedAt: '2024-03-07',
86
88
  tokens: 200_000,
@@ -113,43 +115,41 @@ const OpenRouter: ModelProviderCard = {
113
115
  id: 'anthropic/claude-3-opus',
114
116
  maxOutput: 4096,
115
117
  pricing: {
118
+ cachedInput: 1.5,
116
119
  input: 15,
117
120
  output: 75,
121
+ writeCacheInput: 18.75,
118
122
  },
119
123
  releasedAt: '2024-02-29',
120
124
  tokens: 200_000,
121
125
  vision: true,
122
126
  },
123
127
  {
124
- description: 'Gemini 1.5 Flash 0827 提供了优化后的多模态处理能力,适用多种复杂任务场景。',
125
- displayName: 'Gemini 1.5 Flash 0827',
128
+ description: 'Gemini 1.5 Flash 提供了优化后的多模态处理能力,适用多种复杂任务场景。',
129
+ displayName: 'Gemini 1.5 Flash',
126
130
  enabled: true,
127
131
  functionCall: true,
128
- id: 'google/gemini-flash-1.5-exp',
132
+ id: 'google/gemini-flash-1.5',
129
133
  maxOutput: 8192,
130
134
  pricing: {
131
- cachedInput: 0.018_75,
132
135
  input: 0.075,
133
136
  output: 0.3,
134
137
  },
135
- releasedAt: '2024-08-27',
136
- tokens: 1_048_576 + 8192,
138
+ tokens: 1_000_000 + 8192,
137
139
  vision: true,
138
140
  },
139
141
  {
140
- description: 'Gemini 1.5 Pro 0827 结合最新优化技术,带来更高效的多模态数据处理能力。',
141
- displayName: 'Gemini 1.5 Pro 0827',
142
+ description: 'Gemini 1.5 Pro 结合最新优化技术,带来更高效的多模态数据处理能力。',
143
+ displayName: 'Gemini 1.5 Pro',
142
144
  enabled: true,
143
145
  functionCall: true,
144
- id: 'google/gemini-pro-1.5-exp',
146
+ id: 'google/gemini-pro-1.5',
145
147
  maxOutput: 8192,
146
148
  pricing: {
147
- cachedInput: 0.875,
148
149
  input: 3.5,
149
150
  output: 10.5,
150
151
  },
151
- releasedAt: '2024-08-27',
152
- tokens: 2_097_152 + 8192,
152
+ tokens: 2_000_000 + 8192,
153
153
  vision: true,
154
154
  },
155
155
  {
@@ -160,13 +160,36 @@ const OpenRouter: ModelProviderCard = {
160
160
  functionCall: true,
161
161
  id: 'deepseek/deepseek-chat',
162
162
  pricing: {
163
- cachedInput: 0.014,
164
163
  input: 0.14,
165
164
  output: 0.28,
166
165
  },
167
166
  releasedAt: '2024-09-05',
168
167
  tokens: 128_000,
169
168
  },
169
+ {
170
+ description: 'LLaMA 3.2 旨在处理结合视觉和文本数据的任务。它在图像描述和视觉问答等任务中表现出色,跨越了语言生成和视觉推理之间的鸿沟。',
171
+ displayName: 'Llama 3.2 11B Vision',
172
+ enabled: true,
173
+ id: 'meta-llama/llama-3.2-11b-vision-instruct',
174
+ pricing: {
175
+ input: 0.162,
176
+ output: 0.162,
177
+ },
178
+ tokens: 131_072,
179
+ vision: true,
180
+ },
181
+ {
182
+ description: 'LLaMA 3.2 旨在处理结合视觉和文本数据的任务。它在图像描述和视觉问答等任务中表现出色,跨越了语言生成和视觉推理之间的鸿沟。',
183
+ displayName: 'Llama 3.2 90B Vision',
184
+ enabled: true,
185
+ id: 'meta-llama/llama-3.2-90b-vision-instruct',
186
+ pricing: {
187
+ input: 0.4,
188
+ output: 0.4,
189
+ },
190
+ tokens: 131_072,
191
+ vision: true,
192
+ },
170
193
  {
171
194
  description: 'Qwen2 是全新的大型语言模型系列,具有更强的理解和生成能力。',
172
195
  displayName: 'Qwen2 7B (Free)',
@@ -9,6 +9,7 @@ import {
9
9
  GithubProviderCard,
10
10
  GoogleProviderCard,
11
11
  GroqProviderCard,
12
+ HunyuanProviderCard,
12
13
  MinimaxProviderCard,
13
14
  MistralProviderCard,
14
15
  MoonshotProviderCard,
@@ -75,6 +76,10 @@ export const DEFAULT_LLM_CONFIG: UserModelProviderConfig = {
75
76
  enabled: false,
76
77
  enabledModels: filterEnabledModels(GroqProviderCard),
77
78
  },
79
+ hunyuan: {
80
+ enabled: false,
81
+ enabledModels: filterEnabledModels(HunyuanProviderCard),
82
+ },
78
83
  minimax: {
79
84
  enabled: false,
80
85
  enabledModels: filterEnabledModels(MinimaxProviderCard),
@@ -14,6 +14,7 @@ import { LobeFireworksAI } from './fireworksai';
14
14
  import { LobeGithubAI } from './github';
15
15
  import { LobeGoogleAI } from './google';
16
16
  import { LobeGroq } from './groq';
17
+ import { LobeHunyuanAI } from './hunyuan';
17
18
  import { LobeMinimaxAI } from './minimax';
18
19
  import { LobeMistralAI } from './mistral';
19
20
  import { LobeMoonshotAI } from './moonshot';
@@ -133,6 +134,7 @@ class AgentRuntime {
133
134
  github: Partial<ClientOptions>;
134
135
  google: { apiKey?: string; baseURL?: string };
135
136
  groq: Partial<ClientOptions>;
137
+ hunyuan: Partial<ClientOptions>;
136
138
  minimax: Partial<ClientOptions>;
137
139
  mistral: Partial<ClientOptions>;
138
140
  moonshot: Partial<ClientOptions>;
@@ -300,6 +302,11 @@ class AgentRuntime {
300
302
  runtimeModel = new LobeAi21AI(params.ai21);
301
303
  break;
302
304
  }
305
+
306
+ case ModelProvider.Hunyuan: {
307
+ runtimeModel = new LobeHunyuanAI(params.hunyuan);
308
+ break;
309
+ }
303
310
  }
304
311
 
305
312
  return new AgentRuntime(runtimeModel);
@@ -0,0 +1,255 @@
1
+ // @vitest-environment node
2
+ import OpenAI from 'openai';
3
+ import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
4
+
5
+ import {
6
+ ChatStreamCallbacks,
7
+ LobeOpenAICompatibleRuntime,
8
+ ModelProvider,
9
+ } from '@/libs/agent-runtime';
10
+
11
+ import * as debugStreamModule from '../utils/debugStream';
12
+ import { LobeHunyuanAI } from './index';
13
+
14
+ const provider = ModelProvider.Hunyuan;
15
+ const defaultBaseURL = 'https://api.hunyuan.cloud.tencent.com/v1';
16
+
17
+ const bizErrorType = 'ProviderBizError';
18
+ const invalidErrorType = 'InvalidProviderAPIKey';
19
+
20
+ // Mock the console.error to avoid polluting test output
21
+ vi.spyOn(console, 'error').mockImplementation(() => {});
22
+
23
+ let instance: LobeOpenAICompatibleRuntime;
24
+
25
+ beforeEach(() => {
26
+ instance = new LobeHunyuanAI({ apiKey: 'test' });
27
+
28
+ // 使用 vi.spyOn 来模拟 chat.completions.create 方法
29
+ vi.spyOn(instance['client'].chat.completions, 'create').mockResolvedValue(
30
+ new ReadableStream() as any,
31
+ );
32
+ });
33
+
34
+ afterEach(() => {
35
+ vi.clearAllMocks();
36
+ });
37
+
38
+ describe('LobeHunyuanAI', () => {
39
+ describe('init', () => {
40
+ it('should correctly initialize with an API key', async () => {
41
+ const instance = new LobeHunyuanAI({ apiKey: 'test_api_key' });
42
+ expect(instance).toBeInstanceOf(LobeHunyuanAI);
43
+ expect(instance.baseURL).toEqual(defaultBaseURL);
44
+ });
45
+ });
46
+
47
+ describe('chat', () => {
48
+ describe('Error', () => {
49
+ it('should return OpenAIBizError with an openai error response when OpenAI.APIError is thrown', async () => {
50
+ // Arrange
51
+ const apiError = new OpenAI.APIError(
52
+ 400,
53
+ {
54
+ status: 400,
55
+ error: {
56
+ message: 'Bad Request',
57
+ },
58
+ },
59
+ 'Error message',
60
+ {},
61
+ );
62
+
63
+ vi.spyOn(instance['client'].chat.completions, 'create').mockRejectedValue(apiError);
64
+
65
+ // Act
66
+ try {
67
+ await instance.chat({
68
+ messages: [{ content: 'Hello', role: 'user' }],
69
+ model: 'hunyuan-lite',
70
+ temperature: 0,
71
+ });
72
+ } catch (e) {
73
+ expect(e).toEqual({
74
+ endpoint: defaultBaseURL,
75
+ error: {
76
+ error: { message: 'Bad Request' },
77
+ status: 400,
78
+ },
79
+ errorType: bizErrorType,
80
+ provider,
81
+ });
82
+ }
83
+ });
84
+
85
+ it('should throw AgentRuntimeError with NoOpenAIAPIKey if no apiKey is provided', async () => {
86
+ try {
87
+ new LobeHunyuanAI({});
88
+ } catch (e) {
89
+ expect(e).toEqual({ errorType: invalidErrorType });
90
+ }
91
+ });
92
+
93
+ it('should return OpenAIBizError with the cause when OpenAI.APIError is thrown with cause', async () => {
94
+ // Arrange
95
+ const errorInfo = {
96
+ stack: 'abc',
97
+ cause: {
98
+ message: 'api is undefined',
99
+ },
100
+ };
101
+ const apiError = new OpenAI.APIError(400, errorInfo, 'module error', {});
102
+
103
+ vi.spyOn(instance['client'].chat.completions, 'create').mockRejectedValue(apiError);
104
+
105
+ // Act
106
+ try {
107
+ await instance.chat({
108
+ messages: [{ content: 'Hello', role: 'user' }],
109
+ model: 'hunyuan-lite',
110
+ temperature: 0,
111
+ });
112
+ } catch (e) {
113
+ expect(e).toEqual({
114
+ endpoint: defaultBaseURL,
115
+ error: {
116
+ cause: { message: 'api is undefined' },
117
+ stack: 'abc',
118
+ },
119
+ errorType: bizErrorType,
120
+ provider,
121
+ });
122
+ }
123
+ });
124
+
125
+ it('should return OpenAIBizError with an cause response with desensitize Url', async () => {
126
+ // Arrange
127
+ const errorInfo = {
128
+ stack: 'abc',
129
+ cause: { message: 'api is undefined' },
130
+ };
131
+ const apiError = new OpenAI.APIError(400, errorInfo, 'module error', {});
132
+
133
+ instance = new LobeHunyuanAI({
134
+ apiKey: 'test',
135
+
136
+ baseURL: 'https://api.abc.com/v1',
137
+ });
138
+
139
+ vi.spyOn(instance['client'].chat.completions, 'create').mockRejectedValue(apiError);
140
+
141
+ // Act
142
+ try {
143
+ await instance.chat({
144
+ messages: [{ content: 'Hello', role: 'user' }],
145
+ model: 'hunyuan-lite',
146
+ temperature: 0,
147
+ });
148
+ } catch (e) {
149
+ expect(e).toEqual({
150
+ endpoint: 'https://api.***.com/v1',
151
+ error: {
152
+ cause: { message: 'api is undefined' },
153
+ stack: 'abc',
154
+ },
155
+ errorType: bizErrorType,
156
+ provider,
157
+ });
158
+ }
159
+ });
160
+
161
+ it('should throw an InvalidHunyuanAPIKey error type on 401 status code', async () => {
162
+ // Mock the API call to simulate a 401 error
163
+ const error = new Error('Unauthorized') as any;
164
+ error.status = 401;
165
+ vi.mocked(instance['client'].chat.completions.create).mockRejectedValue(error);
166
+
167
+ try {
168
+ await instance.chat({
169
+ messages: [{ content: 'Hello', role: 'user' }],
170
+ model: 'hunyuan-lite',
171
+ temperature: 0,
172
+ });
173
+ } catch (e) {
174
+ // Expect the chat method to throw an error with InvalidHunyuanAPIKey
175
+ expect(e).toEqual({
176
+ endpoint: defaultBaseURL,
177
+ error: new Error('Unauthorized'),
178
+ errorType: invalidErrorType,
179
+ provider,
180
+ });
181
+ }
182
+ });
183
+
184
+ it('should return AgentRuntimeError for non-OpenAI errors', async () => {
185
+ // Arrange
186
+ const genericError = new Error('Generic Error');
187
+
188
+ vi.spyOn(instance['client'].chat.completions, 'create').mockRejectedValue(genericError);
189
+
190
+ // Act
191
+ try {
192
+ await instance.chat({
193
+ messages: [{ content: 'Hello', role: 'user' }],
194
+ model: 'hunyuan-lite',
195
+ temperature: 0,
196
+ });
197
+ } catch (e) {
198
+ expect(e).toEqual({
199
+ endpoint: defaultBaseURL,
200
+ errorType: 'AgentRuntimeError',
201
+ provider,
202
+ error: {
203
+ name: genericError.name,
204
+ cause: genericError.cause,
205
+ message: genericError.message,
206
+ stack: genericError.stack,
207
+ },
208
+ });
209
+ }
210
+ });
211
+ });
212
+
213
+ describe('DEBUG', () => {
214
+ it('should call debugStream and return StreamingTextResponse when DEBUG_HUNYUAN_CHAT_COMPLETION is 1', async () => {
215
+ // Arrange
216
+ const mockProdStream = new ReadableStream() as any; // 模拟的 prod 流
217
+ const mockDebugStream = new ReadableStream({
218
+ start(controller) {
219
+ controller.enqueue('Debug stream content');
220
+ controller.close();
221
+ },
222
+ }) as any;
223
+ mockDebugStream.toReadableStream = () => mockDebugStream; // 添加 toReadableStream 方法
224
+
225
+ // 模拟 chat.completions.create 返回值,包括模拟的 tee 方法
226
+ (instance['client'].chat.completions.create as Mock).mockResolvedValue({
227
+ tee: () => [mockProdStream, { toReadableStream: () => mockDebugStream }],
228
+ });
229
+
230
+ // 保存原始环境变量值
231
+ const originalDebugValue = process.env.DEBUG_HUNYUAN_CHAT_COMPLETION;
232
+
233
+ // 模拟环境变量
234
+ process.env.DEBUG_HUNYUAN_CHAT_COMPLETION = '1';
235
+ vi.spyOn(debugStreamModule, 'debugStream').mockImplementation(() => Promise.resolve());
236
+
237
+ // 执行测试
238
+ // 运行你的测试函数,确保它会在条件满足时调用 debugStream
239
+ // 假设的测试函数调用,你可能需要根据实际情况调整
240
+ await instance.chat({
241
+ messages: [{ content: 'Hello', role: 'user' }],
242
+ model: 'hunyuan-lite',
243
+ stream: true,
244
+ temperature: 0,
245
+ });
246
+
247
+ // 验证 debugStream 被调用
248
+ expect(debugStreamModule.debugStream).toHaveBeenCalled();
249
+
250
+ // 恢复原始环境变量值
251
+ process.env.DEBUG_HUNYUAN_CHAT_COMPLETION = originalDebugValue;
252
+ });
253
+ });
254
+ });
255
+ });
@@ -0,0 +1,10 @@
1
+ import { ModelProvider } from '../types';
2
+ import { LobeOpenAICompatibleFactory } from '../utils/openaiCompatibleFactory';
3
+
4
+ export const LobeHunyuanAI = LobeOpenAICompatibleFactory({
5
+ baseURL: 'https://api.hunyuan.cloud.tencent.com/v1',
6
+ debug: {
7
+ chatCompletion: () => process.env.DEBUG_HUNYUAN_CHAT_COMPLETION === '1',
8
+ },
9
+ provider: ModelProvider.Hunyuan,
10
+ });
@@ -83,7 +83,7 @@ Usage of Gemini is subject to Google's [Gemini Terms of Use](https://ai.google.d
83
83
 
84
84
  Note: This model is experimental and not suited for production use-cases. It may be removed or redirected to another model in the future.",
85
85
  "displayName": "Google: Gemini Flash 1.5 Experimental",
86
- "enabled": true,
86
+ "enabled": false,
87
87
  "functionCall": false,
88
88
  "id": "google/gemini-flash-1.5-exp",
89
89
  "maxTokens": 32768,
@@ -291,7 +291,7 @@ Usage of Gemini is subject to Google's [Gemini Terms of Use](https://ai.google.d
291
291
 
292
292
  Note: This model is experimental and not suited for production use-cases. It may be removed or redirected to another model in the future.",
293
293
  "displayName": "Google: Gemini Pro 1.5 Experimental",
294
- "enabled": true,
294
+ "enabled": false,
295
295
  "functionCall": false,
296
296
  "id": "google/gemini-pro-1.5-exp",
297
297
  "maxTokens": 32768,
@@ -878,7 +878,7 @@ Usage of Gemini is subject to Google's [Gemini Terms of Use](https://ai.google.d
878
878
 
879
879
  #multimodal",
880
880
  "displayName": "Google: Gemini Flash 1.5",
881
- "enabled": false,
881
+ "enabled": true,
882
882
  "functionCall": false,
883
883
  "id": "google/gemini-flash-1.5",
884
884
  "maxTokens": 32768,
@@ -1249,7 +1249,7 @@ Usage of Gemini is subject to Google's [Gemini Terms of Use](https://ai.google.d
1249
1249
 
1250
1250
  #multimodal",
1251
1251
  "displayName": "Google: Gemini Pro 1.5",
1252
- "enabled": false,
1252
+ "enabled": true,
1253
1253
  "functionCall": false,
1254
1254
  "id": "google/gemini-pro-1.5",
1255
1255
  "maxTokens": 32768,
@@ -33,6 +33,7 @@ export enum ModelProvider {
33
33
  Github = 'github',
34
34
  Google = 'google',
35
35
  Groq = 'groq',
36
+ Hunyuan = 'hunyuan',
36
37
  Minimax = 'minimax',
37
38
  Mistral = 'mistral',
38
39
  Moonshot = 'moonshot',
@@ -9,6 +9,7 @@ import {
9
9
  GithubProviderCard,
10
10
  GoogleProviderCard,
11
11
  GroqProviderCard,
12
+ HunyuanProviderCard,
12
13
  NovitaProviderCard,
13
14
  OllamaProviderCard,
14
15
  OpenAIProviderCard,
@@ -49,6 +50,9 @@ export const getServerGlobalConfig = () => {
49
50
  ENABLED_GITHUB,
50
51
  GITHUB_MODEL_LIST,
51
52
 
53
+ ENABLED_HUNYUAN,
54
+ HUNYUAN_MODEL_LIST,
55
+
52
56
  ENABLED_DEEPSEEK,
53
57
  ENABLED_PERPLEXITY,
54
58
  ENABLED_ANTHROPIC,
@@ -160,6 +164,14 @@ export const getServerGlobalConfig = () => {
160
164
  modelString: GROQ_MODEL_LIST,
161
165
  }),
162
166
  },
167
+ hunyuan: {
168
+ enabled: ENABLED_HUNYUAN,
169
+ enabledModels: extractEnabledModels(HUNYUAN_MODEL_LIST),
170
+ serverModelCards: transformToChatModelCards({
171
+ defaultChatModels: HunyuanProviderCard.chatModels,
172
+ modelString: HUNYUAN_MODEL_LIST,
173
+ }),
174
+ },
163
175
  minimax: { enabled: ENABLED_MINIMAX },
164
176
  mistral: { enabled: ENABLED_MISTRAL },
165
177
  moonshot: { enabled: ENABLED_MOONSHOT },
@@ -28,6 +28,7 @@ export interface UserKeyVaults {
28
28
  github?: OpenAICompatibleKeyVault;
29
29
  google?: OpenAICompatibleKeyVault;
30
30
  groq?: OpenAICompatibleKeyVault;
31
+ hunyuan?: OpenAICompatibleKeyVault;
31
32
  lobehub?: any;
32
33
  minimax?: OpenAICompatibleKeyVault;
33
34
  mistral?: OpenAICompatibleKeyVault;