@lobehub/chat 1.49.5 → 1.49.7
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/changelog/v1.json +18 -0
- package/package.json +1 -1
- package/src/libs/agent-runtime/deepseek/index.test.ts +135 -0
- package/src/libs/agent-runtime/deepseek/index.ts +28 -3
- package/src/libs/agent-runtime/utils/streams/openai.test.ts +201 -1
- package/src/libs/agent-runtime/utils/streams/openai.ts +10 -5
package/CHANGELOG.md
CHANGED
@@ -2,6 +2,56 @@
|
|
2
2
|
|
3
3
|
# Changelog
|
4
4
|
|
5
|
+
### [Version 1.49.7](https://github.com/lobehub/lobe-chat/compare/v1.49.6...v1.49.7)
|
6
|
+
|
7
|
+
<sup>Released on **2025-02-01**</sup>
|
8
|
+
|
9
|
+
#### 🐛 Bug Fixes
|
10
|
+
|
11
|
+
- **misc**: Multiple deepseek-reasoner request errors.
|
12
|
+
|
13
|
+
<br/>
|
14
|
+
|
15
|
+
<details>
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
17
|
+
|
18
|
+
#### What's fixed
|
19
|
+
|
20
|
+
- **misc**: Multiple deepseek-reasoner request errors, closes [#5601](https://github.com/lobehub/lobe-chat/issues/5601) ([71cc32b](https://github.com/lobehub/lobe-chat/commit/71cc32b))
|
21
|
+
|
22
|
+
</details>
|
23
|
+
|
24
|
+
<div align="right">
|
25
|
+
|
26
|
+
[](#readme-top)
|
27
|
+
|
28
|
+
</div>
|
29
|
+
|
30
|
+
### [Version 1.49.6](https://github.com/lobehub/lobe-chat/compare/v1.49.5...v1.49.6)
|
31
|
+
|
32
|
+
<sup>Released on **2025-01-30**</sup>
|
33
|
+
|
34
|
+
#### 🐛 Bug Fixes
|
35
|
+
|
36
|
+
- **misc**: Support litellm reasoning streaming.
|
37
|
+
|
38
|
+
<br/>
|
39
|
+
|
40
|
+
<details>
|
41
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
42
|
+
|
43
|
+
#### What's fixed
|
44
|
+
|
45
|
+
- **misc**: Support litellm reasoning streaming, closes [#5632](https://github.com/lobehub/lobe-chat/issues/5632) ([9942fb3](https://github.com/lobehub/lobe-chat/commit/9942fb3))
|
46
|
+
|
47
|
+
</details>
|
48
|
+
|
49
|
+
<div align="right">
|
50
|
+
|
51
|
+
[](#readme-top)
|
52
|
+
|
53
|
+
</div>
|
54
|
+
|
5
55
|
### [Version 1.49.5](https://github.com/lobehub/lobe-chat/compare/v1.49.4...v1.49.5)
|
6
56
|
|
7
57
|
<sup>Released on **2025-01-28**</sup>
|
package/changelog/v1.json
CHANGED
@@ -1,4 +1,22 @@
|
|
1
1
|
[
|
2
|
+
{
|
3
|
+
"children": {
|
4
|
+
"fixes": [
|
5
|
+
"Multiple deepseek-reasoner request errors."
|
6
|
+
]
|
7
|
+
},
|
8
|
+
"date": "2025-02-01",
|
9
|
+
"version": "1.49.7"
|
10
|
+
},
|
11
|
+
{
|
12
|
+
"children": {
|
13
|
+
"fixes": [
|
14
|
+
"Support litellm reasoning streaming."
|
15
|
+
]
|
16
|
+
},
|
17
|
+
"date": "2025-01-30",
|
18
|
+
"version": "1.49.6"
|
19
|
+
},
|
2
20
|
{
|
3
21
|
"children": {
|
4
22
|
"fixes": [
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@lobehub/chat",
|
3
|
-
"version": "1.49.
|
3
|
+
"version": "1.49.7",
|
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",
|
@@ -4,12 +4,15 @@ import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
4
4
|
|
5
5
|
import {
|
6
6
|
ChatStreamCallbacks,
|
7
|
+
ChatStreamPayload,
|
8
|
+
LLMRoleType,
|
7
9
|
LobeOpenAICompatibleRuntime,
|
8
10
|
ModelProvider,
|
9
11
|
} from '@/libs/agent-runtime';
|
10
12
|
|
11
13
|
import * as debugStreamModule from '../utils/debugStream';
|
12
14
|
import { LobeDeepSeekAI } from './index';
|
15
|
+
import { LobeOpenAICompatibleFactory } from '../utils/openaiCompatibleFactory';
|
13
16
|
|
14
17
|
const provider = ModelProvider.DeepSeek;
|
15
18
|
const defaultBaseURL = 'https://api.deepseek.com/v1';
|
@@ -22,6 +25,17 @@ vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
22
25
|
|
23
26
|
let instance: LobeOpenAICompatibleRuntime;
|
24
27
|
|
28
|
+
const createDeepSeekAIInstance = () => new LobeDeepSeekAI({ apiKey: 'test' });
|
29
|
+
|
30
|
+
const mockSuccessfulChatCompletion = () => {
|
31
|
+
vi.spyOn(instance['client'].chat.completions, 'create').mockResolvedValue({
|
32
|
+
id: 'cmpl-mock',
|
33
|
+
object: 'chat.completion',
|
34
|
+
created: Date.now(),
|
35
|
+
choices: [{ index: 0, message: { role: 'assistant', content: 'Mock response' }, finish_reason: 'stop' }],
|
36
|
+
} as any);
|
37
|
+
};
|
38
|
+
|
25
39
|
beforeEach(() => {
|
26
40
|
instance = new LobeDeepSeekAI({ apiKey: 'test' });
|
27
41
|
|
@@ -251,5 +265,126 @@ describe('LobeDeepSeekAI', () => {
|
|
251
265
|
process.env.DEBUG_DEEPSEEK_CHAT_COMPLETION = originalDebugValue;
|
252
266
|
});
|
253
267
|
});
|
268
|
+
|
269
|
+
describe('deepseek-reasoner', () => {
|
270
|
+
beforeEach(() => {
|
271
|
+
instance = createDeepSeekAIInstance();
|
272
|
+
mockSuccessfulChatCompletion();
|
273
|
+
});
|
274
|
+
|
275
|
+
it('should insert a user message if the first message is from assistant', async () => {
|
276
|
+
const payloadMessages = [{ content: 'Hello', role: 'assistant' as LLMRoleType }];
|
277
|
+
const expectedMessages = [
|
278
|
+
{ content: '', role: 'user' },
|
279
|
+
...payloadMessages,
|
280
|
+
];
|
281
|
+
|
282
|
+
const payload: ChatStreamPayload = {
|
283
|
+
messages: payloadMessages,
|
284
|
+
model: 'deepseek-reasoner',
|
285
|
+
temperature: 0,
|
286
|
+
};
|
287
|
+
|
288
|
+
await instance.chat(payload);
|
289
|
+
|
290
|
+
expect(instance['client'].chat.completions.create).toHaveBeenCalled();
|
291
|
+
const actualArgs = (instance['client'].chat.completions.create as Mock).mock.calls[0];
|
292
|
+
const actualMessages = actualArgs[0].messages;
|
293
|
+
expect(actualMessages).toEqual(expectedMessages);
|
294
|
+
});
|
295
|
+
|
296
|
+
it('should insert a user message if the first message is from assistant (with system summary)', async () => {
|
297
|
+
const payloadMessages = [
|
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);
|
382
|
+
|
383
|
+
expect(instance['client'].chat.completions.create).toHaveBeenCalled();
|
384
|
+
const actualArgs = (instance['client'].chat.completions.create as Mock).mock.calls[0];
|
385
|
+
const actualMessages = actualArgs[0].messages;
|
386
|
+
expect(actualMessages).toEqual(expectedMessages);
|
387
|
+
});
|
388
|
+
});
|
254
389
|
});
|
255
390
|
});
|
@@ -12,24 +12,49 @@ export interface DeepSeekModelCard {
|
|
12
12
|
export const LobeDeepSeekAI = LobeOpenAICompatibleFactory({
|
13
13
|
baseURL: 'https://api.deepseek.com/v1',
|
14
14
|
chatCompletion: {
|
15
|
-
handlePayload: ({ frequency_penalty, model, presence_penalty, temperature, top_p, ...payload }: ChatStreamPayload) =>
|
16
|
-
|
15
|
+
handlePayload: ({ frequency_penalty, messages, model, presence_penalty, temperature, top_p, ...payload }: ChatStreamPayload) => {
|
16
|
+
// github.com/lobehub/lobe-chat/pull/5548
|
17
|
+
let filteredMessages = messages.filter(message => message.role !== 'system');
|
18
|
+
|
19
|
+
if (filteredMessages.length > 0 && filteredMessages[0].role === 'assistant') {
|
20
|
+
filteredMessages.unshift({ content: "", role: "user" });
|
21
|
+
}
|
22
|
+
|
23
|
+
let lastRole = '';
|
24
|
+
for (let i = 0; i < filteredMessages.length; i++) {
|
25
|
+
const message = filteredMessages[i];
|
26
|
+
if (message.role === lastRole) {
|
27
|
+
const newRole = lastRole === 'assistant' ? 'user' : 'assistant';
|
28
|
+
filteredMessages.splice(i, 0, { content: "", role: newRole });
|
29
|
+
i++;
|
30
|
+
}
|
31
|
+
lastRole = message.role;
|
32
|
+
}
|
33
|
+
|
34
|
+
if (messages.length > 0 && messages[0].role === 'system') {
|
35
|
+
filteredMessages.unshift(messages[0]);
|
36
|
+
}
|
37
|
+
|
38
|
+
return {
|
17
39
|
...payload,
|
18
40
|
model,
|
19
41
|
...(model === 'deepseek-reasoner'
|
20
42
|
? {
|
21
43
|
frequency_penalty: undefined,
|
44
|
+
messages: filteredMessages,
|
22
45
|
presence_penalty: undefined,
|
23
46
|
temperature: undefined,
|
24
47
|
top_p: undefined,
|
25
48
|
}
|
26
49
|
: {
|
27
50
|
frequency_penalty,
|
51
|
+
messages,
|
28
52
|
presence_penalty,
|
29
53
|
temperature,
|
30
54
|
top_p,
|
31
55
|
}),
|
32
|
-
}
|
56
|
+
} as OpenAI.ChatCompletionCreateParamsStreaming;
|
57
|
+
},
|
33
58
|
},
|
34
59
|
debug: {
|
35
60
|
chatCompletion: () => process.env.DEBUG_DEEPSEEK_CHAT_COMPLETION === '1',
|
@@ -554,7 +554,7 @@ describe('OpenAIStream', () => {
|
|
554
554
|
});
|
555
555
|
|
556
556
|
describe('Reasoning', () => {
|
557
|
-
it('should handle reasoning event', async () => {
|
557
|
+
it('should handle reasoning event in official DeepSeek api', async () => {
|
558
558
|
const data = [
|
559
559
|
{
|
560
560
|
id: '1',
|
@@ -722,6 +722,206 @@ describe('OpenAIStream', () => {
|
|
722
722
|
chunks.push(decoder.decode(chunk, { stream: true }));
|
723
723
|
}
|
724
724
|
|
725
|
+
expect(chunks).toEqual(
|
726
|
+
[
|
727
|
+
'id: 1',
|
728
|
+
'event: reasoning',
|
729
|
+
`data: ""\n`,
|
730
|
+
'id: 1',
|
731
|
+
'event: reasoning',
|
732
|
+
`data: "您好"\n`,
|
733
|
+
'id: 1',
|
734
|
+
'event: reasoning',
|
735
|
+
`data: "!"\n`,
|
736
|
+
'id: 1',
|
737
|
+
'event: text',
|
738
|
+
`data: "你好"\n`,
|
739
|
+
'id: 1',
|
740
|
+
'event: text',
|
741
|
+
`data: "很高兴"\n`,
|
742
|
+
'id: 1',
|
743
|
+
'event: text',
|
744
|
+
`data: "为您"\n`,
|
745
|
+
'id: 1',
|
746
|
+
'event: text',
|
747
|
+
`data: "提供"\n`,
|
748
|
+
'id: 1',
|
749
|
+
'event: text',
|
750
|
+
`data: "帮助。"\n`,
|
751
|
+
'id: 1',
|
752
|
+
'event: stop',
|
753
|
+
`data: "stop"\n`,
|
754
|
+
].map((i) => `${i}\n`),
|
755
|
+
);
|
756
|
+
});
|
757
|
+
it('should handle reasoning in litellm', async () => {
|
758
|
+
const data = [
|
759
|
+
{
|
760
|
+
id: '1',
|
761
|
+
object: 'chat.completion.chunk',
|
762
|
+
created: 1737563070,
|
763
|
+
model: 'deepseek-reasoner',
|
764
|
+
system_fingerprint: 'fp_1c5d8833bc',
|
765
|
+
choices: [
|
766
|
+
{
|
767
|
+
index: 0,
|
768
|
+
delta: { role: 'assistant', reasoning_content: '' },
|
769
|
+
logprobs: null,
|
770
|
+
finish_reason: null,
|
771
|
+
},
|
772
|
+
],
|
773
|
+
},
|
774
|
+
{
|
775
|
+
id: '1',
|
776
|
+
object: 'chat.completion.chunk',
|
777
|
+
created: 1737563070,
|
778
|
+
model: 'deepseek-reasoner',
|
779
|
+
system_fingerprint: 'fp_1c5d8833bc',
|
780
|
+
choices: [
|
781
|
+
{
|
782
|
+
index: 0,
|
783
|
+
delta: { reasoning_content: '您好' },
|
784
|
+
logprobs: null,
|
785
|
+
finish_reason: null,
|
786
|
+
},
|
787
|
+
],
|
788
|
+
},
|
789
|
+
{
|
790
|
+
id: '1',
|
791
|
+
object: 'chat.completion.chunk',
|
792
|
+
created: 1737563070,
|
793
|
+
model: 'deepseek-reasoner',
|
794
|
+
system_fingerprint: 'fp_1c5d8833bc',
|
795
|
+
choices: [
|
796
|
+
{
|
797
|
+
index: 0,
|
798
|
+
delta: { reasoning_content: '!' },
|
799
|
+
logprobs: null,
|
800
|
+
finish_reason: null,
|
801
|
+
},
|
802
|
+
],
|
803
|
+
},
|
804
|
+
{
|
805
|
+
id: '1',
|
806
|
+
object: 'chat.completion.chunk',
|
807
|
+
created: 1737563070,
|
808
|
+
model: 'deepseek-reasoner',
|
809
|
+
system_fingerprint: 'fp_1c5d8833bc',
|
810
|
+
choices: [
|
811
|
+
{
|
812
|
+
index: 0,
|
813
|
+
delta: { content: '你好', reasoning_content: null },
|
814
|
+
logprobs: null,
|
815
|
+
finish_reason: null,
|
816
|
+
},
|
817
|
+
],
|
818
|
+
},
|
819
|
+
{
|
820
|
+
id: '1',
|
821
|
+
object: 'chat.completion.chunk',
|
822
|
+
created: 1737563070,
|
823
|
+
model: 'deepseek-reasoner',
|
824
|
+
system_fingerprint: 'fp_1c5d8833bc',
|
825
|
+
choices: [
|
826
|
+
{
|
827
|
+
index: 0,
|
828
|
+
delta: { content: '很高兴', reasoning_cont: null },
|
829
|
+
logprobs: null,
|
830
|
+
finish_reason: null,
|
831
|
+
},
|
832
|
+
],
|
833
|
+
},
|
834
|
+
{
|
835
|
+
id: '1',
|
836
|
+
object: 'chat.completion.chunk',
|
837
|
+
created: 1737563070,
|
838
|
+
model: 'deepseek-reasoner',
|
839
|
+
system_fingerprint: 'fp_1c5d8833bc',
|
840
|
+
choices: [
|
841
|
+
{
|
842
|
+
index: 0,
|
843
|
+
delta: { content: '为您', reasoning_content: null },
|
844
|
+
logprobs: null,
|
845
|
+
finish_reason: null,
|
846
|
+
},
|
847
|
+
],
|
848
|
+
},
|
849
|
+
{
|
850
|
+
id: '1',
|
851
|
+
object: 'chat.completion.chunk',
|
852
|
+
created: 1737563070,
|
853
|
+
model: 'deepseek-reasoner',
|
854
|
+
system_fingerprint: 'fp_1c5d8833bc',
|
855
|
+
choices: [
|
856
|
+
{
|
857
|
+
index: 0,
|
858
|
+
delta: { content: '提供', reasoning_content: null },
|
859
|
+
logprobs: null,
|
860
|
+
finish_reason: null,
|
861
|
+
},
|
862
|
+
],
|
863
|
+
},
|
864
|
+
{
|
865
|
+
id: '1',
|
866
|
+
object: 'chat.completion.chunk',
|
867
|
+
created: 1737563070,
|
868
|
+
model: 'deepseek-reasoner',
|
869
|
+
system_fingerprint: 'fp_1c5d8833bc',
|
870
|
+
choices: [
|
871
|
+
{
|
872
|
+
index: 0,
|
873
|
+
delta: { content: '帮助。', reasoning_content: null },
|
874
|
+
logprobs: null,
|
875
|
+
finish_reason: null,
|
876
|
+
},
|
877
|
+
],
|
878
|
+
},
|
879
|
+
{
|
880
|
+
id: '1',
|
881
|
+
object: 'chat.completion.chunk',
|
882
|
+
created: 1737563070,
|
883
|
+
model: 'deepseek-reasoner',
|
884
|
+
system_fingerprint: 'fp_1c5d8833bc',
|
885
|
+
choices: [
|
886
|
+
{
|
887
|
+
index: 0,
|
888
|
+
delta: { content: '', reasoning_content: null },
|
889
|
+
logprobs: null,
|
890
|
+
finish_reason: 'stop',
|
891
|
+
},
|
892
|
+
],
|
893
|
+
usage: {
|
894
|
+
prompt_tokens: 6,
|
895
|
+
completion_tokens: 104,
|
896
|
+
total_tokens: 110,
|
897
|
+
prompt_tokens_details: { cached_tokens: 0 },
|
898
|
+
completion_tokens_details: { reasoning_tokens: 70 },
|
899
|
+
prompt_cache_hit_tokens: 0,
|
900
|
+
prompt_cache_miss_tokens: 6,
|
901
|
+
},
|
902
|
+
},
|
903
|
+
];
|
904
|
+
|
905
|
+
const mockOpenAIStream = new ReadableStream({
|
906
|
+
start(controller) {
|
907
|
+
data.forEach((chunk) => {
|
908
|
+
controller.enqueue(chunk);
|
909
|
+
});
|
910
|
+
|
911
|
+
controller.close();
|
912
|
+
},
|
913
|
+
});
|
914
|
+
|
915
|
+
const protocolStream = OpenAIStream(mockOpenAIStream);
|
916
|
+
|
917
|
+
const decoder = new TextDecoder();
|
918
|
+
const chunks = [];
|
919
|
+
|
920
|
+
// @ts-ignore
|
921
|
+
for await (const chunk of protocolStream) {
|
922
|
+
chunks.push(decoder.decode(chunk, { stream: true }));
|
923
|
+
}
|
924
|
+
|
725
925
|
expect(chunks).toEqual(
|
726
926
|
[
|
727
927
|
'id: 1',
|
@@ -92,13 +92,18 @@ export const transformOpenAIStream = (
|
|
92
92
|
return { data: item.delta.content, id: chunk.id, type: 'text' };
|
93
93
|
}
|
94
94
|
|
95
|
+
// DeepSeek reasoner 会将 thinking 放在 reasoning_content 字段中
|
96
|
+
// litellm 处理 reasoning content 时 不会设定 content = null
|
97
|
+
if (
|
98
|
+
item.delta &&
|
99
|
+
'reasoning_content' in item.delta &&
|
100
|
+
typeof item.delta.reasoning_content === 'string'
|
101
|
+
) {
|
102
|
+
return { data: item.delta.reasoning_content, id: chunk.id, type: 'reasoning' };
|
103
|
+
}
|
104
|
+
|
95
105
|
// 无内容情况
|
96
106
|
if (item.delta && item.delta.content === null) {
|
97
|
-
// deepseek reasoner 会将 thinking 放在 reasoning_content 字段中
|
98
|
-
if ('reasoning_content' in item.delta && typeof item.delta.reasoning_content === 'string') {
|
99
|
-
return { data: item.delta.reasoning_content, id: chunk.id, type: 'reasoning' };
|
100
|
-
}
|
101
|
-
|
102
107
|
return { data: item.delta, id: chunk.id, type: 'data' };
|
103
108
|
}
|
104
109
|
|