@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.
Files changed (52) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/locales/ar/setting.json +4 -0
  3. package/locales/bg-BG/setting.json +4 -0
  4. package/locales/de-DE/setting.json +4 -0
  5. package/locales/en-US/setting.json +4 -0
  6. package/locales/es-ES/setting.json +4 -0
  7. package/locales/fr-FR/setting.json +4 -0
  8. package/locales/it-IT/setting.json +4 -0
  9. package/locales/ja-JP/setting.json +4 -0
  10. package/locales/ko-KR/setting.json +4 -0
  11. package/locales/nl-NL/setting.json +4 -0
  12. package/locales/pl-PL/setting.json +4 -0
  13. package/locales/pt-BR/setting.json +4 -0
  14. package/locales/ru-RU/setting.json +4 -0
  15. package/locales/tr-TR/setting.json +4 -0
  16. package/locales/vi-VN/setting.json +4 -0
  17. package/locales/zh-CN/setting.json +4 -0
  18. package/locales/zh-TW/setting.json +4 -0
  19. package/package.json +3 -2
  20. package/public/favicon-32x32.ico +0 -0
  21. package/public/favicon.ico +0 -0
  22. package/public/icons/apple-touch-icon.png +0 -0
  23. package/src/app/api/chat/[provider]/route.test.ts +5 -7
  24. package/src/app/api/chat/[provider]/route.ts +13 -7
  25. package/src/app/api/chat/agentRuntime.test.ts +195 -451
  26. package/src/app/api/chat/agentRuntime.ts +197 -280
  27. package/src/app/api/chat/models/[provider]/route.ts +2 -2
  28. package/src/app/chat/features/TopicListContent/Topic/TopicContent.tsx +2 -2
  29. package/src/app/metadata.ts +3 -5
  30. package/src/app/settings/llm/components/ProviderConfig/index.tsx +23 -1
  31. package/src/app/settings/llm/index.tsx +2 -2
  32. package/src/app/settings/llm/page.tsx +1 -5
  33. package/src/features/ChatInput/Topic/index.tsx +6 -2
  34. package/src/features/Conversation/components/ChatItem/index.tsx +8 -3
  35. package/src/libs/agent-runtime/AgentRuntime.test.ts +400 -0
  36. package/src/libs/agent-runtime/AgentRuntime.ts +192 -0
  37. package/src/libs/agent-runtime/index.ts +1 -0
  38. package/src/libs/swr/index.ts +9 -0
  39. package/src/locales/default/setting.ts +4 -0
  40. package/src/services/__tests__/chat.test.ts +287 -1
  41. package/src/services/chat.ts +148 -2
  42. package/src/store/chat/slices/message/action.ts +80 -42
  43. package/src/store/chat/slices/message/initialState.ts +1 -1
  44. package/src/store/chat/slices/message/reducer.ts +32 -1
  45. package/src/store/chat/slices/topic/action.test.ts +25 -2
  46. package/src/store/chat/slices/topic/action.ts +24 -7
  47. package/src/store/chat/slices/topic/reducer.test.ts +141 -0
  48. package/src/store/chat/slices/topic/reducer.ts +67 -0
  49. package/src/store/global/slices/settings/selectors/modelConfig.ts +13 -0
  50. package/src/store/session/slices/session/action.ts +4 -5
  51. package/src/types/settings/modelProvider.ts +4 -0
  52. package/vercel.json +1 -1
@@ -1,17 +1,13 @@
1
1
  // @vitest-environment node
2
- import { Langfuse } from 'langfuse';
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 AgentRuntime, { AgentChatOptions } from './agentRuntime';
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
- describe('AgentRuntime', () => {
54
- describe('should initialize with various providers', () => {
55
- describe('OpenAI provider', () => {
56
- it('should initialize correctly', async () => {
57
- const jwtPayload: JWTPayload = { apiKey: 'user-openai-key', endpoint: 'user-endpoint' };
58
- const runtime = await AgentRuntime.initializeWithUserPayload(
59
- ModelProvider.OpenAI,
60
- jwtPayload,
61
- );
62
-
63
- expect(runtime).toBeInstanceOf(AgentRuntime);
64
- expect(runtime['_runtime']).toBeInstanceOf(LobeOpenAI);
65
- expect(runtime['_runtime'].baseURL).toBe('user-endpoint');
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
- describe('Azure OpenAI provider', () => {
70
- it('should initialize correctly', async () => {
71
- const jwtPayload: JWTPayload = {
72
- apiKey: 'user-azure-key',
73
- endpoint: 'user-azure-endpoint',
74
- azureApiVersion: '2024-02-01',
75
- };
76
- const runtime = await AgentRuntime.initializeWithUserPayload(
77
- ModelProvider.Azure,
78
- jwtPayload,
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
- describe('ZhiPu AI provider', () => {
126
- it('should initialize correctly', async () => {
127
- const jwtPayload: JWTPayload = { apiKey: 'zhipu.user-key' };
128
- const runtime = await AgentRuntime.initializeWithUserPayload(
129
- ModelProvider.ZhiPu,
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
- describe('Google provider', () => {
149
- it('should initialize correctly', async () => {
150
- const jwtPayload: JWTPayload = { apiKey: 'user-google-key' };
151
- const runtime = await AgentRuntime.initializeWithUserPayload(
152
- ModelProvider.Google,
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
- describe('Moonshot AI provider', () => {
173
- it('should initialize correctly', async () => {
174
- const jwtPayload: JWTPayload = { apiKey: 'user-moonshot-key' };
175
- const runtime = await AgentRuntime.initializeWithUserPayload(
176
- ModelProvider.Moonshot,
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
- describe('Bedrock AI provider', () => {
196
- it('should initialize correctly with payload apiKey', async () => {
197
- const jwtPayload: JWTPayload = {
198
- apiKey: 'user-bedrock-key',
199
- awsAccessKeyId: 'user-aws-id',
200
- awsSecretAccessKey: 'user-aws-secret',
201
- awsRegion: 'user-aws-region',
202
- };
203
- const runtime = await AgentRuntime.initializeWithUserPayload(
204
- ModelProvider.Bedrock,
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
- describe('Ollama provider', () => {
225
- it('should initialize correctly', async () => {
226
- const jwtPayload: JWTPayload = { endpoint: 'user-ollama-url' };
227
- const runtime = await AgentRuntime.initializeWithUserPayload(
228
- ModelProvider.Ollama,
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
- describe('Perplexity AI provider', () => {
249
- it('should initialize correctly', async () => {
250
- const jwtPayload: JWTPayload = { apiKey: 'user-perplexity-key' };
251
- const runtime = await AgentRuntime.initializeWithUserPayload(
252
- ModelProvider.Perplexity,
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
- describe('Anthropic AI provider', () => {
273
- it('should initialize correctly', async () => {
274
- const jwtPayload: JWTPayload = { apiKey: 'user-anthropic-key' };
275
- const runtime = await AgentRuntime.initializeWithUserPayload(
276
- ModelProvider.Anthropic,
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
- describe('Mistral AI provider', () => {
297
- it('should initialize correctly', async () => {
298
- const jwtPayload: JWTPayload = { apiKey: 'user-mistral-key' };
299
- const runtime = await AgentRuntime.initializeWithUserPayload(
300
- ModelProvider.Mistral,
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
- describe('OpenRouter AI provider', () => {
321
- it('should initialize correctly', async () => {
322
- const jwtPayload: JWTPayload = { apiKey: 'user-openrouter-key' };
323
- const runtime = await AgentRuntime.initializeWithUserPayload(
324
- ModelProvider.OpenRouter,
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
- describe('Together AI provider', () => {
345
- it('should initialize correctly', async () => {
346
- const jwtPayload: JWTPayload = { apiKey: 'user-togetherai-key' };
347
- const runtime = await AgentRuntime.initializeWithUserPayload(
348
- ModelProvider.TogetherAI,
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('should handle unknown provider gracefully', async () => {
369
- const jwtPayload: JWTPayload = {};
370
- const runtime = await AgentRuntime.initializeWithUserPayload('unknown', jwtPayload);
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
- // 根据实际实现,你可能需要检查是否返回了默认的 runtime 实例,或者是否抛出了异常
373
- // 例如,如果默认使用 OpenAI:
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('AgentRuntime chat method', () => {
379
- it('should run correctly', async () => {
380
- const jwtPayload: JWTPayload = { apiKey: 'user-openai-key', endpoint: 'user-endpoint' };
381
- const runtime = await AgentRuntime.initializeWithUserPayload(
382
- ModelProvider.OpenAI,
383
- jwtPayload,
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
- vi.spyOn(LobeOpenAI.prototype, 'chat').mockResolvedValue(new Response(''));
187
+ it('Azure AI Provider: without apikey', async () => {
188
+ const jwtPayload: JWTPayload = {};
189
+ const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Azure, jwtPayload);
393
190
 
394
- await runtime.chat(payload, { provider: 'openai' });
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
- const options: AgentChatOptions = {
410
- provider: 'openai',
411
- trace: {
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
- vi.spyOn(LobeOpenAI.prototype, 'chat').mockResolvedValue(new Response(''));
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
- await runtime.chat(payload, options);
205
+ // 假设 LobeGoogleAI 是 Google 提供者的实现类
206
+ expect(runtime['_runtime']).toBeInstanceOf(LobeGoogleAI);
424
207
  });
425
208
 
426
- describe('callback', async () => {
427
- const jwtPayload: JWTPayload = { apiKey: 'user-openai-key', endpoint: 'user-endpoint' };
428
- const runtime = await AgentRuntime.initializeWithUserPayload(
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
- const options: AgentChatOptions = {
440
- provider: 'openai',
441
- trace: {
442
- traceId: 'test-trace-id',
443
- traceName: TraceNameMap.Conversation,
444
- sessionId: 'test-session-id',
445
- topicId: 'test-topic-id',
446
- tags: [],
447
- userId: 'test-user-id',
448
- },
449
- enableTrace: true,
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
- const updateMock = vi.fn();
453
- beforeEach(() => {
454
- vi.mocked(getServerConfig).mockReturnValue({
455
- ENABLE_LANGFUSE: true,
456
- LANGFUSE_PUBLIC_KEY: 'abc',
457
- LANGFUSE_SECRET_KEY: 'DDD',
458
- } as any);
459
- });
460
-
461
- it('should call experimental_onToolCall correctly', async () => {
462
- // 使用 spyOn 模拟 chat 方法
463
- vi.spyOn(LobeOpenAI.prototype, 'chat').mockImplementation(
464
- async (payload, { callback }: any) => {
465
- // 模拟 experimental_onToolCall 回调的触发
466
- if (callback?.experimental_onToolCall) {
467
- await callback.experimental_onToolCall();
468
- }
469
- return new Response('abc');
470
- },
471
- );
472
- vi.spyOn(LangfuseTraceClient.prototype, 'update').mockImplementation(updateMock);
473
-
474
- await runtime.chat(payload, options);
475
-
476
- expect(updateMock).toHaveBeenCalledWith({ tags: ['Tools Call'] });
477
- });
478
- it('should call onStart correctly', async () => {
479
- vi.spyOn(LangfuseGenerationClient.prototype, 'update').mockImplementation(updateMock);
480
- vi.spyOn(LobeOpenAI.prototype, 'chat').mockImplementation(
481
- async (payload, { callback }: any) => {
482
- if (callback?.onStart) {
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
  });