@lobehub/chat 0.161.1 → 0.161.3
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 +8 -8
- package/README.zh-CN.md +8 -8
- package/package.json +1 -1
- package/src/app/api/chat/[provider]/route.test.ts +1 -1
- package/src/app/api/chat/agentRuntime.test.ts +4 -4
- package/src/app/api/chat/agentRuntime.ts +17 -17
- package/src/app/api/chat/apiKeyManager.test.ts +1 -0
- package/src/app/api/chat/apiKeyManager.ts +2 -2
- package/src/app/api/config.test.ts +1 -1
- package/src/app/api/config.ts +3 -4
- package/src/app/api/openai/createBizOpenAI/createAzureOpenai.ts +2 -2
- package/src/app/api/openai/createBizOpenAI/createOpenai.ts +2 -2
- package/src/config/__tests__/server.test.ts +5 -5
- package/src/config/langfuse.ts +23 -0
- package/src/config/llm.ts +217 -0
- package/src/config/server/app.ts +0 -12
- package/src/config/server/index.ts +1 -5
- package/src/libs/agent-runtime/AgentRuntime.test.ts +21 -5
- package/src/libs/agent-runtime/minimax/index.test.ts +0 -1
- package/src/libs/agent-runtime/zhipu/index.test.ts +0 -3
- package/src/libs/traces/index.test.ts +6 -5
- package/src/libs/traces/index.ts +2 -2
- package/src/server/globalConfig/index.ts +8 -8
- package/src/config/server/provider.ts +0 -229
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
### [Version 0.161.3](https://github.com/lobehub/lobe-chat/compare/v0.161.2...v0.161.3)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2024-05-22**</sup>
|
|
8
|
+
|
|
9
|
+
#### ♻ Code Refactoring
|
|
10
|
+
|
|
11
|
+
- **misc**: Refactor the langfuse env.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### Code refactoring
|
|
19
|
+
|
|
20
|
+
- **misc**: Refactor the langfuse env, closes [#2602](https://github.com/lobehub/lobe-chat/issues/2602) ([cbebfbc](https://github.com/lobehub/lobe-chat/commit/cbebfbc))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
### [Version 0.161.2](https://github.com/lobehub/lobe-chat/compare/v0.161.1...v0.161.2)
|
|
31
|
+
|
|
32
|
+
<sup>Released on **2024-05-22**</sup>
|
|
33
|
+
|
|
34
|
+
#### ♻ Code Refactoring
|
|
35
|
+
|
|
36
|
+
- **misc**: Refactor the llm env.
|
|
37
|
+
|
|
38
|
+
<br/>
|
|
39
|
+
|
|
40
|
+
<details>
|
|
41
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
42
|
+
|
|
43
|
+
#### Code refactoring
|
|
44
|
+
|
|
45
|
+
- **misc**: Refactor the llm env, closes [#2592](https://github.com/lobehub/lobe-chat/issues/2592) ([5eb225a](https://github.com/lobehub/lobe-chat/commit/5eb225a))
|
|
46
|
+
|
|
47
|
+
</details>
|
|
48
|
+
|
|
49
|
+
<div align="right">
|
|
50
|
+
|
|
51
|
+
[](#readme-top)
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
5
55
|
### [Version 0.161.1](https://github.com/lobehub/lobe-chat/compare/v0.161.0...v0.161.1)
|
|
6
56
|
|
|
7
57
|
<sup>Released on **2024-05-22**</sup>
|
package/README.md
CHANGED
|
@@ -262,14 +262,14 @@ Our marketplace is not just a showcase platform but also a collaborative space.
|
|
|
262
262
|
|
|
263
263
|
<!-- AGENT LIST -->
|
|
264
264
|
|
|
265
|
-
| Recent Submits
|
|
266
|
-
|
|
|
267
|
-
| [
|
|
268
|
-
| [
|
|
269
|
-
| [
|
|
270
|
-
| [
|
|
271
|
-
|
|
272
|
-
> 📊 Total agents: [<kbd>**
|
|
265
|
+
| Recent Submits | Description |
|
|
266
|
+
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
267
|
+
| [Bahasa/English Translator](https://chat-preview.lobehub.com/market?agent=bahasa-translation)<br/><sup>By **[xenstar](https://github.com/xenstar)** on **2024-05-22**</sup> | Translates text into Bahasa or English, as needed<br/>`english` `translation` `writing` `bahasa` |
|
|
268
|
+
| [Zen Master](https://chat-preview.lobehub.com/market?agent=buddhism-master)<br/><sup>By **[epochaudio](https://github.com/epochaudio)** on **2024-05-22**</sup> | Well-versed in classics, adept at using Buddhism to guide life<br/>`buddhist-studies` `zen-buddhism` `buddhist-scripture-interpretation` `wisdom-q-a` |
|
|
269
|
+
| [Chinese Historian](https://chat-preview.lobehub.com/market?agent=chinese-historian)<br/><sup>By **[epochaudio](https://github.com/epochaudio)** on **2024-05-22**</sup> | Specialized in Chinese historical research, adept at applying ancient wisdom to analyze modern issues.<br/>`historical-research` `chinese-history` |
|
|
270
|
+
| [Confucian Scholar](https://chat-preview.lobehub.com/market?agent=confucian-sage)<br/><sup>By **[epochaudio](https://github.com/epochaudio)** on **2024-05-22**</sup> | A scholar who is proficient in Confucian classics and emphasizes the promotion of righteousness and morality.<br/>`confucian-scholar` `promoter-of-righteousness` |
|
|
271
|
+
|
|
272
|
+
> 📊 Total agents: [<kbd>**269**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
|
|
273
273
|
|
|
274
274
|
<!-- AGENT LIST -->
|
|
275
275
|
|
package/README.zh-CN.md
CHANGED
|
@@ -250,14 +250,14 @@ LobeChat 的插件生态系统是其核心功能的重要扩展,它极大地
|
|
|
250
250
|
|
|
251
251
|
<!-- AGENT LIST -->
|
|
252
252
|
|
|
253
|
-
| 最近新增
|
|
254
|
-
|
|
|
255
|
-
| [
|
|
256
|
-
| [
|
|
257
|
-
| [
|
|
258
|
-
| [
|
|
259
|
-
|
|
260
|
-
> 📊 Total agents: [<kbd>**
|
|
253
|
+
| 最近新增 | 助手说明 |
|
|
254
|
+
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
|
|
255
|
+
| [Bahasa/English Translator](https://chat-preview.lobehub.com/market?agent=bahasa-translation)<br/><sup>By **[xenstar](https://github.com/xenstar)** on **2024-05-22**</sup> | 根据需要将文本翻译成马来语或英语<br/>`英语` `翻译` `写作` `马来语` |
|
|
256
|
+
| [禅定法师](https://chat-preview.lobehub.com/market?agent=buddhism-master)<br/><sup>By **[epochaudio](https://github.com/epochaudio)** on **2024-05-22**</sup> | 熟读经典,善于运用佛法来指导人生<br/>`佛法佛法研究` `禅宗` `佛经解读` `智慧问答` |
|
|
257
|
+
| [中国历史学者](https://chat-preview.lobehub.com/market?agent=chinese-historian)<br/><sup>By **[epochaudio](https://github.com/epochaudio)** on **2024-05-22**</sup> | 专精于中国历史研究,擅长将古代智慧应用于现代问题分析<br/>`历史研究` `中国历史` |
|
|
258
|
+
| [儒家学者](https://chat-preview.lobehub.com/market?agent=confucian-sage)<br/><sup>By **[epochaudio](https://github.com/epochaudio)** on **2024-05-22**</sup> | 一名精通儒家经典且注重弘扬道义的学者<br/>`儒家学者` `道义弘扬者` |
|
|
259
|
+
|
|
260
|
+
> 📊 Total agents: [<kbd>**269**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
|
|
261
261
|
|
|
262
262
|
<!-- AGENT LIST -->
|
|
263
263
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "0.161.
|
|
3
|
+
"version": "0.161.3",
|
|
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",
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
LobeAnthropicAI,
|
|
7
7
|
LobeAzureOpenAI,
|
|
8
8
|
LobeBedrockAI,
|
|
9
|
+
LobeDeepSeekAI,
|
|
9
10
|
LobeGoogleAI,
|
|
10
11
|
LobeGroq,
|
|
11
12
|
LobeMinimaxAI,
|
|
@@ -16,7 +17,6 @@ import {
|
|
|
16
17
|
LobeOpenRouterAI,
|
|
17
18
|
LobePerplexityAI,
|
|
18
19
|
LobeRuntimeAI,
|
|
19
|
-
LobeDeepSeekAI,
|
|
20
20
|
LobeTogetherAI,
|
|
21
21
|
LobeZeroOneAI,
|
|
22
22
|
LobeZhipuAI,
|
|
@@ -27,8 +27,8 @@ import { AgentRuntime } from '@/libs/agent-runtime';
|
|
|
27
27
|
import { initAgentRuntimeWithUserPayload } from './agentRuntime';
|
|
28
28
|
|
|
29
29
|
// 模拟依赖项
|
|
30
|
-
vi.mock('@/config/
|
|
31
|
-
|
|
30
|
+
vi.mock('@/config/llm', () => ({
|
|
31
|
+
getLLMConfig: vi.fn(() => ({
|
|
32
32
|
// 确保为每个provider提供必要的配置信息
|
|
33
33
|
OPENAI_API_KEY: 'test-openai-key',
|
|
34
34
|
GOOGLE_API_KEY: 'test-google-key',
|
|
@@ -295,7 +295,7 @@ describe('initAgentRuntimeWithUserPayload method', () => {
|
|
|
295
295
|
// 假设 LobeDeepSeekAI 是 DeepSeek 提供者的实现类
|
|
296
296
|
expect(runtime['_runtime']).toBeInstanceOf(LobeDeepSeekAI);
|
|
297
297
|
});
|
|
298
|
-
|
|
298
|
+
|
|
299
299
|
it('Together AI provider: without apikey', async () => {
|
|
300
300
|
const jwtPayload = {};
|
|
301
301
|
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.TogetherAI, jwtPayload);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getLLMConfig } from '@/config/llm';
|
|
2
2
|
import { JWTPayload } from '@/const/auth';
|
|
3
3
|
import { INBOX_SESSION_ID } from '@/const/session';
|
|
4
4
|
import {
|
|
@@ -30,7 +30,7 @@ const getLlmOptionsFromPayload = (provider: string, payload: JWTPayload) => {
|
|
|
30
30
|
switch (provider) {
|
|
31
31
|
default: // Use Openai options as default
|
|
32
32
|
case ModelProvider.OpenAI: {
|
|
33
|
-
const { OPENAI_API_KEY, OPENAI_PROXY_URL } =
|
|
33
|
+
const { OPENAI_API_KEY, OPENAI_PROXY_URL } = getLLMConfig();
|
|
34
34
|
const openaiApiKey = payload?.apiKey || OPENAI_API_KEY;
|
|
35
35
|
const baseURL = payload?.endpoint || OPENAI_PROXY_URL;
|
|
36
36
|
const apiKey = apiKeyManager.pick(openaiApiKey);
|
|
@@ -40,7 +40,7 @@ const getLlmOptionsFromPayload = (provider: string, payload: JWTPayload) => {
|
|
|
40
40
|
};
|
|
41
41
|
}
|
|
42
42
|
case ModelProvider.Azure: {
|
|
43
|
-
const { AZURE_API_KEY, AZURE_API_VERSION, AZURE_ENDPOINT } =
|
|
43
|
+
const { AZURE_API_KEY, AZURE_API_VERSION, AZURE_ENDPOINT } = getLLMConfig();
|
|
44
44
|
const apiKey = apiKeyManager.pick(payload?.apiKey || AZURE_API_KEY);
|
|
45
45
|
const endpoint = payload?.endpoint || AZURE_ENDPOINT;
|
|
46
46
|
const apiVersion = payload?.azureApiVersion || AZURE_API_VERSION;
|
|
@@ -51,14 +51,14 @@ const getLlmOptionsFromPayload = (provider: string, payload: JWTPayload) => {
|
|
|
51
51
|
};
|
|
52
52
|
}
|
|
53
53
|
case ModelProvider.ZhiPu: {
|
|
54
|
-
const { ZHIPU_API_KEY } =
|
|
54
|
+
const { ZHIPU_API_KEY } = getLLMConfig();
|
|
55
55
|
const apiKey = apiKeyManager.pick(payload?.apiKey || ZHIPU_API_KEY);
|
|
56
56
|
return {
|
|
57
57
|
apiKey,
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
60
|
case ModelProvider.Google: {
|
|
61
|
-
const { GOOGLE_API_KEY, GOOGLE_PROXY_URL } =
|
|
61
|
+
const { GOOGLE_API_KEY, GOOGLE_PROXY_URL } = getLLMConfig();
|
|
62
62
|
const apiKey = apiKeyManager.pick(payload?.apiKey || GOOGLE_API_KEY);
|
|
63
63
|
const baseURL = payload?.endpoint || GOOGLE_PROXY_URL;
|
|
64
64
|
return {
|
|
@@ -67,7 +67,7 @@ const getLlmOptionsFromPayload = (provider: string, payload: JWTPayload) => {
|
|
|
67
67
|
};
|
|
68
68
|
}
|
|
69
69
|
case ModelProvider.Moonshot: {
|
|
70
|
-
const { MOONSHOT_API_KEY, MOONSHOT_PROXY_URL } =
|
|
70
|
+
const { MOONSHOT_API_KEY, MOONSHOT_PROXY_URL } = getLLMConfig();
|
|
71
71
|
const apiKey = apiKeyManager.pick(payload?.apiKey || MOONSHOT_API_KEY);
|
|
72
72
|
return {
|
|
73
73
|
apiKey,
|
|
@@ -75,7 +75,7 @@ const getLlmOptionsFromPayload = (provider: string, payload: JWTPayload) => {
|
|
|
75
75
|
};
|
|
76
76
|
}
|
|
77
77
|
case ModelProvider.Bedrock: {
|
|
78
|
-
const { AWS_SECRET_ACCESS_KEY, AWS_ACCESS_KEY_ID, AWS_REGION } =
|
|
78
|
+
const { AWS_SECRET_ACCESS_KEY, AWS_ACCESS_KEY_ID, AWS_REGION } = getLLMConfig();
|
|
79
79
|
let accessKeyId: string | undefined = AWS_ACCESS_KEY_ID;
|
|
80
80
|
let accessKeySecret: string | undefined = AWS_SECRET_ACCESS_KEY;
|
|
81
81
|
let region = AWS_REGION;
|
|
@@ -88,12 +88,12 @@ const getLlmOptionsFromPayload = (provider: string, payload: JWTPayload) => {
|
|
|
88
88
|
return { accessKeyId, accessKeySecret, region };
|
|
89
89
|
}
|
|
90
90
|
case ModelProvider.Ollama: {
|
|
91
|
-
const { OLLAMA_PROXY_URL } =
|
|
91
|
+
const { OLLAMA_PROXY_URL } = getLLMConfig();
|
|
92
92
|
const baseURL = payload?.endpoint || OLLAMA_PROXY_URL;
|
|
93
93
|
return { baseURL };
|
|
94
94
|
}
|
|
95
95
|
case ModelProvider.Perplexity: {
|
|
96
|
-
const { PERPLEXITY_API_KEY, PERPLEXITY_PROXY_URL } =
|
|
96
|
+
const { PERPLEXITY_API_KEY, PERPLEXITY_PROXY_URL } = getLLMConfig();
|
|
97
97
|
|
|
98
98
|
const apiKey = apiKeyManager.pick(payload?.apiKey || PERPLEXITY_API_KEY);
|
|
99
99
|
const baseURL = payload?.endpoint || PERPLEXITY_PROXY_URL;
|
|
@@ -101,7 +101,7 @@ const getLlmOptionsFromPayload = (provider: string, payload: JWTPayload) => {
|
|
|
101
101
|
return { apiKey, baseURL };
|
|
102
102
|
}
|
|
103
103
|
case ModelProvider.Anthropic: {
|
|
104
|
-
const { ANTHROPIC_API_KEY, ANTHROPIC_PROXY_URL } =
|
|
104
|
+
const { ANTHROPIC_API_KEY, ANTHROPIC_PROXY_URL } = getLLMConfig();
|
|
105
105
|
|
|
106
106
|
const apiKey = apiKeyManager.pick(payload?.apiKey || ANTHROPIC_API_KEY);
|
|
107
107
|
const baseURL = payload?.endpoint || ANTHROPIC_PROXY_URL;
|
|
@@ -109,21 +109,21 @@ const getLlmOptionsFromPayload = (provider: string, payload: JWTPayload) => {
|
|
|
109
109
|
return { apiKey, baseURL };
|
|
110
110
|
}
|
|
111
111
|
case ModelProvider.Minimax: {
|
|
112
|
-
const { MINIMAX_API_KEY } =
|
|
112
|
+
const { MINIMAX_API_KEY } = getLLMConfig();
|
|
113
113
|
|
|
114
114
|
const apiKey = apiKeyManager.pick(payload?.apiKey || MINIMAX_API_KEY);
|
|
115
115
|
|
|
116
116
|
return { apiKey };
|
|
117
117
|
}
|
|
118
118
|
case ModelProvider.Mistral: {
|
|
119
|
-
const { MISTRAL_API_KEY } =
|
|
119
|
+
const { MISTRAL_API_KEY } = getLLMConfig();
|
|
120
120
|
|
|
121
121
|
const apiKey = apiKeyManager.pick(payload?.apiKey || MISTRAL_API_KEY);
|
|
122
122
|
|
|
123
123
|
return { apiKey };
|
|
124
124
|
}
|
|
125
125
|
case ModelProvider.Groq: {
|
|
126
|
-
const { GROQ_API_KEY, GROQ_PROXY_URL } =
|
|
126
|
+
const { GROQ_API_KEY, GROQ_PROXY_URL } = getLLMConfig();
|
|
127
127
|
|
|
128
128
|
const apiKey = apiKeyManager.pick(payload?.apiKey || GROQ_API_KEY);
|
|
129
129
|
const baseURL = payload?.endpoint || GROQ_PROXY_URL;
|
|
@@ -131,28 +131,28 @@ const getLlmOptionsFromPayload = (provider: string, payload: JWTPayload) => {
|
|
|
131
131
|
return { apiKey, baseURL };
|
|
132
132
|
}
|
|
133
133
|
case ModelProvider.OpenRouter: {
|
|
134
|
-
const { OPENROUTER_API_KEY } =
|
|
134
|
+
const { OPENROUTER_API_KEY } = getLLMConfig();
|
|
135
135
|
|
|
136
136
|
const apiKey = apiKeyManager.pick(payload?.apiKey || OPENROUTER_API_KEY);
|
|
137
137
|
|
|
138
138
|
return { apiKey };
|
|
139
139
|
}
|
|
140
140
|
case ModelProvider.DeepSeek: {
|
|
141
|
-
const { DEEPSEEK_API_KEY } =
|
|
141
|
+
const { DEEPSEEK_API_KEY } = getLLMConfig();
|
|
142
142
|
|
|
143
143
|
const apiKey = apiKeyManager.pick(payload?.apiKey || DEEPSEEK_API_KEY);
|
|
144
144
|
|
|
145
145
|
return { apiKey };
|
|
146
146
|
}
|
|
147
147
|
case ModelProvider.TogetherAI: {
|
|
148
|
-
const { TOGETHERAI_API_KEY } =
|
|
148
|
+
const { TOGETHERAI_API_KEY } = getLLMConfig();
|
|
149
149
|
|
|
150
150
|
const apiKey = apiKeyManager.pick(payload?.apiKey || TOGETHERAI_API_KEY);
|
|
151
151
|
|
|
152
152
|
return { apiKey };
|
|
153
153
|
}
|
|
154
154
|
case ModelProvider.ZeroOne: {
|
|
155
|
-
const { ZEROONE_API_KEY } =
|
|
155
|
+
const { ZEROONE_API_KEY } = getLLMConfig();
|
|
156
156
|
|
|
157
157
|
const apiKey = apiKeyManager.pick(payload?.apiKey || ZEROONE_API_KEY);
|
|
158
158
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getLLMConfig } from '@/config/llm';
|
|
2
2
|
|
|
3
3
|
interface KeyStore {
|
|
4
4
|
index: number;
|
|
@@ -12,7 +12,7 @@ export class ApiKeyManager {
|
|
|
12
12
|
private _mode: string;
|
|
13
13
|
|
|
14
14
|
constructor() {
|
|
15
|
-
const { API_KEY_SELECT_MODE: mode = 'random' } =
|
|
15
|
+
const { API_KEY_SELECT_MODE: mode = 'random' } = getLLMConfig();
|
|
16
16
|
|
|
17
17
|
this._mode = mode;
|
|
18
18
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
// @vitest-environment node
|
|
1
2
|
import { describe, expect, it, vi } from 'vitest';
|
|
2
3
|
|
|
3
4
|
import { getPreferredRegion } from './config';
|
|
4
|
-
import { checkAuth } from './openai/createBizOpenAI/auth';
|
|
5
5
|
|
|
6
6
|
// Stub the global process object to safely mock environment variables
|
|
7
7
|
vi.stubGlobal('process', {
|
package/src/app/api/config.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getLLMConfig } from '@/config/llm';
|
|
2
2
|
|
|
3
3
|
export const getPreferredRegion = (region: string | string[] = 'auto') => {
|
|
4
4
|
try {
|
|
5
|
-
|
|
6
|
-
if (cfg.OPENAI_FUNCTION_REGIONS.length <= 0) {
|
|
5
|
+
if (getLLMConfig().OPENAI_FUNCTION_REGIONS.length <= 0) {
|
|
7
6
|
return region;
|
|
8
7
|
}
|
|
9
8
|
|
|
10
|
-
return
|
|
9
|
+
return getLLMConfig().OPENAI_FUNCTION_REGIONS;
|
|
11
10
|
} catch (error) {
|
|
12
11
|
console.error('get server config failed, error:', error);
|
|
13
12
|
return region;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import OpenAI, { ClientOptions } from 'openai';
|
|
2
2
|
import urlJoin from 'url-join';
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { getLLMConfig } from '@/config/llm';
|
|
5
5
|
import { ChatErrorType } from '@/types/fetch';
|
|
6
6
|
|
|
7
7
|
// create Azure OpenAI Instance
|
|
@@ -11,7 +11,7 @@ export const createAzureOpenai = (params: {
|
|
|
11
11
|
model: string;
|
|
12
12
|
userApiKey?: string | null;
|
|
13
13
|
}) => {
|
|
14
|
-
const { OPENAI_PROXY_URL = '', AZURE_API_VERSION, AZURE_API_KEY } =
|
|
14
|
+
const { OPENAI_PROXY_URL = '', AZURE_API_VERSION, AZURE_API_KEY } = getLLMConfig();
|
|
15
15
|
|
|
16
16
|
const endpoint = !params.endpoint ? OPENAI_PROXY_URL : params.endpoint;
|
|
17
17
|
const baseURL = urlJoin(endpoint, `/openai/deployments/${params.model.replace('.', '')}`); // refs: https://test-001.openai.azure.com/openai/deployments/gpt-35-turbo
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import OpenAI from 'openai';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { getLLMConfig } from '@/config/llm';
|
|
4
4
|
import { ChatErrorType } from '@/types/fetch';
|
|
5
5
|
|
|
6
6
|
// create OpenAI instance
|
|
7
7
|
export const createOpenai = (userApiKey: string | null, endpoint?: string | null) => {
|
|
8
|
-
const { OPENAI_API_KEY, OPENAI_PROXY_URL } =
|
|
8
|
+
const { OPENAI_API_KEY, OPENAI_PROXY_URL } = getLLMConfig();
|
|
9
9
|
|
|
10
10
|
const baseURL = endpoint ? endpoint : OPENAI_PROXY_URL ? OPENAI_PROXY_URL : undefined;
|
|
11
11
|
|
|
@@ -27,11 +27,11 @@ describe('getServerConfig', () => {
|
|
|
27
27
|
global.process = originalProcess; // Restore the original process object
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
-
it('correctly handles values for OPENAI_FUNCTION_REGIONS', () => {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
});
|
|
30
|
+
// it('correctly handles values for OPENAI_FUNCTION_REGIONS', () => {
|
|
31
|
+
// process.env.OPENAI_FUNCTION_REGIONS = 'iad1,sfo1';
|
|
32
|
+
// const config = getServerConfig();
|
|
33
|
+
// expect(config.OPENAI_FUNCTION_REGIONS).toStrictEqual(['iad1', 'sfo1']);
|
|
34
|
+
// });
|
|
35
35
|
|
|
36
36
|
describe('index url', () => {
|
|
37
37
|
it('should return default URLs when no environment variables are set', () => {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/* eslint-disable sort-keys-fix/sort-keys-fix , typescript-sort-keys/interface */
|
|
2
|
+
import { createEnv } from '@t3-oss/env-nextjs';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
|
|
5
|
+
export const getLangfuseConfig = () => {
|
|
6
|
+
return createEnv({
|
|
7
|
+
runtimeEnv: {
|
|
8
|
+
ENABLE_LANGFUSE: process.env.ENABLE_LANGFUSE === '1',
|
|
9
|
+
LANGFUSE_SECRET_KEY: process.env.LANGFUSE_SECRET_KEY || '',
|
|
10
|
+
LANGFUSE_PUBLIC_KEY: process.env.LANGFUSE_PUBLIC_KEY || '',
|
|
11
|
+
LANGFUSE_HOST: process.env.LANGFUSE_HOST || 'https://cloud.langfuse.com',
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
server: {
|
|
15
|
+
ENABLE_LANGFUSE: z.boolean(),
|
|
16
|
+
LANGFUSE_SECRET_KEY: z.string().optional(),
|
|
17
|
+
LANGFUSE_PUBLIC_KEY: z.string().optional(),
|
|
18
|
+
LANGFUSE_HOST: z.string().url(),
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const langfuseEnv = getLangfuseConfig();
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/* eslint-disable sort-keys-fix/sort-keys-fix , typescript-sort-keys/interface */
|
|
2
|
+
import { createEnv } from '@t3-oss/env-nextjs';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
|
|
5
|
+
declare global {
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
7
|
+
namespace NodeJS {
|
|
8
|
+
interface ProcessEnv {
|
|
9
|
+
/**
|
|
10
|
+
* @deprecated
|
|
11
|
+
*/
|
|
12
|
+
CUSTOM_MODELS?: string;
|
|
13
|
+
/**
|
|
14
|
+
* @deprecated
|
|
15
|
+
*/
|
|
16
|
+
OLLAMA_CUSTOM_MODELS?: string;
|
|
17
|
+
/**
|
|
18
|
+
* @deprecated
|
|
19
|
+
*/
|
|
20
|
+
OPENROUTER_CUSTOM_MODELS?: string;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const getLLMConfig = () => {
|
|
26
|
+
const AZURE_API_KEY = process.env.AZURE_API_KEY || '';
|
|
27
|
+
|
|
28
|
+
const ZHIPU_API_KEY = process.env.ZHIPU_API_KEY || '';
|
|
29
|
+
|
|
30
|
+
const AWS_ACCESS_KEY_ID = process.env.AWS_ACCESS_KEY_ID || '';
|
|
31
|
+
|
|
32
|
+
const DEEPSEEK_API_KEY = process.env.DEEPSEEK_API_KEY || '';
|
|
33
|
+
|
|
34
|
+
const GOOGLE_API_KEY = process.env.GOOGLE_API_KEY || '';
|
|
35
|
+
|
|
36
|
+
const MOONSHOT_API_KEY = process.env.MOONSHOT_API_KEY || '';
|
|
37
|
+
|
|
38
|
+
const PERPLEXITY_API_KEY = process.env.PERPLEXITY_API_KEY || '';
|
|
39
|
+
|
|
40
|
+
const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY || '';
|
|
41
|
+
|
|
42
|
+
const MINIMAX_API_KEY = process.env.MINIMAX_API_KEY || '';
|
|
43
|
+
|
|
44
|
+
const MISTRAL_API_KEY = process.env.MISTRAL_API_KEY || '';
|
|
45
|
+
|
|
46
|
+
const GROQ_API_KEY = process.env.GROQ_API_KEY || '';
|
|
47
|
+
|
|
48
|
+
const OPENROUTER_API_KEY = process.env.OPENROUTER_API_KEY || '';
|
|
49
|
+
|
|
50
|
+
const ZEROONE_API_KEY = process.env.ZEROONE_API_KEY || '';
|
|
51
|
+
|
|
52
|
+
const TOGETHERAI_API_KEY = process.env.TOGETHERAI_API_KEY || '';
|
|
53
|
+
|
|
54
|
+
// region format: iad1,sfo1
|
|
55
|
+
let regions: string[] = [];
|
|
56
|
+
if (process.env.OPENAI_FUNCTION_REGIONS) {
|
|
57
|
+
regions = process.env.OPENAI_FUNCTION_REGIONS.split(',');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (process.env.CUSTOM_MODELS) {
|
|
61
|
+
console.warn(
|
|
62
|
+
'DEPRECATED: `CUSTOM_MODELS` is deprecated, please use `OPENAI_MODEL_LIST` instead, we will remove `CUSTOM_MODELS` in the LobeChat 1.0',
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (process.env.OLLAMA_CUSTOM_MODELS) {
|
|
67
|
+
console.warn(
|
|
68
|
+
'DEPRECATED: `OLLAMA_CUSTOM_MODELS` is deprecated, please use `OLLAMA_MODEL_LIST` instead, we will remove `OLLAMA_CUSTOM_MODELS` in the LobeChat 1.0',
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (process.env.OPENROUTER_CUSTOM_MODELS) {
|
|
73
|
+
console.warn(
|
|
74
|
+
'DEPRECATED: `OPENROUTER_CUSTOM_MODELS` is deprecated, please use `OPENROUTER_MODEL_LIST` instead, we will remove `OPENROUTER_CUSTOM_MODELS` in the LobeChat 1.0',
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return createEnv({
|
|
79
|
+
server: {
|
|
80
|
+
API_KEY_SELECT_MODE: z.string().optional(),
|
|
81
|
+
|
|
82
|
+
ENABLED_OPENAI: z.boolean(),
|
|
83
|
+
OPENAI_API_KEY: z.string().optional(),
|
|
84
|
+
OPENAI_PROXY_URL: z.string().optional(),
|
|
85
|
+
OPENAI_MODEL_LIST: z.string().optional(),
|
|
86
|
+
OPENAI_FUNCTION_REGIONS: z.array(z.string()),
|
|
87
|
+
|
|
88
|
+
ENABLED_AZURE_OPENAI: z.boolean(),
|
|
89
|
+
AZURE_API_KEY: z.string().optional(),
|
|
90
|
+
AZURE_API_VERSION: z.string().optional(),
|
|
91
|
+
AZURE_ENDPOINT: z.string().optional(),
|
|
92
|
+
AZURE_MODEL_LIST: z.string().optional(),
|
|
93
|
+
|
|
94
|
+
ENABLED_ZHIPU: z.boolean(),
|
|
95
|
+
ZHIPU_API_KEY: z.string().optional(),
|
|
96
|
+
|
|
97
|
+
ENABLED_DEEPSEEK: z.boolean(),
|
|
98
|
+
DEEPSEEK_API_KEY: z.string().optional(),
|
|
99
|
+
|
|
100
|
+
ENABLED_GOOGLE: z.boolean(),
|
|
101
|
+
GOOGLE_API_KEY: z.string().optional(),
|
|
102
|
+
GOOGLE_PROXY_URL: z.string().optional(),
|
|
103
|
+
|
|
104
|
+
ENABLED_MOONSHOT: z.boolean(),
|
|
105
|
+
MOONSHOT_API_KEY: z.string().optional(),
|
|
106
|
+
MOONSHOT_PROXY_URL: z.string().optional(),
|
|
107
|
+
|
|
108
|
+
ENABLED_PERPLEXITY: z.boolean(),
|
|
109
|
+
PERPLEXITY_API_KEY: z.string().optional(),
|
|
110
|
+
PERPLEXITY_PROXY_URL: z.string().optional(),
|
|
111
|
+
|
|
112
|
+
ENABLED_ANTHROPIC: z.boolean(),
|
|
113
|
+
ANTHROPIC_API_KEY: z.string().optional(),
|
|
114
|
+
ANTHROPIC_PROXY_URL: z.string().optional(),
|
|
115
|
+
|
|
116
|
+
ENABLED_MINIMAX: z.boolean(),
|
|
117
|
+
MINIMAX_API_KEY: z.string().optional(),
|
|
118
|
+
|
|
119
|
+
ENABLED_MISTRAL: z.boolean(),
|
|
120
|
+
MISTRAL_API_KEY: z.string().optional(),
|
|
121
|
+
|
|
122
|
+
ENABLED_GROQ: z.boolean(),
|
|
123
|
+
GROQ_API_KEY: z.string().optional(),
|
|
124
|
+
GROQ_PROXY_URL: z.string().optional(),
|
|
125
|
+
|
|
126
|
+
ENABLED_OPENROUTER: z.boolean(),
|
|
127
|
+
OPENROUTER_API_KEY: z.string().optional(),
|
|
128
|
+
OPENROUTER_MODEL_LIST: z.string().optional(),
|
|
129
|
+
|
|
130
|
+
ENABLED_ZEROONE: z.boolean(),
|
|
131
|
+
ZEROONE_API_KEY: z.string().optional(),
|
|
132
|
+
|
|
133
|
+
ENABLED_TOGETHERAI: z.boolean(),
|
|
134
|
+
TOGETHERAI_API_KEY: z.string().optional(),
|
|
135
|
+
TOGETHERAI_MODEL_LIST: z.string().optional(),
|
|
136
|
+
|
|
137
|
+
ENABLED_AWS_BEDROCK: z.boolean(),
|
|
138
|
+
AWS_REGION: z.string().optional(),
|
|
139
|
+
AWS_ACCESS_KEY_ID: z.string().optional(),
|
|
140
|
+
AWS_SECRET_ACCESS_KEY: z.string().optional(),
|
|
141
|
+
|
|
142
|
+
ENABLED_OLLAMA: z.boolean(),
|
|
143
|
+
OLLAMA_PROXY_URL: z.string().optional(),
|
|
144
|
+
OLLAMA_MODEL_LIST: z.string().optional(),
|
|
145
|
+
},
|
|
146
|
+
runtimeEnv: {
|
|
147
|
+
API_KEY_SELECT_MODE: process.env.API_KEY_SELECT_MODE,
|
|
148
|
+
|
|
149
|
+
ENABLED_OPENAI: process.env.ENABLED_OPENAI !== '0',
|
|
150
|
+
OPENAI_API_KEY: process.env.OPENAI_API_KEY,
|
|
151
|
+
OPENAI_PROXY_URL: process.env.OPENAI_PROXY_URL,
|
|
152
|
+
OPENAI_MODEL_LIST: process.env.OPENAI_MODEL_LIST || process.env.CUSTOM_MODELS,
|
|
153
|
+
OPENAI_FUNCTION_REGIONS: regions as any,
|
|
154
|
+
|
|
155
|
+
ENABLED_AZURE_OPENAI: !!AZURE_API_KEY,
|
|
156
|
+
AZURE_API_KEY,
|
|
157
|
+
AZURE_API_VERSION: process.env.AZURE_API_VERSION,
|
|
158
|
+
AZURE_ENDPOINT: process.env.AZURE_ENDPOINT,
|
|
159
|
+
AZURE_MODEL_LIST: process.env.AZURE_MODEL_LIST,
|
|
160
|
+
|
|
161
|
+
ENABLED_ZHIPU: !!ZHIPU_API_KEY,
|
|
162
|
+
ZHIPU_API_KEY,
|
|
163
|
+
|
|
164
|
+
ENABLED_DEEPSEEK: !!DEEPSEEK_API_KEY,
|
|
165
|
+
DEEPSEEK_API_KEY,
|
|
166
|
+
|
|
167
|
+
ENABLED_GOOGLE: !!GOOGLE_API_KEY,
|
|
168
|
+
GOOGLE_API_KEY,
|
|
169
|
+
GOOGLE_PROXY_URL: process.env.GOOGLE_PROXY_URL,
|
|
170
|
+
|
|
171
|
+
ENABLED_PERPLEXITY: !!PERPLEXITY_API_KEY,
|
|
172
|
+
PERPLEXITY_API_KEY,
|
|
173
|
+
PERPLEXITY_PROXY_URL: process.env.PERPLEXITY_PROXY_URL,
|
|
174
|
+
|
|
175
|
+
ENABLED_ANTHROPIC: !!ANTHROPIC_API_KEY,
|
|
176
|
+
ANTHROPIC_API_KEY,
|
|
177
|
+
ANTHROPIC_PROXY_URL: process.env.ANTHROPIC_PROXY_URL,
|
|
178
|
+
|
|
179
|
+
ENABLED_MINIMAX: !!MINIMAX_API_KEY,
|
|
180
|
+
MINIMAX_API_KEY,
|
|
181
|
+
|
|
182
|
+
ENABLED_MISTRAL: !!MISTRAL_API_KEY,
|
|
183
|
+
MISTRAL_API_KEY,
|
|
184
|
+
|
|
185
|
+
ENABLED_OPENROUTER: !!OPENROUTER_API_KEY,
|
|
186
|
+
OPENROUTER_API_KEY,
|
|
187
|
+
OPENROUTER_MODEL_LIST:
|
|
188
|
+
process.env.OPENROUTER_MODEL_LIST || process.env.OPENROUTER_CUSTOM_MODELS,
|
|
189
|
+
|
|
190
|
+
ENABLED_TOGETHERAI: !!TOGETHERAI_API_KEY,
|
|
191
|
+
TOGETHERAI_API_KEY,
|
|
192
|
+
TOGETHERAI_MODEL_LIST: process.env.TOGETHERAI_MODEL_LIST,
|
|
193
|
+
|
|
194
|
+
ENABLED_MOONSHOT: !!MOONSHOT_API_KEY,
|
|
195
|
+
MOONSHOT_API_KEY,
|
|
196
|
+
MOONSHOT_PROXY_URL: process.env.MOONSHOT_PROXY_URL,
|
|
197
|
+
|
|
198
|
+
ENABLED_GROQ: !!GROQ_API_KEY,
|
|
199
|
+
GROQ_PROXY_URL: process.env.GROQ_PROXY_URL,
|
|
200
|
+
GROQ_API_KEY,
|
|
201
|
+
|
|
202
|
+
ENABLED_ZEROONE: !!ZEROONE_API_KEY,
|
|
203
|
+
ZEROONE_API_KEY,
|
|
204
|
+
|
|
205
|
+
ENABLED_AWS_BEDROCK: !!AWS_ACCESS_KEY_ID,
|
|
206
|
+
AWS_REGION: process.env.AWS_REGION,
|
|
207
|
+
AWS_ACCESS_KEY_ID: AWS_ACCESS_KEY_ID,
|
|
208
|
+
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY || '',
|
|
209
|
+
|
|
210
|
+
ENABLED_OLLAMA: process.env.ENABLED_OLLAMA !== '0',
|
|
211
|
+
OLLAMA_PROXY_URL: process.env.OLLAMA_PROXY_URL || '',
|
|
212
|
+
OLLAMA_MODEL_LIST: process.env.OLLAMA_MODEL_LIST || process.env.OLLAMA_CUSTOM_MODELS,
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
export const llmEnv = getLLMConfig();
|
package/src/config/server/app.ts
CHANGED
|
@@ -14,11 +14,6 @@ declare global {
|
|
|
14
14
|
PLUGIN_SETTINGS?: string;
|
|
15
15
|
|
|
16
16
|
DEFAULT_AGENT_CONFIG?: string;
|
|
17
|
-
|
|
18
|
-
ENABLE_LANGFUSE?: string;
|
|
19
|
-
LANGFUSE_PUBLIC_KEY?: string;
|
|
20
|
-
LANGFUSE_SECRET_KEY?: string;
|
|
21
|
-
LANGFUSE_HOST?: string;
|
|
22
17
|
}
|
|
23
18
|
}
|
|
24
19
|
}
|
|
@@ -35,8 +30,6 @@ export const getAppConfig = () => {
|
|
|
35
30
|
|
|
36
31
|
DEFAULT_AGENT_CONFIG: process.env.DEFAULT_AGENT_CONFIG || '',
|
|
37
32
|
|
|
38
|
-
SHOW_ACCESS_CODE_CONFIG: !!ACCESS_CODES.length,
|
|
39
|
-
|
|
40
33
|
SITE_URL: process.env.SITE_URL,
|
|
41
34
|
|
|
42
35
|
AGENTS_INDEX_URL: !!process.env.AGENTS_INDEX_URL
|
|
@@ -48,10 +41,5 @@ export const getAppConfig = () => {
|
|
|
48
41
|
: 'https://chat-plugins.lobehub.com',
|
|
49
42
|
|
|
50
43
|
PLUGIN_SETTINGS: process.env.PLUGIN_SETTINGS,
|
|
51
|
-
|
|
52
|
-
ENABLE_LANGFUSE: process.env.ENABLE_LANGFUSE === '1',
|
|
53
|
-
LANGFUSE_SECRET_KEY: process.env.LANGFUSE_SECRET_KEY || '',
|
|
54
|
-
LANGFUSE_PUBLIC_KEY: process.env.LANGFUSE_PUBLIC_KEY || '',
|
|
55
|
-
LANGFUSE_HOST: process.env.LANGFUSE_HOST || 'https://cloud.langfuse.com',
|
|
56
44
|
};
|
|
57
45
|
};
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import { getAppConfig } from './app';
|
|
2
|
-
import { getProviderConfig } from './provider';
|
|
3
2
|
|
|
4
3
|
export const getServerConfig = () => {
|
|
5
4
|
if (typeof process === 'undefined') {
|
|
6
5
|
throw new Error('[Server Config] you are importing a server-only module outside of server');
|
|
7
6
|
}
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
const app = getAppConfig();
|
|
11
|
-
|
|
12
|
-
return { ...provider, ...app };
|
|
8
|
+
return getAppConfig();
|
|
13
9
|
};
|
|
@@ -5,7 +5,7 @@ import { ClientOptions } from 'openai';
|
|
|
5
5
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
6
6
|
|
|
7
7
|
import { createTraceOptions } from '@/app/api/chat/agentRuntime';
|
|
8
|
-
import
|
|
8
|
+
import * as langfuseCfg from '@/config/langfuse';
|
|
9
9
|
import { JWTPayload } from '@/const/auth';
|
|
10
10
|
import { TraceNameMap } from '@/const/trace';
|
|
11
11
|
import {
|
|
@@ -312,15 +312,14 @@ describe('AgentRuntime', () => {
|
|
|
312
312
|
};
|
|
313
313
|
|
|
314
314
|
const updateMock = vi.fn();
|
|
315
|
-
|
|
316
|
-
|
|
315
|
+
|
|
316
|
+
it('should call experimental_onToolCall correctly', async () => {
|
|
317
|
+
vi.spyOn(langfuseCfg, 'getLangfuseConfig').mockReturnValue({
|
|
317
318
|
ENABLE_LANGFUSE: true,
|
|
318
319
|
LANGFUSE_PUBLIC_KEY: 'abc',
|
|
319
320
|
LANGFUSE_SECRET_KEY: 'DDD',
|
|
320
321
|
} as any);
|
|
321
|
-
});
|
|
322
322
|
|
|
323
|
-
it('should call experimental_onToolCall correctly', async () => {
|
|
324
323
|
// 使用 spyOn 模拟 chat 方法
|
|
325
324
|
vi.spyOn(LobeOpenAI.prototype, 'chat').mockImplementation(
|
|
326
325
|
async (payload, { callback }: any) => {
|
|
@@ -338,6 +337,12 @@ describe('AgentRuntime', () => {
|
|
|
338
337
|
expect(updateMock).toHaveBeenCalledWith({ tags: ['Tools Call'] });
|
|
339
338
|
});
|
|
340
339
|
it('should call onStart correctly', async () => {
|
|
340
|
+
vi.spyOn(langfuseCfg, 'getLangfuseConfig').mockReturnValue({
|
|
341
|
+
ENABLE_LANGFUSE: true,
|
|
342
|
+
LANGFUSE_PUBLIC_KEY: 'abc',
|
|
343
|
+
LANGFUSE_SECRET_KEY: 'DDD',
|
|
344
|
+
} as any);
|
|
345
|
+
|
|
341
346
|
vi.spyOn(LangfuseGenerationClient.prototype, 'update').mockImplementation(updateMock);
|
|
342
347
|
vi.spyOn(LobeOpenAI.prototype, 'chat').mockImplementation(
|
|
343
348
|
async (payload, { callback }: any) => {
|
|
@@ -355,6 +360,11 @@ describe('AgentRuntime', () => {
|
|
|
355
360
|
});
|
|
356
361
|
|
|
357
362
|
it('should call onCompletion correctly', async () => {
|
|
363
|
+
vi.spyOn(langfuseCfg, 'getLangfuseConfig').mockReturnValue({
|
|
364
|
+
ENABLE_LANGFUSE: true,
|
|
365
|
+
LANGFUSE_PUBLIC_KEY: 'abc',
|
|
366
|
+
LANGFUSE_SECRET_KEY: 'DDD',
|
|
367
|
+
} as any);
|
|
358
368
|
// Spy on the chat method and trigger onCompletion callback
|
|
359
369
|
vi.spyOn(LangfuseGenerationClient.prototype, 'update').mockImplementation(updateMock);
|
|
360
370
|
vi.spyOn(LobeOpenAI.prototype, 'chat').mockImplementation(
|
|
@@ -379,6 +389,12 @@ describe('AgentRuntime', () => {
|
|
|
379
389
|
});
|
|
380
390
|
});
|
|
381
391
|
it('should call onFinal correctly', async () => {
|
|
392
|
+
vi.spyOn(langfuseCfg, 'getLangfuseConfig').mockReturnValue({
|
|
393
|
+
ENABLE_LANGFUSE: true,
|
|
394
|
+
LANGFUSE_PUBLIC_KEY: 'abc',
|
|
395
|
+
LANGFUSE_SECRET_KEY: 'DDD',
|
|
396
|
+
} as any);
|
|
397
|
+
|
|
382
398
|
vi.spyOn(LobeOpenAI.prototype, 'chat').mockImplementation(
|
|
383
399
|
async (payload, { callback }: any) => {
|
|
384
400
|
if (callback?.onFinal) {
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
// @vitest-environment node
|
|
2
|
-
import { StreamingTextResponse } from 'ai';
|
|
3
2
|
import { OpenAI } from 'openai';
|
|
4
3
|
import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
4
|
|
|
6
5
|
import { ChatStreamCallbacks, LobeOpenAI } from '@/libs/agent-runtime';
|
|
7
6
|
import * as debugStreamModule from '@/libs/agent-runtime/utils/debugStream';
|
|
8
7
|
|
|
9
|
-
import { AgentRuntimeErrorType } from '../error';
|
|
10
|
-
import { ModelProvider } from '../types';
|
|
11
8
|
import * as authTokenModule from './authToken';
|
|
12
9
|
import { LobeZhipuAI } from './index';
|
|
13
10
|
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
+
// @vitest-environment node
|
|
1
2
|
import { Langfuse } from 'langfuse';
|
|
2
3
|
import { CreateLangfuseTraceBody } from 'langfuse-core';
|
|
3
4
|
import { describe, expect, it, vi } from 'vitest';
|
|
4
5
|
|
|
5
|
-
import * as server from '@/config/
|
|
6
|
+
import * as server from '@/config/langfuse';
|
|
6
7
|
|
|
7
8
|
import { TraceClient } from './index';
|
|
8
9
|
|
|
9
10
|
describe('TraceClient', () => {
|
|
10
11
|
it('should not initialize Langfuse client when ENABLE_LANGFUSE is false', () => {
|
|
11
|
-
vi.spyOn(server, '
|
|
12
|
+
vi.spyOn(server, 'getLangfuseConfig').mockReturnValue({
|
|
12
13
|
ENABLE_LANGFUSE: false,
|
|
13
14
|
} as any);
|
|
14
15
|
const client = new TraceClient();
|
|
@@ -16,7 +17,7 @@ describe('TraceClient', () => {
|
|
|
16
17
|
});
|
|
17
18
|
|
|
18
19
|
it('should throw error if LANGFUSE keys are missing', () => {
|
|
19
|
-
vi.spyOn(server, '
|
|
20
|
+
vi.spyOn(server, 'getLangfuseConfig').mockReturnValue({
|
|
20
21
|
ENABLE_LANGFUSE: true,
|
|
21
22
|
} as any);
|
|
22
23
|
expect(() => new TraceClient()).toThrow('NO_LANGFUSE_KEY_ERROR');
|
|
@@ -27,7 +28,7 @@ describe('TraceClient', () => {
|
|
|
27
28
|
|
|
28
29
|
vi.spyOn(Langfuse.prototype, 'trace').mockImplementation(mockTrace);
|
|
29
30
|
|
|
30
|
-
vi.spyOn(server, '
|
|
31
|
+
vi.spyOn(server, 'getLangfuseConfig').mockReturnValue({
|
|
31
32
|
ENABLE_LANGFUSE: true,
|
|
32
33
|
LANGFUSE_PUBLIC_KEY: 'public-key',
|
|
33
34
|
LANGFUSE_SECRET_KEY: 'secret-key',
|
|
@@ -45,7 +46,7 @@ describe('TraceClient', () => {
|
|
|
45
46
|
const mockShutdownAsync = vi.fn();
|
|
46
47
|
|
|
47
48
|
vi.spyOn(Langfuse.prototype, 'shutdownAsync').mockImplementation(mockShutdownAsync);
|
|
48
|
-
vi.spyOn(server, '
|
|
49
|
+
vi.spyOn(server, 'getLangfuseConfig').mockReturnValue({
|
|
49
50
|
ENABLE_LANGFUSE: true,
|
|
50
51
|
LANGFUSE_PUBLIC_KEY: 'public-key',
|
|
51
52
|
LANGFUSE_SECRET_KEY: 'secret-key',
|
package/src/libs/traces/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Langfuse } from 'langfuse';
|
|
2
2
|
import { CreateLangfuseTraceBody } from 'langfuse-core';
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { getLangfuseConfig } from '@/config/langfuse';
|
|
5
5
|
import { CURRENT_VERSION } from '@/const/version';
|
|
6
6
|
import { TraceEventClient } from '@/libs/traces/event';
|
|
7
7
|
|
|
@@ -13,7 +13,7 @@ export class TraceClient {
|
|
|
13
13
|
|
|
14
14
|
constructor() {
|
|
15
15
|
const { ENABLE_LANGFUSE, LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY, LANGFUSE_HOST } =
|
|
16
|
-
|
|
16
|
+
getLangfuseConfig();
|
|
17
17
|
|
|
18
18
|
if (!ENABLE_LANGFUSE) return;
|
|
19
19
|
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { fileEnv } from '@/config/file';
|
|
2
|
+
import { langfuseEnv } from '@/config/langfuse';
|
|
3
|
+
import { getLLMConfig } from '@/config/llm';
|
|
2
4
|
import {
|
|
3
5
|
OllamaProviderCard,
|
|
4
6
|
OpenAIProviderCard,
|
|
@@ -13,11 +15,9 @@ import { extractEnabledModels, transformToChatModelCards } from '@/utils/parseMo
|
|
|
13
15
|
import { parseAgentConfig } from './parseDefaultAgent';
|
|
14
16
|
|
|
15
17
|
export const getServerGlobalConfig = () => {
|
|
16
|
-
const {
|
|
17
|
-
ACCESS_CODES,
|
|
18
|
-
ENABLE_LANGFUSE,
|
|
18
|
+
const { ACCESS_CODES, DEFAULT_AGENT_CONFIG } = getServerConfig();
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
const {
|
|
21
21
|
ENABLED_OPENAI,
|
|
22
22
|
OPENAI_MODEL_LIST,
|
|
23
23
|
|
|
@@ -35,7 +35,7 @@ export const getServerGlobalConfig = () => {
|
|
|
35
35
|
ENABLED_AZURE_OPENAI,
|
|
36
36
|
AZURE_MODEL_LIST,
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
ENABLED_OLLAMA,
|
|
39
39
|
OLLAMA_MODEL_LIST,
|
|
40
40
|
OLLAMA_PROXY_URL,
|
|
41
41
|
|
|
@@ -45,7 +45,7 @@ export const getServerGlobalConfig = () => {
|
|
|
45
45
|
ENABLED_ZEROONE,
|
|
46
46
|
ENABLED_TOGETHERAI,
|
|
47
47
|
TOGETHERAI_MODEL_LIST,
|
|
48
|
-
} =
|
|
48
|
+
} = getLLMConfig();
|
|
49
49
|
|
|
50
50
|
const config: GlobalServerConfig = {
|
|
51
51
|
defaultAgent: {
|
|
@@ -76,7 +76,7 @@ export const getServerGlobalConfig = () => {
|
|
|
76
76
|
mistral: { enabled: ENABLED_MISTRAL },
|
|
77
77
|
moonshot: { enabled: ENABLED_MOONSHOT },
|
|
78
78
|
ollama: {
|
|
79
|
-
enabled:
|
|
79
|
+
enabled: ENABLED_OLLAMA,
|
|
80
80
|
fetchOnClient: !OLLAMA_PROXY_URL,
|
|
81
81
|
serverModelCards: transformToChatModelCards({
|
|
82
82
|
defaultChatModels: OllamaProviderCard.chatModels,
|
|
@@ -115,7 +115,7 @@ export const getServerGlobalConfig = () => {
|
|
|
115
115
|
zhipu: { enabled: ENABLED_ZHIPU },
|
|
116
116
|
},
|
|
117
117
|
telemetry: {
|
|
118
|
-
langfuse: ENABLE_LANGFUSE,
|
|
118
|
+
langfuse: langfuseEnv.ENABLE_LANGFUSE,
|
|
119
119
|
},
|
|
120
120
|
};
|
|
121
121
|
|
|
@@ -1,229 +0,0 @@
|
|
|
1
|
-
/* eslint-disable sort-keys-fix/sort-keys-fix , typescript-sort-keys/interface */
|
|
2
|
-
|
|
3
|
-
declare global {
|
|
4
|
-
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
5
|
-
namespace NodeJS {
|
|
6
|
-
interface ProcessEnv {
|
|
7
|
-
API_KEY_SELECT_MODE?: string;
|
|
8
|
-
|
|
9
|
-
// OpenAI Provider
|
|
10
|
-
ENABLED_OPENAI?: string;
|
|
11
|
-
OPENAI_API_KEY?: string;
|
|
12
|
-
OPENAI_PROXY_URL?: string;
|
|
13
|
-
OPENAI_MODEL_LIST?: string;
|
|
14
|
-
OPENAI_ENABLED_MODELS?: string;
|
|
15
|
-
OPENAI_FUNCTION_REGIONS?: string;
|
|
16
|
-
|
|
17
|
-
// Azure OpenAI Provider
|
|
18
|
-
AZURE_API_KEY?: string;
|
|
19
|
-
AZURE_ENDPOINT?: string;
|
|
20
|
-
AZURE_API_VERSION?: string;
|
|
21
|
-
|
|
22
|
-
// DeepSeek Provider
|
|
23
|
-
ENABLED_DEEPSEEK?: string;
|
|
24
|
-
DEEPSEEK_API_KEY?: string;
|
|
25
|
-
|
|
26
|
-
// ZhiPu Provider
|
|
27
|
-
ENABLED_ZHIPU?: string;
|
|
28
|
-
ZHIPU_API_KEY?: string;
|
|
29
|
-
ZHIPU_PROXY_URL?: string;
|
|
30
|
-
|
|
31
|
-
// Google Provider
|
|
32
|
-
ENABLED_GOOGLE?: string;
|
|
33
|
-
GOOGLE_API_KEY?: string;
|
|
34
|
-
GOOGLE_PROXY_URL?: string;
|
|
35
|
-
|
|
36
|
-
// Moonshot Provider
|
|
37
|
-
ENABLED_MOONSHOT?: string;
|
|
38
|
-
MOONSHOT_API_KEY?: string;
|
|
39
|
-
MOONSHOT_PROXY_URL?: string;
|
|
40
|
-
|
|
41
|
-
// Perplexity Provider
|
|
42
|
-
ENABLED_PERPLEXITY?: string;
|
|
43
|
-
PERPLEXITY_API_KEY?: string;
|
|
44
|
-
PERPLEXITY_PROXY_URL?: string;
|
|
45
|
-
|
|
46
|
-
// Anthropic Provider
|
|
47
|
-
ENABLED_ANTHROPIC?: string;
|
|
48
|
-
ANTHROPIC_API_KEY?: string;
|
|
49
|
-
ANTHROPIC_PROXY_URL?: string;
|
|
50
|
-
|
|
51
|
-
// Minimax Provider
|
|
52
|
-
ENABLED_MINIMAX?: string;
|
|
53
|
-
MINIMAX_API_KEY?: string;
|
|
54
|
-
|
|
55
|
-
// Mistral Provider
|
|
56
|
-
ENABLED_MISTRAL?: string;
|
|
57
|
-
MISTRAL_API_KEY?: string;
|
|
58
|
-
|
|
59
|
-
// Groq Provider
|
|
60
|
-
ENABLED_GROQ?: string;
|
|
61
|
-
GROQ_API_KEY?: string;
|
|
62
|
-
GROQ_PROXY_URL?: string;
|
|
63
|
-
|
|
64
|
-
// OpenRouter Provider
|
|
65
|
-
ENABLED_OPENROUTER?: string;
|
|
66
|
-
OPENROUTER_API_KEY?: string;
|
|
67
|
-
OPENROUTER_MODEL_LIST?: string;
|
|
68
|
-
|
|
69
|
-
// ZeroOne Provider
|
|
70
|
-
ENABLED_ZEROONE?: string;
|
|
71
|
-
ZEROONE_API_KEY?: string;
|
|
72
|
-
|
|
73
|
-
// TogetherAI Provider
|
|
74
|
-
ENABLED_TOGETHERAI?: string;
|
|
75
|
-
TOGETHERAI_API_KEY?: string;
|
|
76
|
-
TOGETHERAI_MODEL_LIST?: string;
|
|
77
|
-
|
|
78
|
-
// AWS Credentials
|
|
79
|
-
AWS_REGION?: string;
|
|
80
|
-
AWS_ACCESS_KEY_ID?: string;
|
|
81
|
-
AWS_SECRET_ACCESS_KEY?: string;
|
|
82
|
-
|
|
83
|
-
// Ollama Provider;
|
|
84
|
-
ENABLE_OLLAMA?: string;
|
|
85
|
-
OLLAMA_PROXY_URL?: string;
|
|
86
|
-
OLLAMA_MODEL_LIST?: string;
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* @deprecated
|
|
90
|
-
*/
|
|
91
|
-
CUSTOM_MODELS?: string;
|
|
92
|
-
/**
|
|
93
|
-
* @deprecated
|
|
94
|
-
*/
|
|
95
|
-
OLLAMA_CUSTOM_MODELS?: string;
|
|
96
|
-
/**
|
|
97
|
-
* @deprecated
|
|
98
|
-
*/
|
|
99
|
-
OPENROUTER_CUSTOM_MODELS?: string;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export const getProviderConfig = () => {
|
|
105
|
-
if (typeof process === 'undefined') {
|
|
106
|
-
throw new Error('[Server Config] you are importing a server-only module outside of server');
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const AZURE_API_KEY = process.env.AZURE_API_KEY || '';
|
|
110
|
-
|
|
111
|
-
const ZHIPU_API_KEY = process.env.ZHIPU_API_KEY || '';
|
|
112
|
-
|
|
113
|
-
const AWS_ACCESS_KEY_ID = process.env.AWS_ACCESS_KEY_ID || '';
|
|
114
|
-
|
|
115
|
-
const DEEPSEEK_API_KEY = process.env.DEEPSEEK_API_KEY || '';
|
|
116
|
-
|
|
117
|
-
const GOOGLE_API_KEY = process.env.GOOGLE_API_KEY || '';
|
|
118
|
-
|
|
119
|
-
const MOONSHOT_API_KEY = process.env.MOONSHOT_API_KEY || '';
|
|
120
|
-
|
|
121
|
-
const PERPLEXITY_API_KEY = process.env.PERPLEXITY_API_KEY || '';
|
|
122
|
-
|
|
123
|
-
const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY || '';
|
|
124
|
-
|
|
125
|
-
const MINIMAX_API_KEY = process.env.MINIMAX_API_KEY || '';
|
|
126
|
-
|
|
127
|
-
const MISTRAL_API_KEY = process.env.MISTRAL_API_KEY || '';
|
|
128
|
-
|
|
129
|
-
const GROQ_API_KEY = process.env.GROQ_API_KEY || '';
|
|
130
|
-
|
|
131
|
-
const OPENROUTER_API_KEY = process.env.OPENROUTER_API_KEY || '';
|
|
132
|
-
|
|
133
|
-
const ZEROONE_API_KEY = process.env.ZEROONE_API_KEY || '';
|
|
134
|
-
|
|
135
|
-
const TOGETHERAI_API_KEY = process.env.TOGETHERAI_API_KEY || '';
|
|
136
|
-
|
|
137
|
-
// region format: iad1,sfo1
|
|
138
|
-
let regions: string[] = [];
|
|
139
|
-
if (process.env.OPENAI_FUNCTION_REGIONS) {
|
|
140
|
-
regions = process.env.OPENAI_FUNCTION_REGIONS.split(',');
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (process.env.CUSTOM_MODELS) {
|
|
144
|
-
console.warn(
|
|
145
|
-
'DEPRECATED: `CUSTOM_MODELS` is deprecated, please use `OPENAI_MODEL_LIST` instead, we will remove `CUSTOM_MODELS` in the LobeChat 1.0',
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (process.env.OLLAMA_CUSTOM_MODELS) {
|
|
150
|
-
console.warn(
|
|
151
|
-
'DEPRECATED: `OLLAMA_CUSTOM_MODELS` is deprecated, please use `OLLAMA_MODEL_LIST` instead, we will remove `OLLAMA_CUSTOM_MODELS` in the LobeChat 1.0',
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
if (process.env.OPENROUTER_CUSTOM_MODELS) {
|
|
156
|
-
console.warn(
|
|
157
|
-
'DEPRECATED: `OPENROUTER_CUSTOM_MODELS` is deprecated, please use `OPENROUTER_MODEL_LIST` instead, we will remove `OPENROUTER_CUSTOM_MODELS` in the LobeChat 1.0',
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
return {
|
|
162
|
-
API_KEY_SELECT_MODE: process.env.API_KEY_SELECT_MODE,
|
|
163
|
-
|
|
164
|
-
ENABLED_OPENAI: process.env.ENABLED_OPENAI !== '0',
|
|
165
|
-
OPENAI_API_KEY: process.env.OPENAI_API_KEY,
|
|
166
|
-
OPENAI_PROXY_URL: process.env.OPENAI_PROXY_URL,
|
|
167
|
-
OPENAI_MODEL_LIST: process.env.OPENAI_MODEL_LIST || process.env.CUSTOM_MODELS,
|
|
168
|
-
OPENAI_FUNCTION_REGIONS: regions,
|
|
169
|
-
|
|
170
|
-
ENABLED_AZURE_OPENAI: !!AZURE_API_KEY,
|
|
171
|
-
AZURE_API_KEY,
|
|
172
|
-
AZURE_API_VERSION: process.env.AZURE_API_VERSION,
|
|
173
|
-
AZURE_ENDPOINT: process.env.AZURE_ENDPOINT,
|
|
174
|
-
AZURE_MODEL_LIST: process.env.AZURE_MODEL_LIST,
|
|
175
|
-
|
|
176
|
-
ENABLED_ZHIPU: !!ZHIPU_API_KEY,
|
|
177
|
-
ZHIPU_API_KEY,
|
|
178
|
-
|
|
179
|
-
ENABLED_DEEPSEEK: !!DEEPSEEK_API_KEY,
|
|
180
|
-
DEEPSEEK_API_KEY,
|
|
181
|
-
|
|
182
|
-
ENABLED_GOOGLE: !!GOOGLE_API_KEY,
|
|
183
|
-
GOOGLE_API_KEY,
|
|
184
|
-
GOOGLE_PROXY_URL: process.env.GOOGLE_PROXY_URL,
|
|
185
|
-
|
|
186
|
-
ENABLED_PERPLEXITY: !!PERPLEXITY_API_KEY,
|
|
187
|
-
PERPLEXITY_API_KEY,
|
|
188
|
-
PERPLEXITY_PROXY_URL: process.env.PERPLEXITY_PROXY_URL,
|
|
189
|
-
|
|
190
|
-
ENABLED_ANTHROPIC: !!ANTHROPIC_API_KEY,
|
|
191
|
-
ANTHROPIC_API_KEY,
|
|
192
|
-
ANTHROPIC_PROXY_URL: process.env.ANTHROPIC_PROXY_URL,
|
|
193
|
-
|
|
194
|
-
ENABLED_MINIMAX: !!MINIMAX_API_KEY,
|
|
195
|
-
MINIMAX_API_KEY,
|
|
196
|
-
|
|
197
|
-
ENABLED_MISTRAL: !!MISTRAL_API_KEY,
|
|
198
|
-
MISTRAL_API_KEY,
|
|
199
|
-
|
|
200
|
-
ENABLED_OPENROUTER: !!OPENROUTER_API_KEY,
|
|
201
|
-
OPENROUTER_API_KEY,
|
|
202
|
-
OPENROUTER_MODEL_LIST:
|
|
203
|
-
process.env.OPENROUTER_MODEL_LIST || process.env.OPENROUTER_CUSTOM_MODELS,
|
|
204
|
-
|
|
205
|
-
ENABLED_TOGETHERAI: !!TOGETHERAI_API_KEY,
|
|
206
|
-
TOGETHERAI_API_KEY,
|
|
207
|
-
TOGETHERAI_MODEL_LIST: process.env.TOGETHERAI_MODEL_LIST,
|
|
208
|
-
|
|
209
|
-
ENABLED_MOONSHOT: !!MOONSHOT_API_KEY,
|
|
210
|
-
MOONSHOT_API_KEY,
|
|
211
|
-
MOONSHOT_PROXY_URL: process.env.MOONSHOT_PROXY_URL,
|
|
212
|
-
|
|
213
|
-
ENABLED_GROQ: !!GROQ_API_KEY,
|
|
214
|
-
GROQ_PROXY_URL: process.env.GROQ_PROXY_URL,
|
|
215
|
-
GROQ_API_KEY,
|
|
216
|
-
|
|
217
|
-
ENABLED_ZEROONE: !!ZEROONE_API_KEY,
|
|
218
|
-
ZEROONE_API_KEY,
|
|
219
|
-
|
|
220
|
-
ENABLED_AWS_BEDROCK: !!AWS_ACCESS_KEY_ID,
|
|
221
|
-
AWS_REGION: process.env.AWS_REGION,
|
|
222
|
-
AWS_ACCESS_KEY_ID: AWS_ACCESS_KEY_ID,
|
|
223
|
-
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY || '',
|
|
224
|
-
|
|
225
|
-
ENABLE_OLLAMA: process.env.ENABLE_OLLAMA !== '0',
|
|
226
|
-
OLLAMA_PROXY_URL: process.env.OLLAMA_PROXY_URL || '',
|
|
227
|
-
OLLAMA_MODEL_LIST: process.env.OLLAMA_MODEL_LIST || process.env.OLLAMA_CUSTOM_MODELS,
|
|
228
|
-
};
|
|
229
|
-
};
|