@lobehub/chat 0.147.21 → 0.148.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 +42 -0
- package/locales/ar/setting.json +4 -0
- package/locales/bg-BG/setting.json +4 -0
- package/locales/de-DE/setting.json +4 -0
- package/locales/en-US/setting.json +4 -0
- package/locales/es-ES/setting.json +4 -0
- package/locales/fr-FR/setting.json +4 -0
- package/locales/it-IT/setting.json +4 -0
- package/locales/ja-JP/setting.json +4 -0
- package/locales/ko-KR/setting.json +4 -0
- package/locales/nl-NL/setting.json +4 -0
- package/locales/pl-PL/setting.json +4 -0
- package/locales/pt-BR/setting.json +4 -0
- package/locales/ru-RU/setting.json +4 -0
- package/locales/tr-TR/setting.json +4 -0
- package/locales/vi-VN/setting.json +4 -0
- package/locales/zh-CN/setting.json +4 -0
- package/locales/zh-TW/setting.json +4 -0
- package/package.json +3 -2
- package/public/favicon-32x32.ico +0 -0
- package/public/favicon.ico +0 -0
- package/public/icons/apple-touch-icon.png +0 -0
- package/src/app/api/chat/[provider]/route.test.ts +5 -7
- package/src/app/api/chat/[provider]/route.ts +13 -7
- package/src/app/api/chat/agentRuntime.test.ts +195 -451
- package/src/app/api/chat/agentRuntime.ts +197 -280
- package/src/app/api/chat/models/[provider]/route.ts +2 -2
- package/src/app/chat/features/TopicListContent/Topic/TopicContent.tsx +2 -2
- package/src/app/metadata.ts +3 -5
- package/src/app/settings/llm/components/ProviderConfig/index.tsx +23 -1
- package/src/app/settings/llm/index.tsx +2 -2
- package/src/app/settings/llm/page.tsx +1 -5
- package/src/features/ChatInput/Topic/index.tsx +6 -2
- package/src/features/Conversation/components/ChatItem/index.tsx +8 -3
- package/src/libs/agent-runtime/AgentRuntime.test.ts +400 -0
- package/src/libs/agent-runtime/AgentRuntime.ts +192 -0
- package/src/libs/agent-runtime/index.ts +1 -0
- package/src/libs/swr/index.ts +9 -0
- package/src/locales/default/setting.ts +4 -0
- package/src/services/__tests__/chat.test.ts +287 -1
- package/src/services/chat.ts +148 -2
- package/src/store/chat/slices/message/action.ts +80 -42
- package/src/store/chat/slices/message/initialState.ts +1 -1
- package/src/store/chat/slices/message/reducer.ts +32 -1
- package/src/store/chat/slices/topic/action.test.ts +25 -2
- package/src/store/chat/slices/topic/action.ts +24 -7
- package/src/store/chat/slices/topic/reducer.test.ts +141 -0
- package/src/store/chat/slices/topic/reducer.ts +67 -0
- package/src/store/global/slices/settings/selectors/modelConfig.ts +13 -0
- package/src/store/session/slices/session/action.ts +4 -5
- package/src/types/settings/modelProvider.ts +4 -0
- package/vercel.json +1 -1
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
// @vitest-environment node
|
|
2
|
-
import {
|
|
3
|
-
import { LangfuseGenerationClient, LangfuseTraceClient } from 'langfuse-core';
|
|
4
|
-
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
5
3
|
|
|
6
|
-
import { getServerConfig } from '@/config/server';
|
|
7
4
|
import { JWTPayload } from '@/const/auth';
|
|
8
|
-
import { TraceNameMap } from '@/const/trace';
|
|
9
5
|
import {
|
|
10
|
-
ChatStreamPayload,
|
|
11
6
|
LobeAnthropicAI,
|
|
12
7
|
LobeAzureOpenAI,
|
|
13
8
|
LobeBedrockAI,
|
|
14
9
|
LobeGoogleAI,
|
|
10
|
+
LobeGroq,
|
|
15
11
|
LobeMistralAI,
|
|
16
12
|
LobeMoonshotAI,
|
|
17
13
|
LobeOllamaAI,
|
|
@@ -20,11 +16,13 @@ import {
|
|
|
20
16
|
LobePerplexityAI,
|
|
21
17
|
LobeRuntimeAI,
|
|
22
18
|
LobeTogetherAI,
|
|
19
|
+
LobeZeroOneAI,
|
|
23
20
|
LobeZhipuAI,
|
|
24
21
|
ModelProvider,
|
|
25
22
|
} from '@/libs/agent-runtime';
|
|
23
|
+
import { AgentRuntime } from '@/libs/agent-runtime';
|
|
26
24
|
|
|
27
|
-
import
|
|
25
|
+
import { initAgentRuntimeWithUserPayload } from './agentRuntime';
|
|
28
26
|
|
|
29
27
|
// 模拟依赖项
|
|
30
28
|
vi.mock('@/config/server', () => ({
|
|
@@ -50,489 +48,235 @@ vi.mock('@/config/server', () => ({
|
|
|
50
48
|
})),
|
|
51
49
|
}));
|
|
52
50
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Test cases for function initAgentRuntimeWithUserPayload
|
|
53
|
+
* this method will use AgentRuntime from `@/libs/agent-runtime`
|
|
54
|
+
* and method `getLlmOptionsFromPayload` to initialize runtime
|
|
55
|
+
* with user payload. Test case below will test both the methods
|
|
56
|
+
*/
|
|
57
|
+
describe('initAgentRuntimeWithUserPayload method', () => {
|
|
58
|
+
describe('should initialize with options correctly', () => {
|
|
59
|
+
it('OpenAI provider: with apikey and endpoint', async () => {
|
|
60
|
+
const jwtPayload: JWTPayload = { apiKey: 'user-openai-key', endpoint: 'user-endpoint' };
|
|
61
|
+
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.OpenAI, jwtPayload);
|
|
62
|
+
expect(runtime).toBeInstanceOf(AgentRuntime);
|
|
63
|
+
expect(runtime['_runtime']).toBeInstanceOf(LobeOpenAI);
|
|
64
|
+
expect(runtime['_runtime'].baseURL).toBe(jwtPayload.endpoint);
|
|
67
65
|
});
|
|
68
66
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
);
|
|
80
|
-
|
|
81
|
-
expect(runtime).toBeInstanceOf(AgentRuntime);
|
|
82
|
-
expect(runtime['_runtime']).toBeInstanceOf(LobeAzureOpenAI);
|
|
83
|
-
expect(runtime['_runtime'].baseURL).toBe('user-azure-endpoint');
|
|
84
|
-
});
|
|
85
|
-
it('should initialize with azureOpenAIParams correctly', async () => {
|
|
86
|
-
const jwtPayload: JWTPayload = {
|
|
87
|
-
apiKey: 'user-openai-key',
|
|
88
|
-
endpoint: 'user-endpoint',
|
|
89
|
-
azureApiVersion: 'custom-version',
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
const runtime = await AgentRuntime.initializeWithUserPayload(
|
|
93
|
-
ModelProvider.Azure,
|
|
94
|
-
jwtPayload,
|
|
95
|
-
);
|
|
96
|
-
|
|
97
|
-
expect(runtime).toBeInstanceOf(AgentRuntime);
|
|
98
|
-
const openAIRuntime = runtime['_runtime'] as LobeRuntimeAI;
|
|
99
|
-
expect(openAIRuntime).toBeInstanceOf(LobeAzureOpenAI);
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it('should initialize with AzureAI correctly', async () => {
|
|
103
|
-
const jwtPayload: JWTPayload = {
|
|
104
|
-
apiKey: 'user-azure-key',
|
|
105
|
-
endpoint: 'user-azure-endpoint',
|
|
106
|
-
};
|
|
107
|
-
const runtime = await AgentRuntime.initializeWithUserPayload(
|
|
108
|
-
ModelProvider.Azure,
|
|
109
|
-
jwtPayload,
|
|
110
|
-
);
|
|
111
|
-
|
|
112
|
-
expect(runtime['_runtime']).toBeInstanceOf(LobeAzureOpenAI);
|
|
113
|
-
});
|
|
114
|
-
it('should initialize AzureAI correctly without apiKey', async () => {
|
|
115
|
-
const jwtPayload: JWTPayload = {};
|
|
116
|
-
const runtime = await AgentRuntime.initializeWithUserPayload(
|
|
117
|
-
ModelProvider.Azure,
|
|
118
|
-
jwtPayload,
|
|
119
|
-
);
|
|
120
|
-
|
|
121
|
-
expect(runtime['_runtime']).toBeInstanceOf(LobeAzureOpenAI);
|
|
122
|
-
});
|
|
67
|
+
it('Azure AI provider: with apikey, endpoint and apiversion', async () => {
|
|
68
|
+
const jwtPayload: JWTPayload = {
|
|
69
|
+
apiKey: 'user-azure-key',
|
|
70
|
+
endpoint: 'user-azure-endpoint',
|
|
71
|
+
azureApiVersion: '2024-02-01',
|
|
72
|
+
};
|
|
73
|
+
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Azure, jwtPayload);
|
|
74
|
+
expect(runtime).toBeInstanceOf(AgentRuntime);
|
|
75
|
+
expect(runtime['_runtime']).toBeInstanceOf(LobeAzureOpenAI);
|
|
76
|
+
expect(runtime['_runtime'].baseURL).toBe(jwtPayload.endpoint);
|
|
123
77
|
});
|
|
124
78
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
jwtPayload,
|
|
131
|
-
);
|
|
132
|
-
|
|
133
|
-
// 假设 LobeZhipuAI 是 ZhiPu 提供者的实现类
|
|
134
|
-
expect(runtime['_runtime']).toBeInstanceOf(LobeZhipuAI);
|
|
135
|
-
});
|
|
136
|
-
it('should initialize correctly without apiKey', async () => {
|
|
137
|
-
const jwtPayload: JWTPayload = {};
|
|
138
|
-
const runtime = await AgentRuntime.initializeWithUserPayload(
|
|
139
|
-
ModelProvider.ZhiPu,
|
|
140
|
-
jwtPayload,
|
|
141
|
-
);
|
|
142
|
-
|
|
143
|
-
// 假设 LobeZhipuAI 是 ZhiPu 提供者的实现类
|
|
144
|
-
expect(runtime['_runtime']).toBeInstanceOf(LobeZhipuAI);
|
|
145
|
-
});
|
|
79
|
+
it('ZhiPu AI provider: with apikey', async () => {
|
|
80
|
+
const jwtPayload: JWTPayload = { apiKey: 'zhipu.user-key' };
|
|
81
|
+
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.ZhiPu, jwtPayload);
|
|
82
|
+
expect(runtime).toBeInstanceOf(AgentRuntime);
|
|
83
|
+
expect(runtime['_runtime']).toBeInstanceOf(LobeZhipuAI);
|
|
146
84
|
});
|
|
147
85
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
jwtPayload,
|
|
154
|
-
);
|
|
155
|
-
|
|
156
|
-
// 假设 LobeGoogleAI 是 Google 提供者的实现类
|
|
157
|
-
expect(runtime['_runtime']).toBeInstanceOf(LobeGoogleAI);
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
it('should initialize correctly without apiKey', async () => {
|
|
161
|
-
const jwtPayload: JWTPayload = {};
|
|
162
|
-
const runtime = await AgentRuntime.initializeWithUserPayload(
|
|
163
|
-
ModelProvider.Google,
|
|
164
|
-
jwtPayload,
|
|
165
|
-
);
|
|
166
|
-
|
|
167
|
-
// 假设 LobeGoogleAI 是 Google 提供者的实现类
|
|
168
|
-
expect(runtime['_runtime']).toBeInstanceOf(LobeGoogleAI);
|
|
169
|
-
});
|
|
86
|
+
it('Google provider: with apikey', async () => {
|
|
87
|
+
const jwtPayload: JWTPayload = { apiKey: 'user-google-key' };
|
|
88
|
+
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Google, jwtPayload);
|
|
89
|
+
expect(runtime).toBeInstanceOf(AgentRuntime);
|
|
90
|
+
expect(runtime['_runtime']).toBeInstanceOf(LobeGoogleAI);
|
|
170
91
|
});
|
|
171
92
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
jwtPayload,
|
|
178
|
-
);
|
|
179
|
-
|
|
180
|
-
// 假设 LobeMoonshotAI 是 Moonshot 提供者的实现类
|
|
181
|
-
expect(runtime['_runtime']).toBeInstanceOf(LobeMoonshotAI);
|
|
182
|
-
});
|
|
183
|
-
it('should initialize correctly without apiKey', async () => {
|
|
184
|
-
const jwtPayload: JWTPayload = {};
|
|
185
|
-
const runtime = await AgentRuntime.initializeWithUserPayload(
|
|
186
|
-
ModelProvider.Moonshot,
|
|
187
|
-
jwtPayload,
|
|
188
|
-
);
|
|
189
|
-
|
|
190
|
-
// 假设 LobeMoonshotAI 是 Moonshot 提供者的实现类
|
|
191
|
-
expect(runtime['_runtime']).toBeInstanceOf(LobeMoonshotAI);
|
|
192
|
-
});
|
|
93
|
+
it('Moonshot AI provider: with apikey', async () => {
|
|
94
|
+
const jwtPayload: JWTPayload = { apiKey: 'user-moonshot-key' };
|
|
95
|
+
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Moonshot, jwtPayload);
|
|
96
|
+
expect(runtime).toBeInstanceOf(AgentRuntime);
|
|
97
|
+
expect(runtime['_runtime']).toBeInstanceOf(LobeMoonshotAI);
|
|
193
98
|
});
|
|
194
99
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
jwtPayload,
|
|
206
|
-
);
|
|
207
|
-
|
|
208
|
-
// 假设 LobeBedrockAI 是 Bedrock 提供者的实现类
|
|
209
|
-
expect(runtime['_runtime']).toBeInstanceOf(LobeBedrockAI);
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
it('should initialize correctly without apiKey', async () => {
|
|
213
|
-
const jwtPayload: JWTPayload = {};
|
|
214
|
-
const runtime = await AgentRuntime.initializeWithUserPayload(
|
|
215
|
-
ModelProvider.Bedrock,
|
|
216
|
-
jwtPayload,
|
|
217
|
-
);
|
|
218
|
-
|
|
219
|
-
// 假设 LobeBedrockAI 是 Bedrock 提供者的实现类
|
|
220
|
-
expect(runtime['_runtime']).toBeInstanceOf(LobeBedrockAI);
|
|
221
|
-
});
|
|
100
|
+
it('Bedrock AI provider: with apikey, awsAccessKeyId, awsSecretAccessKey, awsRegion', async () => {
|
|
101
|
+
const jwtPayload: JWTPayload = {
|
|
102
|
+
apiKey: 'user-bedrock-key',
|
|
103
|
+
awsAccessKeyId: 'user-aws-id',
|
|
104
|
+
awsSecretAccessKey: 'user-aws-secret',
|
|
105
|
+
awsRegion: 'user-aws-region',
|
|
106
|
+
};
|
|
107
|
+
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Bedrock, jwtPayload);
|
|
108
|
+
expect(runtime).toBeInstanceOf(AgentRuntime);
|
|
109
|
+
expect(runtime['_runtime']).toBeInstanceOf(LobeBedrockAI);
|
|
222
110
|
});
|
|
223
111
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
jwtPayload,
|
|
230
|
-
);
|
|
231
|
-
|
|
232
|
-
// 假设 LobeOllamaAI 是 Ollama 提供者的实现类
|
|
233
|
-
expect(runtime['_runtime']).toBeInstanceOf(LobeOllamaAI);
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
it('should initialize correctly without endpoint', async () => {
|
|
237
|
-
const jwtPayload: JWTPayload = {};
|
|
238
|
-
const runtime = await AgentRuntime.initializeWithUserPayload(
|
|
239
|
-
ModelProvider.Ollama,
|
|
240
|
-
jwtPayload,
|
|
241
|
-
);
|
|
242
|
-
|
|
243
|
-
// 假设 LobeOllamaAI 是 Ollama 提供者的实现类
|
|
244
|
-
expect(runtime['_runtime']).toBeInstanceOf(LobeOllamaAI);
|
|
245
|
-
});
|
|
112
|
+
it('Ollama provider: with endpoint', async () => {
|
|
113
|
+
const jwtPayload: JWTPayload = { endpoint: 'user-ollama-url' };
|
|
114
|
+
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Ollama, jwtPayload);
|
|
115
|
+
expect(runtime).toBeInstanceOf(AgentRuntime);
|
|
116
|
+
expect(runtime['_runtime']).toBeInstanceOf(LobeOllamaAI);
|
|
246
117
|
});
|
|
247
118
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
jwtPayload,
|
|
254
|
-
);
|
|
255
|
-
|
|
256
|
-
// 假设 LobePerplexityAI 是 Perplexity 提供者的实现类
|
|
257
|
-
expect(runtime['_runtime']).toBeInstanceOf(LobePerplexityAI);
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
it('should initialize correctly without apiKey', async () => {
|
|
261
|
-
const jwtPayload: JWTPayload = {};
|
|
262
|
-
const runtime = await AgentRuntime.initializeWithUserPayload(
|
|
263
|
-
ModelProvider.Perplexity,
|
|
264
|
-
jwtPayload,
|
|
265
|
-
);
|
|
266
|
-
|
|
267
|
-
// 假设 LobePerplexityAI 是 Perplexity 提供者的实现类
|
|
268
|
-
expect(runtime['_runtime']).toBeInstanceOf(LobePerplexityAI);
|
|
269
|
-
});
|
|
119
|
+
it('Perplexity AI provider: with apikey', async () => {
|
|
120
|
+
const jwtPayload: JWTPayload = { apiKey: 'user-perplexity-key' };
|
|
121
|
+
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Perplexity, jwtPayload);
|
|
122
|
+
expect(runtime).toBeInstanceOf(AgentRuntime);
|
|
123
|
+
expect(runtime['_runtime']).toBeInstanceOf(LobePerplexityAI);
|
|
270
124
|
});
|
|
271
125
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
jwtPayload,
|
|
278
|
-
);
|
|
279
|
-
|
|
280
|
-
// 假设 LobeAnthropicAI 是 Anthropic 提供者的实现类
|
|
281
|
-
expect(runtime['_runtime']).toBeInstanceOf(LobeAnthropicAI);
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
it('should initialize correctly without apiKey', async () => {
|
|
285
|
-
const jwtPayload: JWTPayload = {};
|
|
286
|
-
const runtime = await AgentRuntime.initializeWithUserPayload(
|
|
287
|
-
ModelProvider.Anthropic,
|
|
288
|
-
jwtPayload,
|
|
289
|
-
);
|
|
290
|
-
|
|
291
|
-
// 假设 LobeAnthropicAI 是 Anthropic 提供者的实现类
|
|
292
|
-
expect(runtime['_runtime']).toBeInstanceOf(LobeAnthropicAI);
|
|
293
|
-
});
|
|
126
|
+
it('Anthropic AI provider: with apikey', async () => {
|
|
127
|
+
const jwtPayload: JWTPayload = { apiKey: 'user-anthropic-key' };
|
|
128
|
+
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Anthropic, jwtPayload);
|
|
129
|
+
expect(runtime).toBeInstanceOf(AgentRuntime);
|
|
130
|
+
expect(runtime['_runtime']).toBeInstanceOf(LobeAnthropicAI);
|
|
294
131
|
});
|
|
295
132
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
jwtPayload,
|
|
302
|
-
);
|
|
303
|
-
|
|
304
|
-
// 假设 LobeMistralAI 是 Mistral 提供者的实现类
|
|
305
|
-
expect(runtime['_runtime']).toBeInstanceOf(LobeMistralAI);
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
it('should initialize correctly without apiKey', async () => {
|
|
309
|
-
const jwtPayload: JWTPayload = {};
|
|
310
|
-
const runtime = await AgentRuntime.initializeWithUserPayload(
|
|
311
|
-
ModelProvider.Mistral,
|
|
312
|
-
jwtPayload,
|
|
313
|
-
);
|
|
314
|
-
|
|
315
|
-
// 假设 LobeMistralAI 是 Mistral 提供者的实现类
|
|
316
|
-
expect(runtime['_runtime']).toBeInstanceOf(LobeMistralAI);
|
|
317
|
-
});
|
|
133
|
+
it('Mistral AI provider: with apikey', async () => {
|
|
134
|
+
const jwtPayload: JWTPayload = { apiKey: 'user-mistral-key' };
|
|
135
|
+
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Mistral, jwtPayload);
|
|
136
|
+
expect(runtime).toBeInstanceOf(AgentRuntime);
|
|
137
|
+
expect(runtime['_runtime']).toBeInstanceOf(LobeMistralAI);
|
|
318
138
|
});
|
|
319
139
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
jwtPayload,
|
|
326
|
-
);
|
|
327
|
-
|
|
328
|
-
// 假设 LobeOpenRouterAI 是 OpenRouter 提供者的实现类
|
|
329
|
-
expect(runtime['_runtime']).toBeInstanceOf(LobeOpenRouterAI);
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
it('should initialize correctly without apiKey', async () => {
|
|
333
|
-
const jwtPayload: JWTPayload = {};
|
|
334
|
-
const runtime = await AgentRuntime.initializeWithUserPayload(
|
|
335
|
-
ModelProvider.OpenRouter,
|
|
336
|
-
jwtPayload,
|
|
337
|
-
);
|
|
338
|
-
|
|
339
|
-
// 假设 LobeOpenRouterAI 是 OpenRouter 提供者的实现类
|
|
340
|
-
expect(runtime['_runtime']).toBeInstanceOf(LobeOpenRouterAI);
|
|
341
|
-
});
|
|
140
|
+
it('OpenRouter AI provider: with apikey', async () => {
|
|
141
|
+
const jwtPayload: JWTPayload = { apiKey: 'user-openrouter-key' };
|
|
142
|
+
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.OpenRouter, jwtPayload);
|
|
143
|
+
expect(runtime).toBeInstanceOf(AgentRuntime);
|
|
144
|
+
expect(runtime['_runtime']).toBeInstanceOf(LobeOpenRouterAI);
|
|
342
145
|
});
|
|
343
146
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
jwtPayload,
|
|
350
|
-
);
|
|
351
|
-
|
|
352
|
-
// 假设 LobeTogetherAI 是 TogetherAI 提供者的实现类
|
|
353
|
-
expect(runtime['_runtime']).toBeInstanceOf(LobeTogetherAI);
|
|
354
|
-
});
|
|
355
|
-
|
|
356
|
-
it('should initialize correctly without apiKey', async () => {
|
|
357
|
-
const jwtPayload: JWTPayload = {};
|
|
358
|
-
const runtime = await AgentRuntime.initializeWithUserPayload(
|
|
359
|
-
ModelProvider.TogetherAI,
|
|
360
|
-
jwtPayload,
|
|
361
|
-
);
|
|
362
|
-
|
|
363
|
-
// 假设 LobeTogetherAI 是 TogetherAI 提供者的实现类
|
|
364
|
-
expect(runtime['_runtime']).toBeInstanceOf(LobeTogetherAI);
|
|
365
|
-
});
|
|
147
|
+
it('Together AI provider: with apikey', async () => {
|
|
148
|
+
const jwtPayload: JWTPayload = { apiKey: 'user-togetherai-key' };
|
|
149
|
+
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.TogetherAI, jwtPayload);
|
|
150
|
+
expect(runtime).toBeInstanceOf(AgentRuntime);
|
|
151
|
+
expect(runtime['_runtime']).toBeInstanceOf(LobeTogetherAI);
|
|
366
152
|
});
|
|
367
153
|
|
|
368
|
-
it('
|
|
369
|
-
const jwtPayload
|
|
370
|
-
const runtime = await
|
|
154
|
+
it('ZeroOne AI provider: with apikey', async () => {
|
|
155
|
+
const jwtPayload = { apiKey: 'user-zeroone-key' };
|
|
156
|
+
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.ZeroOne, jwtPayload);
|
|
157
|
+
expect(runtime).toBeInstanceOf(AgentRuntime);
|
|
158
|
+
expect(runtime['_runtime']).toBeInstanceOf(LobeZeroOneAI);
|
|
159
|
+
});
|
|
371
160
|
|
|
372
|
-
|
|
373
|
-
|
|
161
|
+
it('Groq AI provider: with apikey', async () => {
|
|
162
|
+
const jwtPayload = { apiKey: 'user-zeroone-key' };
|
|
163
|
+
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Groq, jwtPayload);
|
|
164
|
+
expect(runtime).toBeInstanceOf(AgentRuntime);
|
|
165
|
+
expect(runtime['_runtime']).toBeInstanceOf(LobeGroq);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('Unknown Provider: with apikey and endpoint, should initialize to OpenAi', async () => {
|
|
169
|
+
const jwtPayload: JWTPayload = {
|
|
170
|
+
apiKey: 'user-unknown-key',
|
|
171
|
+
endpoint: 'user-unknown-endpoint',
|
|
172
|
+
};
|
|
173
|
+
const runtime = await initAgentRuntimeWithUserPayload('unknown', jwtPayload);
|
|
174
|
+
expect(runtime).toBeInstanceOf(AgentRuntime);
|
|
374
175
|
expect(runtime['_runtime']).toBeInstanceOf(LobeOpenAI);
|
|
176
|
+
expect(runtime['_runtime'].baseURL).toBe(jwtPayload.endpoint);
|
|
375
177
|
});
|
|
376
178
|
});
|
|
377
179
|
|
|
378
|
-
describe('
|
|
379
|
-
it('
|
|
380
|
-
const jwtPayload: JWTPayload = {
|
|
381
|
-
const runtime = await
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
);
|
|
385
|
-
|
|
386
|
-
const payload: ChatStreamPayload = {
|
|
387
|
-
messages: [{ role: 'user', content: 'Hello, world!' }],
|
|
388
|
-
model: 'text-davinci-002',
|
|
389
|
-
temperature: 0,
|
|
390
|
-
};
|
|
180
|
+
describe('should initialize without some options', () => {
|
|
181
|
+
it('OpenAI provider: without apikey', async () => {
|
|
182
|
+
const jwtPayload: JWTPayload = {};
|
|
183
|
+
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.OpenAI, jwtPayload);
|
|
184
|
+
expect(runtime['_runtime']).toBeInstanceOf(LobeOpenAI);
|
|
185
|
+
});
|
|
391
186
|
|
|
392
|
-
|
|
187
|
+
it('Azure AI Provider: without apikey', async () => {
|
|
188
|
+
const jwtPayload: JWTPayload = {};
|
|
189
|
+
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Azure, jwtPayload);
|
|
393
190
|
|
|
394
|
-
|
|
191
|
+
expect(runtime['_runtime']).toBeInstanceOf(LobeAzureOpenAI);
|
|
395
192
|
});
|
|
396
|
-
it('should handle options correctly', async () => {
|
|
397
|
-
const jwtPayload: JWTPayload = { apiKey: 'user-openai-key', endpoint: 'user-endpoint' };
|
|
398
|
-
const runtime = await AgentRuntime.initializeWithUserPayload(
|
|
399
|
-
ModelProvider.OpenAI,
|
|
400
|
-
jwtPayload,
|
|
401
|
-
);
|
|
402
|
-
|
|
403
|
-
const payload: ChatStreamPayload = {
|
|
404
|
-
messages: [{ role: 'user', content: 'Hello, world!' }],
|
|
405
|
-
model: 'text-davinci-002',
|
|
406
|
-
temperature: 0,
|
|
407
|
-
};
|
|
408
193
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
traceId: 'test-trace-id',
|
|
413
|
-
traceName: TraceNameMap.Conversation,
|
|
414
|
-
sessionId: 'test-session-id',
|
|
415
|
-
topicId: 'test-topic-id',
|
|
416
|
-
tags: [],
|
|
417
|
-
userId: 'test-user-id',
|
|
418
|
-
},
|
|
419
|
-
};
|
|
194
|
+
it('ZhiPu AI provider: without apikey', async () => {
|
|
195
|
+
const jwtPayload: JWTPayload = {};
|
|
196
|
+
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.ZhiPu, jwtPayload);
|
|
420
197
|
|
|
421
|
-
|
|
198
|
+
// 假设 LobeZhipuAI 是 ZhiPu 提供者的实现类
|
|
199
|
+
expect(runtime['_runtime']).toBeInstanceOf(LobeZhipuAI);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it('Google provider: without apikey', async () => {
|
|
203
|
+
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Google, {});
|
|
422
204
|
|
|
423
|
-
|
|
205
|
+
// 假设 LobeGoogleAI 是 Google 提供者的实现类
|
|
206
|
+
expect(runtime['_runtime']).toBeInstanceOf(LobeGoogleAI);
|
|
424
207
|
});
|
|
425
208
|
|
|
426
|
-
|
|
427
|
-
const jwtPayload: JWTPayload = {
|
|
428
|
-
const runtime = await
|
|
429
|
-
ModelProvider.OpenAI,
|
|
430
|
-
jwtPayload,
|
|
431
|
-
);
|
|
432
|
-
|
|
433
|
-
const payload: ChatStreamPayload = {
|
|
434
|
-
messages: [{ role: 'user', content: 'Hello, world!' }],
|
|
435
|
-
model: 'text-davinci-002',
|
|
436
|
-
temperature: 0,
|
|
437
|
-
};
|
|
209
|
+
it('Moonshot AI provider: without apikey', async () => {
|
|
210
|
+
const jwtPayload: JWTPayload = {};
|
|
211
|
+
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Moonshot, jwtPayload);
|
|
438
212
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
213
|
+
// 假设 LobeMoonshotAI 是 Moonshot 提供者的实现类
|
|
214
|
+
expect(runtime['_runtime']).toBeInstanceOf(LobeMoonshotAI);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it('Bedrock AI provider: without apikey', async () => {
|
|
218
|
+
const jwtPayload = {};
|
|
219
|
+
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Bedrock, jwtPayload);
|
|
220
|
+
|
|
221
|
+
// 假设 LobeBedrockAI 是 Bedrock 提供者的实现类
|
|
222
|
+
expect(runtime['_runtime']).toBeInstanceOf(LobeBedrockAI);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('Ollama provider: without endpoint', async () => {
|
|
226
|
+
const jwtPayload = {};
|
|
227
|
+
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Ollama, jwtPayload);
|
|
228
|
+
|
|
229
|
+
// 假设 LobeOllamaAI 是 Ollama 提供者的实现类
|
|
230
|
+
expect(runtime['_runtime']).toBeInstanceOf(LobeOllamaAI);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('Perplexity AI provider: without apikey', async () => {
|
|
234
|
+
const jwtPayload = {};
|
|
235
|
+
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Perplexity, jwtPayload);
|
|
236
|
+
|
|
237
|
+
// 假设 LobePerplexityAI 是 Perplexity 提供者的实现类
|
|
238
|
+
expect(runtime['_runtime']).toBeInstanceOf(LobePerplexityAI);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('Anthropic AI provider: without apikey', async () => {
|
|
242
|
+
const jwtPayload = {};
|
|
243
|
+
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Anthropic, jwtPayload);
|
|
244
|
+
|
|
245
|
+
// 假设 LobeAnthropicAI 是 Anthropic 提供者的实现类
|
|
246
|
+
expect(runtime['_runtime']).toBeInstanceOf(LobeAnthropicAI);
|
|
247
|
+
});
|
|
451
248
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
callback.onStart();
|
|
484
|
-
}
|
|
485
|
-
return new Response('Success');
|
|
486
|
-
},
|
|
487
|
-
);
|
|
488
|
-
|
|
489
|
-
await runtime.chat(payload, options);
|
|
490
|
-
|
|
491
|
-
// Verify onStart was called
|
|
492
|
-
expect(updateMock).toHaveBeenCalledWith({ completionStartTime: expect.any(Date) });
|
|
493
|
-
});
|
|
494
|
-
|
|
495
|
-
it('should call onCompletion correctly', async () => {
|
|
496
|
-
// Spy on the chat method and trigger onCompletion callback
|
|
497
|
-
vi.spyOn(LangfuseGenerationClient.prototype, 'update').mockImplementation(updateMock);
|
|
498
|
-
vi.spyOn(LobeOpenAI.prototype, 'chat').mockImplementation(
|
|
499
|
-
async (payload, { callback }: any) => {
|
|
500
|
-
if (callback?.onCompletion) {
|
|
501
|
-
await callback.onCompletion('Test completion');
|
|
502
|
-
}
|
|
503
|
-
return new Response('Success');
|
|
504
|
-
},
|
|
505
|
-
);
|
|
506
|
-
|
|
507
|
-
await runtime.chat(payload, options);
|
|
508
|
-
|
|
509
|
-
// Verify onCompletion was called with expected output
|
|
510
|
-
expect(updateMock).toHaveBeenCalledWith({
|
|
511
|
-
endTime: expect.any(Date),
|
|
512
|
-
metadata: {
|
|
513
|
-
provider: 'openai',
|
|
514
|
-
tools: undefined,
|
|
515
|
-
},
|
|
516
|
-
output: 'Test completion',
|
|
517
|
-
});
|
|
518
|
-
});
|
|
519
|
-
it('should call onFinal correctly', async () => {
|
|
520
|
-
vi.spyOn(LobeOpenAI.prototype, 'chat').mockImplementation(
|
|
521
|
-
async (payload, { callback }: any) => {
|
|
522
|
-
if (callback?.onFinal) {
|
|
523
|
-
await callback.onFinal('Test completion');
|
|
524
|
-
}
|
|
525
|
-
return new Response('Success');
|
|
526
|
-
},
|
|
527
|
-
);
|
|
528
|
-
const shutdownAsyncMock = vi.fn();
|
|
529
|
-
vi.spyOn(Langfuse.prototype, 'shutdownAsync').mockImplementation(shutdownAsyncMock);
|
|
530
|
-
|
|
531
|
-
await runtime.chat(payload, options);
|
|
532
|
-
|
|
533
|
-
// Verify onCompletion was called with expected output
|
|
534
|
-
expect(shutdownAsyncMock).toHaveBeenCalled();
|
|
535
|
-
});
|
|
249
|
+
it('Mistral AI provider: without apikey', async () => {
|
|
250
|
+
const jwtPayload = {};
|
|
251
|
+
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Mistral, jwtPayload);
|
|
252
|
+
|
|
253
|
+
// 假设 LobeMistralAI 是 Mistral 提供者的实现类
|
|
254
|
+
expect(runtime['_runtime']).toBeInstanceOf(LobeMistralAI);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
it('OpenRouter AI provider: without apikey', async () => {
|
|
258
|
+
const jwtPayload = {};
|
|
259
|
+
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.OpenRouter, jwtPayload);
|
|
260
|
+
|
|
261
|
+
// 假设 LobeOpenRouterAI 是 OpenRouter 提供者的实现类
|
|
262
|
+
expect(runtime['_runtime']).toBeInstanceOf(LobeOpenRouterAI);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it('Together AI provider: without apikey', async () => {
|
|
266
|
+
const jwtPayload = {};
|
|
267
|
+
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.TogetherAI, jwtPayload);
|
|
268
|
+
|
|
269
|
+
// 假设 LobeTogetherAI 是 TogetherAI 提供者的实现类
|
|
270
|
+
expect(runtime['_runtime']).toBeInstanceOf(LobeTogetherAI);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it('Unknown Provider', async () => {
|
|
274
|
+
const jwtPayload = {};
|
|
275
|
+
const runtime = await initAgentRuntimeWithUserPayload('unknown', jwtPayload);
|
|
276
|
+
|
|
277
|
+
// 根据实际实现,你可能需要检查是否返回了默认的 runtime 实例,或者是否抛出了异常
|
|
278
|
+
// 例如,如果默认使用 OpenAI:
|
|
279
|
+
expect(runtime['_runtime']).toBeInstanceOf(LobeOpenAI);
|
|
536
280
|
});
|
|
537
281
|
});
|
|
538
282
|
});
|