mirror of
https://github.com/labring/FastGPT.git
synced 2026-05-07 01:02:55 +08:00
@@ -8,6 +8,7 @@ description: 'FastGPT V4.14.14 更新说明'
|
||||
### 1. 更新镜像 tag
|
||||
|
||||
- 更新 fastgpt-app(fastgpt 主服务) 镜像 tag: v4.14.14
|
||||
- 更新 fastgpt-pro(fastgpt 商业版) 镜像 tag: v4.14.14
|
||||
|
||||
## 🐛 修复
|
||||
|
||||
@@ -16,4 +17,5 @@ description: 'FastGPT V4.14.14 更新说明'
|
||||
|
||||
1. 个人微信发布渠道,优化轮询策略(拉取与回复解耦),避免数据量超大时出现阻塞。
|
||||
2. 新增环境变量 `WECHAT_CHANNEL_CONCURRENCY`(默认 1000)用于控制微信渠道 poll worker 并发数,建议 ≥ online channel 峰值。
|
||||
3. 完善内网地址检测。
|
||||
3. 完善内网地址检测。
|
||||
4. 兼容 deepseek 工具调用+思考模式,避免接口出现 400 错误。
|
||||
@@ -225,12 +225,12 @@
|
||||
"document/content/docs/self-host/upgrading/4-14/41410.en.mdx": "2026-03-31T23:15:29+08:00",
|
||||
"document/content/docs/self-host/upgrading/4-14/41410.mdx": "2026-04-18T20:47:39+08:00",
|
||||
"document/content/docs/self-host/upgrading/4-14/41411.en.mdx": "2026-04-21T23:04:26+08:00",
|
||||
"document/content/docs/self-host/upgrading/4-14/41411.mdx": "2026-04-20T20:18:35+08:00",
|
||||
"document/content/docs/self-host/upgrading/4-14/41411.mdx": "2026-04-24T17:13:58+08:00",
|
||||
"document/content/docs/self-host/upgrading/4-14/41412.en.mdx": "2026-04-21T23:04:26+08:00",
|
||||
"document/content/docs/self-host/upgrading/4-14/41412.mdx": "2026-04-21T23:04:26+08:00",
|
||||
"document/content/docs/self-host/upgrading/4-14/41413.en.mdx": "2026-04-21T23:04:26+08:00",
|
||||
"document/content/docs/self-host/upgrading/4-14/41413.mdx": "2026-04-21T23:04:26+08:00",
|
||||
"document/content/docs/self-host/upgrading/4-14/41414.mdx": "2026-04-22T23:35:11+08:00",
|
||||
"document/content/docs/self-host/upgrading/4-14/41414.mdx": "2026-04-24T18:21:37+08:00",
|
||||
"document/content/docs/self-host/upgrading/4-14/4142.en.mdx": "2026-03-03T17:39:47+08:00",
|
||||
"document/content/docs/self-host/upgrading/4-14/4142.mdx": "2026-03-03T17:39:47+08:00",
|
||||
"document/content/docs/self-host/upgrading/4-14/4143.en.mdx": "2026-03-03T17:39:47+08:00",
|
||||
@@ -251,7 +251,7 @@
|
||||
"document/content/docs/self-host/upgrading/4-14/41481.mdx": "2026-03-09T17:39:53+08:00",
|
||||
"document/content/docs/self-host/upgrading/4-14/4149.en.mdx": "2026-03-23T12:17:04+08:00",
|
||||
"document/content/docs/self-host/upgrading/4-14/4149.mdx": "2026-04-07T21:01:52+08:00",
|
||||
"document/content/docs/self-host/upgrading/4-15/4150.mdx": "2026-04-22T14:36:14+08:00",
|
||||
"document/content/docs/self-host/upgrading/4-15/4150.mdx": "2026-04-23T18:02:28+08:00",
|
||||
"document/content/docs/self-host/upgrading/outdated/40.en.mdx": "2026-03-03T17:39:47+08:00",
|
||||
"document/content/docs/self-host/upgrading/outdated/40.mdx": "2026-03-03T17:39:47+08:00",
|
||||
"document/content/docs/self-host/upgrading/outdated/41.en.mdx": "2026-03-03T17:39:47+08:00",
|
||||
@@ -426,4 +426,4 @@
|
||||
"document/content/docs/use-cases/external-integration/wecom.mdx": "2025-12-10T20:07:05+08:00",
|
||||
"document/content/docs/use-cases/index.en.mdx": "2026-02-26T22:14:30+08:00",
|
||||
"document/content/docs/use-cases/index.mdx": "2025-07-24T14:23:04+08:00"
|
||||
}
|
||||
}
|
||||
@@ -171,7 +171,7 @@ export const chats2GPTMessages = ({
|
||||
typeof lastResult?.content === 'string'
|
||||
) {
|
||||
lastResult.content += value.text.content;
|
||||
} else if (lastResult.reasoning_content) {
|
||||
} else if (lastResult?.reasoning_content) {
|
||||
lastResult.content = value.text.content;
|
||||
} else {
|
||||
aiResults.push({
|
||||
|
||||
@@ -444,6 +444,124 @@ describe('chats2GPTMessages', () => {
|
||||
// Plan should be skipped when reserveTool is false
|
||||
expect(result).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('should convert AI message with reasoning only', () => {
|
||||
const messages: ChatItemMiniType[] = [
|
||||
{
|
||||
obj: ChatRoleEnum.AI,
|
||||
value: [{ reasoning: { content: 'Let me think...' } }]
|
||||
}
|
||||
];
|
||||
|
||||
const result = chats2GPTMessages({ messages, reserveId: false });
|
||||
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0].role).toBe(ChatCompletionRequestMessageRoleEnum.Assistant);
|
||||
expect((result[0] as any).reasoning_content).toBe('Let me think...');
|
||||
expect((result[0] as any).content).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should merge reasoning + text into a single assistant message', () => {
|
||||
const messages: ChatItemMiniType[] = [
|
||||
{
|
||||
obj: ChatRoleEnum.AI,
|
||||
value: [
|
||||
{ reasoning: { content: 'Let me think...' } },
|
||||
{ text: { content: 'Final answer' } }
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
const result = chats2GPTMessages({ messages, reserveId: false });
|
||||
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0].role).toBe(ChatCompletionRequestMessageRoleEnum.Assistant);
|
||||
expect((result[0] as any).reasoning_content).toBe('Let me think...');
|
||||
expect((result[0] as any).content).toBe('Final answer');
|
||||
});
|
||||
|
||||
it('should merge reasoning + tool_calls into a single assistant message', () => {
|
||||
const messages: ChatItemMiniType[] = [
|
||||
{
|
||||
obj: ChatRoleEnum.AI,
|
||||
value: [
|
||||
{ reasoning: { content: 'Need to call a tool' } },
|
||||
{
|
||||
tool: {
|
||||
id: 'tool-1',
|
||||
toolName: 'Search',
|
||||
toolAvatar: '',
|
||||
functionName: 'search_web',
|
||||
params: '{"q":"x"}',
|
||||
response: '{}'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
const result = chats2GPTMessages({ messages, reserveId: false, reserveTool: true });
|
||||
|
||||
// 1 merged assistant (reasoning + tool_calls) + 1 tool response
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result[0].role).toBe(ChatCompletionRequestMessageRoleEnum.Assistant);
|
||||
expect((result[0] as any).reasoning_content).toBe('Need to call a tool');
|
||||
expect((result[0] as any).tool_calls).toHaveLength(1);
|
||||
expect((result[0] as any).tool_calls[0].function.name).toBe('search_web');
|
||||
expect(result[1].role).toBe(ChatCompletionRequestMessageRoleEnum.Tool);
|
||||
});
|
||||
|
||||
it('should keep tool_calls separate when no reasoning precedes them', () => {
|
||||
const messages: ChatItemMiniType[] = [
|
||||
{
|
||||
obj: ChatRoleEnum.AI,
|
||||
value: [
|
||||
{ text: { content: 'Calling tool' } },
|
||||
{
|
||||
tool: {
|
||||
id: 'tool-1',
|
||||
toolName: 'Search',
|
||||
toolAvatar: '',
|
||||
functionName: 'search_web',
|
||||
params: '{}',
|
||||
response: '{}'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
const result = chats2GPTMessages({ messages, reserveId: false, reserveTool: true });
|
||||
|
||||
// text assistant + tool_calls assistant + tool response
|
||||
expect(result).toHaveLength(3);
|
||||
expect((result[0] as any).content).toBe('Calling tool');
|
||||
expect((result[0] as any).tool_calls).toBeUndefined();
|
||||
expect((result[1] as any).tool_calls).toHaveLength(1);
|
||||
expect(result[2].role).toBe(ChatCompletionRequestMessageRoleEnum.Tool);
|
||||
});
|
||||
|
||||
it('should handle multiple reasoning values producing separate assistant entries', () => {
|
||||
const messages: ChatItemMiniType[] = [
|
||||
{
|
||||
obj: ChatRoleEnum.AI,
|
||||
value: [
|
||||
{ reasoning: { content: 'Step 1 thinking' } },
|
||||
{ text: { content: 'Intermediate answer' } },
|
||||
{ reasoning: { content: 'Step 2 thinking' } },
|
||||
{ text: { content: 'Final answer' } }
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
const result = chats2GPTMessages({ messages, reserveId: false });
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
expect((result[0] as any).reasoning_content).toBe('Step 1 thinking');
|
||||
expect((result[0] as any).content).toBe('Intermediate answer');
|
||||
expect((result[1] as any).reasoning_content).toBe('Step 2 thinking');
|
||||
expect((result[1] as any).content).toBe('Final answer');
|
||||
});
|
||||
});
|
||||
|
||||
describe('GPTMessages2Chats', () => {
|
||||
@@ -530,6 +648,40 @@ describe('GPTMessages2Chats', () => {
|
||||
expect(result[0].value[1].text?.content).toBe('Final answer');
|
||||
});
|
||||
|
||||
it('should drop reasoning when reserveReason is false', () => {
|
||||
const messages: ChatCompletionMessageParam[] = [
|
||||
{
|
||||
role: ChatCompletionRequestMessageRoleEnum.Assistant,
|
||||
content: 'Final answer',
|
||||
reasoning_content: 'Let me think about this...'
|
||||
}
|
||||
];
|
||||
|
||||
const result = GPTMessages2Chats({ messages, reserveReason: false });
|
||||
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0].value).toHaveLength(1);
|
||||
expect(result[0].value[0].text?.content).toBe('Final answer');
|
||||
expect((result[0].value[0] as any).reasoning).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should keep only reasoning when assistant message has no content', () => {
|
||||
const messages: ChatCompletionMessageParam[] = [
|
||||
{
|
||||
role: ChatCompletionRequestMessageRoleEnum.Assistant,
|
||||
content: '',
|
||||
reasoning_content: 'Thinking only'
|
||||
}
|
||||
];
|
||||
|
||||
const result = GPTMessages2Chats({ messages });
|
||||
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0].value).toHaveLength(1);
|
||||
const value = result[0].value[0] as { reasoning?: { content: string } };
|
||||
expect(value.reasoning?.content).toBe('Thinking only');
|
||||
});
|
||||
|
||||
it('should merge messages with same dataId', () => {
|
||||
const messages: ChatCompletionMessageParam[] = [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user