Skip to content

Commit 32438be

Browse files
committed
fix: messages adapt test (#6813)
* doc * doc * doc
1 parent ebe68d8 commit 32438be

4 files changed

Lines changed: 157 additions & 3 deletions

File tree

document/content/docs/self-host/upgrading/4-14/41414.mdx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ description: 'FastGPT V4.14.14 更新说明'
88
### 1. 更新镜像 tag
99

1010
- 更新 fastgpt-app(fastgpt 主服务) 镜像 tag: v4.14.14
11+
- 更新 fastgpt-pro(fastgpt 商业版) 镜像 tag: v4.14.14
1112

1213
## 🐛 修复
1314

@@ -16,4 +17,5 @@ description: 'FastGPT V4.14.14 更新说明'
1617

1718
1. 个人微信发布渠道,优化轮询策略(拉取与回复解耦),避免数据量超大时出现阻塞。
1819
2. 新增环境变量 `WECHAT_CHANNEL_CONCURRENCY`(默认 1000)用于控制微信渠道 poll worker 并发数,建议 ≥ online channel 峰值。
19-
3. 完善内网地址检测。
20+
3. 完善内网地址检测。
21+
4. 兼容 deepseek 工具调用+思考模式,避免接口出现 400 错误。

document/data/doc-last-modified.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@
230230
"document/content/docs/self-host/upgrading/4-14/41412.mdx": "2026-04-21T23:04:26+08:00",
231231
"document/content/docs/self-host/upgrading/4-14/41413.en.mdx": "2026-04-21T23:04:26+08:00",
232232
"document/content/docs/self-host/upgrading/4-14/41413.mdx": "2026-04-21T23:04:26+08:00",
233-
"document/content/docs/self-host/upgrading/4-14/41414.mdx": "2026-04-22T16:29:40+08:00",
233+
"document/content/docs/self-host/upgrading/4-14/41414.mdx": "2026-04-22T23:35:11+08:00",
234234
"document/content/docs/self-host/upgrading/4-14/4142.en.mdx": "2026-03-03T17:39:47+08:00",
235235
"document/content/docs/self-host/upgrading/4-14/4142.mdx": "2026-03-03T17:39:47+08:00",
236236
"document/content/docs/self-host/upgrading/4-14/4143.en.mdx": "2026-03-03T17:39:47+08:00",

packages/global/core/chat/adapt.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ export const chats2GPTMessages = ({
171171
typeof lastResult?.content === 'string'
172172
) {
173173
lastResult.content += value.text.content;
174-
} else if (lastResult.reasoning_content) {
174+
} else if (lastResult?.reasoning_content) {
175175
lastResult.content = value.text.content;
176176
} else {
177177
aiResults.push({

test/cases/global/core/chat/adapt.test.ts

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,124 @@ describe('chats2GPTMessages', () => {
444444
// Plan should be skipped when reserveTool is false
445445
expect(result).toHaveLength(2);
446446
});
447+
448+
it('should convert AI message with reasoning only', () => {
449+
const messages: ChatItemMiniType[] = [
450+
{
451+
obj: ChatRoleEnum.AI,
452+
value: [{ reasoning: { content: 'Let me think...' } }]
453+
}
454+
];
455+
456+
const result = chats2GPTMessages({ messages, reserveId: false });
457+
458+
expect(result).toHaveLength(1);
459+
expect(result[0].role).toBe(ChatCompletionRequestMessageRoleEnum.Assistant);
460+
expect((result[0] as any).reasoning_content).toBe('Let me think...');
461+
expect((result[0] as any).content).toBeUndefined();
462+
});
463+
464+
it('should merge reasoning + text into a single assistant message', () => {
465+
const messages: ChatItemMiniType[] = [
466+
{
467+
obj: ChatRoleEnum.AI,
468+
value: [
469+
{ reasoning: { content: 'Let me think...' } },
470+
{ text: { content: 'Final answer' } }
471+
]
472+
}
473+
];
474+
475+
const result = chats2GPTMessages({ messages, reserveId: false });
476+
477+
expect(result).toHaveLength(1);
478+
expect(result[0].role).toBe(ChatCompletionRequestMessageRoleEnum.Assistant);
479+
expect((result[0] as any).reasoning_content).toBe('Let me think...');
480+
expect((result[0] as any).content).toBe('Final answer');
481+
});
482+
483+
it('should merge reasoning + tool_calls into a single assistant message', () => {
484+
const messages: ChatItemMiniType[] = [
485+
{
486+
obj: ChatRoleEnum.AI,
487+
value: [
488+
{ reasoning: { content: 'Need to call a tool' } },
489+
{
490+
tool: {
491+
id: 'tool-1',
492+
toolName: 'Search',
493+
toolAvatar: '',
494+
functionName: 'search_web',
495+
params: '{"q":"x"}',
496+
response: '{}'
497+
}
498+
}
499+
]
500+
}
501+
];
502+
503+
const result = chats2GPTMessages({ messages, reserveId: false, reserveTool: true });
504+
505+
// 1 merged assistant (reasoning + tool_calls) + 1 tool response
506+
expect(result).toHaveLength(2);
507+
expect(result[0].role).toBe(ChatCompletionRequestMessageRoleEnum.Assistant);
508+
expect((result[0] as any).reasoning_content).toBe('Need to call a tool');
509+
expect((result[0] as any).tool_calls).toHaveLength(1);
510+
expect((result[0] as any).tool_calls[0].function.name).toBe('search_web');
511+
expect(result[1].role).toBe(ChatCompletionRequestMessageRoleEnum.Tool);
512+
});
513+
514+
it('should keep tool_calls separate when no reasoning precedes them', () => {
515+
const messages: ChatItemMiniType[] = [
516+
{
517+
obj: ChatRoleEnum.AI,
518+
value: [
519+
{ text: { content: 'Calling tool' } },
520+
{
521+
tool: {
522+
id: 'tool-1',
523+
toolName: 'Search',
524+
toolAvatar: '',
525+
functionName: 'search_web',
526+
params: '{}',
527+
response: '{}'
528+
}
529+
}
530+
]
531+
}
532+
];
533+
534+
const result = chats2GPTMessages({ messages, reserveId: false, reserveTool: true });
535+
536+
// text assistant + tool_calls assistant + tool response
537+
expect(result).toHaveLength(3);
538+
expect((result[0] as any).content).toBe('Calling tool');
539+
expect((result[0] as any).tool_calls).toBeUndefined();
540+
expect((result[1] as any).tool_calls).toHaveLength(1);
541+
expect(result[2].role).toBe(ChatCompletionRequestMessageRoleEnum.Tool);
542+
});
543+
544+
it('should handle multiple reasoning values producing separate assistant entries', () => {
545+
const messages: ChatItemMiniType[] = [
546+
{
547+
obj: ChatRoleEnum.AI,
548+
value: [
549+
{ reasoning: { content: 'Step 1 thinking' } },
550+
{ text: { content: 'Intermediate answer' } },
551+
{ reasoning: { content: 'Step 2 thinking' } },
552+
{ text: { content: 'Final answer' } }
553+
]
554+
}
555+
];
556+
557+
const result = chats2GPTMessages({ messages, reserveId: false });
558+
559+
expect(result).toHaveLength(2);
560+
expect((result[0] as any).reasoning_content).toBe('Step 1 thinking');
561+
expect((result[0] as any).content).toBe('Intermediate answer');
562+
expect((result[1] as any).reasoning_content).toBe('Step 2 thinking');
563+
expect((result[1] as any).content).toBe('Final answer');
564+
});
447565
});
448566

449567
describe('GPTMessages2Chats', () => {
@@ -530,6 +648,40 @@ describe('GPTMessages2Chats', () => {
530648
expect(result[0].value[1].text?.content).toBe('Final answer');
531649
});
532650

651+
it('should drop reasoning when reserveReason is false', () => {
652+
const messages: ChatCompletionMessageParam[] = [
653+
{
654+
role: ChatCompletionRequestMessageRoleEnum.Assistant,
655+
content: 'Final answer',
656+
reasoning_content: 'Let me think about this...'
657+
}
658+
];
659+
660+
const result = GPTMessages2Chats({ messages, reserveReason: false });
661+
662+
expect(result).toHaveLength(1);
663+
expect(result[0].value).toHaveLength(1);
664+
expect(result[0].value[0].text?.content).toBe('Final answer');
665+
expect((result[0].value[0] as any).reasoning).toBeUndefined();
666+
});
667+
668+
it('should keep only reasoning when assistant message has no content', () => {
669+
const messages: ChatCompletionMessageParam[] = [
670+
{
671+
role: ChatCompletionRequestMessageRoleEnum.Assistant,
672+
content: '',
673+
reasoning_content: 'Thinking only'
674+
}
675+
];
676+
677+
const result = GPTMessages2Chats({ messages });
678+
679+
expect(result).toHaveLength(1);
680+
expect(result[0].value).toHaveLength(1);
681+
const value = result[0].value[0] as { reasoning?: { content: string } };
682+
expect(value.reasoning?.content).toBe('Thinking only');
683+
});
684+
533685
it('should merge messages with same dataId', () => {
534686
const messages: ChatCompletionMessageParam[] = [
535687
{

0 commit comments

Comments
 (0)