@lobehub/chat 1.73.2 → 1.74.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/.env.example +4 -0
- package/CHANGELOG.md +26 -0
- package/Dockerfile +5 -1
- package/Dockerfile.database +5 -1
- package/Dockerfile.pglite +3 -1
- package/README.md +1 -0
- package/README.zh-CN.md +1 -0
- package/changelog/v1.json +9 -0
- package/docs/self-hosting/environment-variables/model-provider.mdx +13 -0
- package/docs/self-hosting/environment-variables/model-provider.zh-CN.mdx +14 -0
- package/docs/usage/providers/infiniai.mdx +29 -0
- package/docs/usage/providers/infiniai.zh-CN.mdx +29 -0
- package/locales/ar/models.json +30 -0
- package/locales/ar/providers.json +3 -0
- package/locales/bg-BG/models.json +30 -0
- package/locales/bg-BG/providers.json +3 -0
- package/locales/de-DE/models.json +30 -0
- package/locales/de-DE/providers.json +3 -0
- package/locales/en-US/models.json +30 -0
- package/locales/en-US/providers.json +3 -0
- package/locales/es-ES/models.json +30 -0
- package/locales/es-ES/providers.json +3 -0
- package/locales/fa-IR/models.json +30 -0
- package/locales/fa-IR/providers.json +3 -0
- package/locales/fr-FR/models.json +30 -0
- package/locales/fr-FR/providers.json +3 -0
- package/locales/it-IT/models.json +30 -0
- package/locales/it-IT/providers.json +3 -0
- package/locales/ja-JP/models.json +22 -0
- package/locales/ja-JP/providers.json +3 -0
- package/locales/ko-KR/models.json +30 -0
- package/locales/ko-KR/providers.json +3 -0
- package/locales/nl-NL/models.json +30 -0
- package/locales/nl-NL/providers.json +3 -0
- package/locales/pl-PL/models.json +30 -0
- package/locales/pl-PL/providers.json +3 -0
- package/locales/pt-BR/models.json +30 -0
- package/locales/pt-BR/providers.json +3 -0
- package/locales/ru-RU/models.json +30 -0
- package/locales/ru-RU/providers.json +3 -0
- package/locales/tr-TR/models.json +30 -0
- package/locales/tr-TR/providers.json +3 -0
- package/locales/vi-VN/models.json +30 -0
- package/locales/vi-VN/providers.json +3 -0
- package/locales/zh-CN/models.json +30 -0
- package/locales/zh-CN/providers.json +3 -0
- package/locales/zh-TW/models.json +19 -0
- package/locales/zh-TW/providers.json +3 -0
- package/package.json +3 -3
- package/packages/web-crawler/src/utils/htmlToMarkdown.test.ts +1 -1
- package/src/app/[variants]/(main)/settings/llm/ProviderList/providers.tsx +5 -1
- package/src/config/aiModels/index.ts +6 -0
- package/src/config/aiModels/infiniai.ts +307 -0
- package/src/config/aiModels/search1api.ts +62 -0
- package/src/config/llm.ts +12 -0
- package/src/config/modelProviders/index.ts +8 -0
- package/src/config/modelProviders/infiniai.ts +184 -0
- package/src/config/modelProviders/search1api.ts +58 -0
- package/src/database/models/__tests__/knowledgeBase.test.ts +2 -0
- package/src/libs/agent-runtime/ai21/index.test.ts +8 -250
- package/src/libs/agent-runtime/ai360/index.test.ts +8 -250
- package/src/libs/agent-runtime/anthropic/index.ts +5 -1
- package/src/libs/agent-runtime/deepseek/index.test.ts +119 -335
- package/src/libs/agent-runtime/fireworksai/index.test.ts +8 -247
- package/src/libs/agent-runtime/giteeai/index.test.ts +8 -250
- package/src/libs/agent-runtime/github/index.test.ts +8 -207
- package/src/libs/agent-runtime/infiniai/index.ts +43 -0
- package/src/libs/agent-runtime/internlm/index.test.ts +8 -250
- package/src/libs/agent-runtime/lmstudio/index.test.ts +8 -247
- package/src/libs/agent-runtime/moonshot/index.test.ts +10 -243
- package/src/libs/agent-runtime/novita/index.test.ts +9 -221
- package/src/libs/agent-runtime/ollama/index.test.ts +4 -4
- package/src/libs/agent-runtime/openrouter/index.test.ts +12 -217
- package/src/libs/agent-runtime/ppio/index.test.ts +11 -220
- package/src/libs/agent-runtime/providerTestUtils.ts +6 -6
- package/src/libs/agent-runtime/qwen/index.test.ts +10 -242
- package/src/libs/agent-runtime/runtimeMap.ts +4 -0
- package/src/libs/agent-runtime/search1api/index.ts +64 -0
- package/src/libs/agent-runtime/sensenova/index.test.ts +10 -242
- package/src/libs/agent-runtime/spark/index.test.ts +7 -242
- package/src/libs/agent-runtime/stepfun/index.test.ts +7 -242
- package/src/libs/agent-runtime/taichu/index.test.ts +12 -220
- package/src/libs/agent-runtime/types/type.ts +2 -0
- package/src/libs/agent-runtime/upstage/index.test.ts +7 -250
- package/src/libs/agent-runtime/utils/openaiCompatibleFactory/index.test.ts +2 -2
- package/src/libs/agent-runtime/xai/index.test.ts +8 -250
- package/src/services/chat.ts +1 -4
- package/src/types/user/settings/keyVaults.ts +2 -0
- package/src/utils/fetch/__tests__/parseToolCalls.test.ts +9 -11
- package/src/utils/server/jwt.test.ts +1 -1
- package/vitest.server.config.ts +3 -1
@@ -1,27 +1,29 @@
|
|
1
1
|
// @vitest-environment node
|
2
|
-
import OpenAI from 'openai';
|
3
2
|
import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
4
3
|
|
5
4
|
import {
|
6
|
-
ChatStreamCallbacks,
|
7
5
|
ChatStreamPayload,
|
8
6
|
LLMRoleType,
|
9
7
|
LobeOpenAICompatibleRuntime,
|
10
8
|
ModelProvider,
|
11
9
|
} from '@/libs/agent-runtime';
|
10
|
+
import { testProvider } from '@/libs/agent-runtime/providerTestUtils';
|
12
11
|
|
13
|
-
import * as debugStreamModule from '../utils/debugStream';
|
14
12
|
import { LobeDeepSeekAI } from './index';
|
15
|
-
import { LobeOpenAICompatibleFactory } from '../utils/openaiCompatibleFactory';
|
16
13
|
|
17
14
|
const provider = ModelProvider.DeepSeek;
|
18
15
|
const defaultBaseURL = 'https://api.deepseek.com/v1';
|
19
16
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
17
|
+
testProvider({
|
18
|
+
Runtime: LobeDeepSeekAI,
|
19
|
+
provider,
|
20
|
+
defaultBaseURL,
|
21
|
+
chatDebugEnv: 'DEBUG_DEEPSEEK_CHAT_COMPLETION',
|
22
|
+
chatModel: 'deepseek-r1',
|
23
|
+
test: {
|
24
|
+
skipAPICall: true,
|
25
|
+
},
|
26
|
+
});
|
25
27
|
|
26
28
|
let instance: LobeOpenAICompatibleRuntime;
|
27
29
|
|
@@ -32,7 +34,9 @@ const mockSuccessfulChatCompletion = () => {
|
|
32
34
|
id: 'cmpl-mock',
|
33
35
|
object: 'chat.completion',
|
34
36
|
created: Date.now(),
|
35
|
-
choices: [
|
37
|
+
choices: [
|
38
|
+
{ index: 0, message: { role: 'assistant', content: 'Mock response' }, finish_reason: 'stop' },
|
39
|
+
],
|
36
40
|
} as any);
|
37
41
|
};
|
38
42
|
|
@@ -50,341 +54,121 @@ afterEach(() => {
|
|
50
54
|
});
|
51
55
|
|
52
56
|
describe('LobeDeepSeekAI', () => {
|
53
|
-
describe('
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
expect(instance.baseURL).toEqual(defaultBaseURL);
|
57
|
+
describe('deepseek-reasoner', () => {
|
58
|
+
beforeEach(() => {
|
59
|
+
instance = createDeepSeekAIInstance();
|
60
|
+
mockSuccessfulChatCompletion();
|
58
61
|
});
|
59
|
-
});
|
60
|
-
|
61
|
-
describe('chat', () => {
|
62
|
-
describe('Error', () => {
|
63
|
-
it('should return OpenAIBizError with an openai error response when OpenAI.APIError is thrown', async () => {
|
64
|
-
// Arrange
|
65
|
-
const apiError = new OpenAI.APIError(
|
66
|
-
400,
|
67
|
-
{
|
68
|
-
status: 400,
|
69
|
-
error: {
|
70
|
-
message: 'Bad Request',
|
71
|
-
},
|
72
|
-
},
|
73
|
-
'Error message',
|
74
|
-
{},
|
75
|
-
);
|
76
|
-
|
77
|
-
vi.spyOn(instance['client'].chat.completions, 'create').mockRejectedValue(apiError);
|
78
|
-
|
79
|
-
// Act
|
80
|
-
try {
|
81
|
-
await instance.chat({
|
82
|
-
messages: [{ content: 'Hello', role: 'user' }],
|
83
|
-
model: 'deepseek-chat',
|
84
|
-
temperature: 0,
|
85
|
-
});
|
86
|
-
} catch (e) {
|
87
|
-
expect(e).toEqual({
|
88
|
-
endpoint: defaultBaseURL,
|
89
|
-
error: {
|
90
|
-
error: { message: 'Bad Request' },
|
91
|
-
status: 400,
|
92
|
-
},
|
93
|
-
errorType: bizErrorType,
|
94
|
-
provider,
|
95
|
-
});
|
96
|
-
}
|
97
|
-
});
|
98
|
-
|
99
|
-
it('should throw AgentRuntimeError with NoOpenAIAPIKey if no apiKey is provided', async () => {
|
100
|
-
try {
|
101
|
-
new LobeDeepSeekAI({});
|
102
|
-
} catch (e) {
|
103
|
-
expect(e).toEqual({ errorType: invalidErrorType });
|
104
|
-
}
|
105
|
-
});
|
106
|
-
|
107
|
-
it('should return OpenAIBizError with the cause when OpenAI.APIError is thrown with cause', async () => {
|
108
|
-
// Arrange
|
109
|
-
const errorInfo = {
|
110
|
-
stack: 'abc',
|
111
|
-
cause: {
|
112
|
-
message: 'api is undefined',
|
113
|
-
},
|
114
|
-
};
|
115
|
-
const apiError = new OpenAI.APIError(400, errorInfo, 'module error', {});
|
116
|
-
|
117
|
-
vi.spyOn(instance['client'].chat.completions, 'create').mockRejectedValue(apiError);
|
118
|
-
|
119
|
-
// Act
|
120
|
-
try {
|
121
|
-
await instance.chat({
|
122
|
-
messages: [{ content: 'Hello', role: 'user' }],
|
123
|
-
model: 'deepseek-chat',
|
124
|
-
temperature: 0,
|
125
|
-
});
|
126
|
-
} catch (e) {
|
127
|
-
expect(e).toEqual({
|
128
|
-
endpoint: defaultBaseURL,
|
129
|
-
error: {
|
130
|
-
cause: { message: 'api is undefined' },
|
131
|
-
stack: 'abc',
|
132
|
-
},
|
133
|
-
errorType: bizErrorType,
|
134
|
-
provider,
|
135
|
-
});
|
136
|
-
}
|
137
|
-
});
|
138
62
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
stack: 'abc',
|
143
|
-
cause: { message: 'api is undefined' },
|
144
|
-
};
|
145
|
-
const apiError = new OpenAI.APIError(400, errorInfo, 'module error', {});
|
63
|
+
it('should insert a user message if the first message is from assistant', async () => {
|
64
|
+
const payloadMessages = [{ content: 'Hello', role: 'assistant' as LLMRoleType }];
|
65
|
+
const expectedMessages = [{ content: '', role: 'user' }, ...payloadMessages];
|
146
66
|
|
147
|
-
|
148
|
-
|
67
|
+
const payload: ChatStreamPayload = {
|
68
|
+
messages: payloadMessages,
|
69
|
+
model: 'deepseek-reasoner',
|
70
|
+
temperature: 0,
|
71
|
+
};
|
149
72
|
|
150
|
-
|
151
|
-
});
|
73
|
+
await instance.chat(payload);
|
152
74
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
await instance.chat({
|
158
|
-
messages: [{ content: 'Hello', role: 'user' }],
|
159
|
-
model: 'deepseek-chat',
|
160
|
-
temperature: 0,
|
161
|
-
});
|
162
|
-
} catch (e) {
|
163
|
-
expect(e).toEqual({
|
164
|
-
endpoint: 'https://api.***.com/v1',
|
165
|
-
error: {
|
166
|
-
cause: { message: 'api is undefined' },
|
167
|
-
stack: 'abc',
|
168
|
-
},
|
169
|
-
errorType: bizErrorType,
|
170
|
-
provider,
|
171
|
-
});
|
172
|
-
}
|
173
|
-
});
|
174
|
-
|
175
|
-
it('should throw an InvalidDeepSeekAPIKey error type on 401 status code', async () => {
|
176
|
-
// Mock the API call to simulate a 401 error
|
177
|
-
const error = new Error('Unauthorized') as any;
|
178
|
-
error.status = 401;
|
179
|
-
vi.mocked(instance['client'].chat.completions.create).mockRejectedValue(error);
|
180
|
-
|
181
|
-
try {
|
182
|
-
await instance.chat({
|
183
|
-
messages: [{ content: 'Hello', role: 'user' }],
|
184
|
-
model: 'deepseek-chat',
|
185
|
-
temperature: 0,
|
186
|
-
});
|
187
|
-
} catch (e) {
|
188
|
-
// Expect the chat method to throw an error with InvalidDeepSeekAPIKey
|
189
|
-
expect(e).toEqual({
|
190
|
-
endpoint: defaultBaseURL,
|
191
|
-
error: new Error('Unauthorized'),
|
192
|
-
errorType: invalidErrorType,
|
193
|
-
provider,
|
194
|
-
});
|
195
|
-
}
|
196
|
-
});
|
197
|
-
|
198
|
-
it('should return AgentRuntimeError for non-OpenAI errors', async () => {
|
199
|
-
// Arrange
|
200
|
-
const genericError = new Error('Generic Error');
|
201
|
-
|
202
|
-
vi.spyOn(instance['client'].chat.completions, 'create').mockRejectedValue(genericError);
|
203
|
-
|
204
|
-
// Act
|
205
|
-
try {
|
206
|
-
await instance.chat({
|
207
|
-
messages: [{ content: 'Hello', role: 'user' }],
|
208
|
-
model: 'deepseek-chat',
|
209
|
-
temperature: 0,
|
210
|
-
});
|
211
|
-
} catch (e) {
|
212
|
-
expect(e).toEqual({
|
213
|
-
endpoint: defaultBaseURL,
|
214
|
-
errorType: 'AgentRuntimeError',
|
215
|
-
provider,
|
216
|
-
error: {
|
217
|
-
name: genericError.name,
|
218
|
-
cause: genericError.cause,
|
219
|
-
message: genericError.message,
|
220
|
-
stack: genericError.stack,
|
221
|
-
},
|
222
|
-
});
|
223
|
-
}
|
224
|
-
});
|
75
|
+
expect(instance['client'].chat.completions.create).toHaveBeenCalled();
|
76
|
+
const actualArgs = (instance['client'].chat.completions.create as Mock).mock.calls[0];
|
77
|
+
const actualMessages = actualArgs[0].messages;
|
78
|
+
expect(actualMessages).toEqual(expectedMessages);
|
225
79
|
});
|
226
80
|
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
// 执行测试
|
252
|
-
// 运行你的测试函数,确保它会在条件满足时调用 debugStream
|
253
|
-
// 假设的测试函数调用,你可能需要根据实际情况调整
|
254
|
-
await instance.chat({
|
255
|
-
messages: [{ content: 'Hello', role: 'user' }],
|
256
|
-
model: 'deepseek-chat',
|
257
|
-
stream: true,
|
258
|
-
temperature: 0,
|
259
|
-
});
|
260
|
-
|
261
|
-
// 验证 debugStream 被调用
|
262
|
-
expect(debugStreamModule.debugStream).toHaveBeenCalled();
|
263
|
-
|
264
|
-
// 恢复原始环境变量值
|
265
|
-
process.env.DEBUG_DEEPSEEK_CHAT_COMPLETION = originalDebugValue;
|
266
|
-
});
|
81
|
+
it('should insert a user message if the first message is from assistant (with system summary)', async () => {
|
82
|
+
const payloadMessages = [
|
83
|
+
{ content: 'System summary', role: 'system' as LLMRoleType },
|
84
|
+
{ content: 'Hello', role: 'assistant' as LLMRoleType },
|
85
|
+
];
|
86
|
+
const expectedMessages = [
|
87
|
+
{ content: 'System summary', role: 'system' },
|
88
|
+
{ content: '', role: 'user' },
|
89
|
+
{ content: 'Hello', role: 'assistant' },
|
90
|
+
];
|
91
|
+
|
92
|
+
const payload: ChatStreamPayload = {
|
93
|
+
messages: payloadMessages,
|
94
|
+
model: 'deepseek-reasoner',
|
95
|
+
temperature: 0,
|
96
|
+
};
|
97
|
+
|
98
|
+
await instance.chat(payload);
|
99
|
+
|
100
|
+
expect(instance['client'].chat.completions.create).toHaveBeenCalled();
|
101
|
+
const actualArgs = (instance['client'].chat.completions.create as Mock).mock.calls[0];
|
102
|
+
const actualMessages = actualArgs[0].messages;
|
103
|
+
expect(actualMessages).toEqual(expectedMessages);
|
267
104
|
});
|
268
105
|
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
{ content: 'System summary', role: 'system' as LLMRoleType },
|
299
|
-
{ content: 'Hello', role: 'assistant' as LLMRoleType },
|
300
|
-
];
|
301
|
-
const expectedMessages = [
|
302
|
-
{ content: 'System summary', role: 'system' },
|
303
|
-
{ content: '', role: 'user' },
|
304
|
-
{ content: 'Hello', role: 'assistant' },
|
305
|
-
];
|
306
|
-
|
307
|
-
const payload: ChatStreamPayload = {
|
308
|
-
messages: payloadMessages,
|
309
|
-
model: 'deepseek-reasoner',
|
310
|
-
temperature: 0,
|
311
|
-
};
|
312
|
-
|
313
|
-
await instance.chat(payload);
|
314
|
-
|
315
|
-
expect(instance['client'].chat.completions.create).toHaveBeenCalled();
|
316
|
-
const actualArgs = (instance['client'].chat.completions.create as Mock).mock.calls[0];
|
317
|
-
const actualMessages = actualArgs[0].messages;
|
318
|
-
expect(actualMessages).toEqual(expectedMessages);
|
319
|
-
});
|
320
|
-
|
321
|
-
it('should insert alternating roles if messages do not alternate', async () => {
|
322
|
-
const payloadMessages = [
|
323
|
-
{ content: 'user1', role: 'user' as LLMRoleType },
|
324
|
-
{ content: 'user2', role: 'user' as LLMRoleType },
|
325
|
-
{ content: 'assistant1', role: 'assistant' as LLMRoleType },
|
326
|
-
{ content: 'assistant2', role: 'assistant' as LLMRoleType },
|
327
|
-
];
|
328
|
-
const expectedMessages = [
|
329
|
-
{ content: 'user1', role: 'user' },
|
330
|
-
{ content: '', role: 'assistant' },
|
331
|
-
{ content: 'user2', role: 'user' },
|
332
|
-
{ content: 'assistant1', role: 'assistant' },
|
333
|
-
{ content: '', role: 'user' },
|
334
|
-
{ content: 'assistant2', role: 'assistant' },
|
335
|
-
];
|
336
|
-
|
337
|
-
const payload: ChatStreamPayload = {
|
338
|
-
messages: payloadMessages,
|
339
|
-
model: 'deepseek-reasoner',
|
340
|
-
temperature: 0,
|
341
|
-
};
|
342
|
-
|
343
|
-
await instance.chat(payload);
|
344
|
-
|
345
|
-
expect(instance['client'].chat.completions.create).toHaveBeenCalled();
|
346
|
-
const actualArgs = (instance['client'].chat.completions.create as Mock).mock.calls[0];
|
347
|
-
const actualMessages = actualArgs[0].messages;
|
348
|
-
expect(actualMessages).toEqual(expectedMessages);
|
349
|
-
});
|
350
|
-
|
351
|
-
it('complex condition', async () => {
|
352
|
-
const payloadMessages = [
|
353
|
-
{ content: 'system', role: 'system' as LLMRoleType },
|
354
|
-
{ content: 'assistant', role: 'assistant' as LLMRoleType },
|
355
|
-
{ content: 'user1', role: 'user' as LLMRoleType },
|
356
|
-
{ content: 'user2', role: 'user' as LLMRoleType },
|
357
|
-
{ content: 'user3', role: 'user' as LLMRoleType },
|
358
|
-
{ content: 'assistant1', role: 'assistant' as LLMRoleType },
|
359
|
-
{ content: 'assistant2', role: 'assistant' as LLMRoleType },
|
360
|
-
];
|
361
|
-
const expectedMessages = [
|
362
|
-
{ content: 'system', role: 'system' },
|
363
|
-
{ content: '', role: 'user' },
|
364
|
-
{ content: 'assistant', role: 'assistant' },
|
365
|
-
{ content: 'user1', role: 'user' },
|
366
|
-
{ content: '', role: 'assistant' },
|
367
|
-
{ content: 'user2', role: 'user' },
|
368
|
-
{ content: '', role: 'assistant' },
|
369
|
-
{ content: 'user3', role: 'user' },
|
370
|
-
{ content: 'assistant1', role: 'assistant' },
|
371
|
-
{ content: '', role: 'user' },
|
372
|
-
{ content: 'assistant2', role: 'assistant' },
|
373
|
-
];
|
374
|
-
|
375
|
-
const payload: ChatStreamPayload = {
|
376
|
-
messages: payloadMessages,
|
377
|
-
model: 'deepseek-reasoner',
|
378
|
-
temperature: 0,
|
379
|
-
};
|
380
|
-
|
381
|
-
await instance.chat(payload);
|
106
|
+
it('should insert alternating roles if messages do not alternate', async () => {
|
107
|
+
const payloadMessages = [
|
108
|
+
{ content: 'user1', role: 'user' as LLMRoleType },
|
109
|
+
{ content: 'user2', role: 'user' as LLMRoleType },
|
110
|
+
{ content: 'assistant1', role: 'assistant' as LLMRoleType },
|
111
|
+
{ content: 'assistant2', role: 'assistant' as LLMRoleType },
|
112
|
+
];
|
113
|
+
const expectedMessages = [
|
114
|
+
{ content: 'user1', role: 'user' },
|
115
|
+
{ content: '', role: 'assistant' },
|
116
|
+
{ content: 'user2', role: 'user' },
|
117
|
+
{ content: 'assistant1', role: 'assistant' },
|
118
|
+
{ content: '', role: 'user' },
|
119
|
+
{ content: 'assistant2', role: 'assistant' },
|
120
|
+
];
|
121
|
+
|
122
|
+
const payload: ChatStreamPayload = {
|
123
|
+
messages: payloadMessages,
|
124
|
+
model: 'deepseek-reasoner',
|
125
|
+
temperature: 0,
|
126
|
+
};
|
127
|
+
|
128
|
+
await instance.chat(payload);
|
129
|
+
|
130
|
+
expect(instance['client'].chat.completions.create).toHaveBeenCalled();
|
131
|
+
const actualArgs = (instance['client'].chat.completions.create as Mock).mock.calls[0];
|
132
|
+
const actualMessages = actualArgs[0].messages;
|
133
|
+
expect(actualMessages).toEqual(expectedMessages);
|
134
|
+
});
|
382
135
|
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
136
|
+
it('complex condition', async () => {
|
137
|
+
const payloadMessages = [
|
138
|
+
{ content: 'system', role: 'system' as LLMRoleType },
|
139
|
+
{ content: 'assistant', role: 'assistant' as LLMRoleType },
|
140
|
+
{ content: 'user1', role: 'user' as LLMRoleType },
|
141
|
+
{ content: 'user2', role: 'user' as LLMRoleType },
|
142
|
+
{ content: 'user3', role: 'user' as LLMRoleType },
|
143
|
+
{ content: 'assistant1', role: 'assistant' as LLMRoleType },
|
144
|
+
{ content: 'assistant2', role: 'assistant' as LLMRoleType },
|
145
|
+
];
|
146
|
+
const expectedMessages = [
|
147
|
+
{ content: 'system', role: 'system' },
|
148
|
+
{ content: '', role: 'user' },
|
149
|
+
{ content: 'assistant', role: 'assistant' },
|
150
|
+
{ content: 'user1', role: 'user' },
|
151
|
+
{ content: '', role: 'assistant' },
|
152
|
+
{ content: 'user2', role: 'user' },
|
153
|
+
{ content: '', role: 'assistant' },
|
154
|
+
{ content: 'user3', role: 'user' },
|
155
|
+
{ content: 'assistant1', role: 'assistant' },
|
156
|
+
{ content: '', role: 'user' },
|
157
|
+
{ content: 'assistant2', role: 'assistant' },
|
158
|
+
];
|
159
|
+
|
160
|
+
const payload: ChatStreamPayload = {
|
161
|
+
messages: payloadMessages,
|
162
|
+
model: 'deepseek-reasoner',
|
163
|
+
temperature: 0,
|
164
|
+
};
|
165
|
+
|
166
|
+
await instance.chat(payload);
|
167
|
+
|
168
|
+
expect(instance['client'].chat.completions.create).toHaveBeenCalled();
|
169
|
+
const actualArgs = (instance['client'].chat.completions.create as Mock).mock.calls[0];
|
170
|
+
const actualMessages = actualArgs[0].messages;
|
171
|
+
expect(actualMessages).toEqual(expectedMessages);
|
388
172
|
});
|
389
173
|
});
|
390
174
|
});
|