Skip to content

Commit b0a58b9

Browse files
authored
feat: toolcall stream response (#6009)
1 parent a7929bd commit b0a58b9

File tree

10 files changed

+72
-30
lines changed

10 files changed

+72
-30
lines changed

document/content/docs/toc.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ description: FastGPT 文档目录
114114
- [/docs/upgrading/4-14/4141](/docs/upgrading/4-14/4141)
115115
- [/docs/upgrading/4-14/4142](/docs/upgrading/4-14/4142)
116116
- [/docs/upgrading/4-14/4143](/docs/upgrading/4-14/4143)
117+
- [/docs/upgrading/4-14/4144](/docs/upgrading/4-14/4144)
117118
- [/docs/upgrading/4-8/40](/docs/upgrading/4-8/40)
118119
- [/docs/upgrading/4-8/41](/docs/upgrading/4-8/41)
119120
- [/docs/upgrading/4-8/42](/docs/upgrading/4-8/42)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
title: 'V4.14.4(进行中)'
3+
description: 'FastGPT V4.14.4 更新说明'
4+
---
5+
6+
7+
## 🚀 新增内容
8+
9+
1. 工具调用支持配置流输出
10+
11+
## ⚙️ 优化
12+
13+
14+
## 🐛 修复
15+
16+
17+
## 插件
18+
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"title": "4.14.x",
33
"description": "",
4-
"pages": ["4143", "4142", "4141", "4140"]
4+
"pages": ["4144", "4143", "4142", "4141", "4140"]
55
}

document/data/doc-last-modified.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@
117117
"document/content/docs/upgrading/4-14/4140.mdx": "2025-11-06T15:43:00+08:00",
118118
"document/content/docs/upgrading/4-14/4141.mdx": "2025-11-19T10:15:27+08:00",
119119
"document/content/docs/upgrading/4-14/4142.mdx": "2025-11-18T19:27:14+08:00",
120-
"document/content/docs/upgrading/4-14/4143.mdx": "2025-11-25T17:08:33+08:00",
120+
"document/content/docs/upgrading/4-14/4143.mdx": "2025-11-26T20:52:05+08:00",
121121
"document/content/docs/upgrading/4-8/40.mdx": "2025-08-02T19:38:37+08:00",
122122
"document/content/docs/upgrading/4-8/41.mdx": "2025-08-02T19:38:37+08:00",
123123
"document/content/docs/upgrading/4-8/42.mdx": "2025-08-02T19:38:37+08:00",

packages/global/core/chat/utils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ export const getHistoryPreview = (
7070
item.text?.content || item?.tools?.map((item) => item.toolName).join(',') || ''
7171
);
7272
})
73-
.join('') || ''
73+
.join('')
74+
.trim() || ''
7475
);
7576
}
7677
return '';

packages/global/core/workflow/template/system/agent.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ export const AgentNode: FlowNodeTemplateType = {
5252
label: '',
5353
valueType: WorkflowIOValueTypeEnum.number
5454
},
55+
{
56+
key: NodeInputKeyEnum.aiChatIsResponseText,
57+
renderTypeList: [FlowNodeInputTypeEnum.hidden],
58+
label: '',
59+
value: true,
60+
valueType: WorkflowIOValueTypeEnum.boolean
61+
},
5562
{
5663
key: NodeInputKeyEnum.aiChatVision,
5764
renderTypeList: [FlowNodeInputTypeEnum.hidden],

packages/service/core/ai/llm/utils.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,15 +265,18 @@ export const loadRequestMessages = async ({
265265
| undefined
266266
) => {
267267
if (typeof content === 'string') {
268-
return content || '';
268+
return content?.trim() || '';
269269
}
270270
// 交互节点
271271
if (!content) return '';
272272

273273
const result = content.filter((item) => item?.type === 'text');
274274
if (result.length === 0) return '';
275275

276-
return result.map((item) => item.text).join('\n');
276+
return result
277+
.map((item) => item.text)
278+
.join('\n')
279+
.trim();
277280
};
278281

279282
if (messages.length === 0) {

packages/service/core/workflow/dispatch/ai/tool/index.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
5757
history = 6,
5858
fileUrlList: fileLinks,
5959
aiChatVision,
60-
aiChatReasoning
60+
aiChatReasoning,
61+
isResponseAnswerText = true
6162
}
6263
} = props;
6364

@@ -235,7 +236,9 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
235236
(sum, item) => sum + item.runTimes,
236237
0
237238
),
238-
[DispatchNodeResponseKeyEnum.assistantResponses]: previewAssistantResponses,
239+
[DispatchNodeResponseKeyEnum.assistantResponses]: isResponseAnswerText
240+
? previewAssistantResponses
241+
: undefined,
239242
[DispatchNodeResponseKeyEnum.nodeResponse]: {
240243
// 展示的积分消耗
241244
totalPoints: totalPointsUsage,

packages/service/core/workflow/dispatch/ai/tool/toolCall.ts

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ export const runToolCall = async (props: DispatchToolModuleProps): Promise<RunTo
3333
aiChatStopSign,
3434
aiChatResponseFormat,
3535
aiChatJsonSchema,
36-
aiChatReasoning
36+
aiChatReasoning,
37+
isResponseAnswerText = true
3738
}
3839
} = workflowProps;
3940

@@ -141,6 +142,7 @@ export const runToolCall = async (props: DispatchToolModuleProps): Promise<RunTo
141142
});
142143
},
143144
onStreaming({ text }) {
145+
if (!isResponseAnswerText) return;
144146
workflowStreamResponse?.({
145147
write,
146148
event: SseResponseEventEnum.answer,
@@ -150,6 +152,7 @@ export const runToolCall = async (props: DispatchToolModuleProps): Promise<RunTo
150152
});
151153
},
152154
onToolCall({ call }) {
155+
if (!isResponseAnswerText) return;
153156
const toolNode = toolNodesMap.get(call.function.name);
154157
if (toolNode) {
155158
workflowStreamResponse?.({
@@ -168,6 +171,7 @@ export const runToolCall = async (props: DispatchToolModuleProps): Promise<RunTo
168171
}
169172
},
170173
onToolParam({ tool, params }) {
174+
if (!isResponseAnswerText) return;
171175
workflowStreamResponse?.({
172176
write,
173177
event: SseResponseEventEnum.toolParams,
@@ -209,18 +213,20 @@ export const runToolCall = async (props: DispatchToolModuleProps): Promise<RunTo
209213
// Format tool response
210214
const stringToolResponse = formatToolResponse(toolRunResponse.toolResponses);
211215

212-
workflowStreamResponse?.({
213-
event: SseResponseEventEnum.toolResponse,
214-
data: {
215-
tool: {
216-
id: call.id,
217-
toolName: '',
218-
toolAvatar: '',
219-
params: '',
220-
response: sliceStrStartEnd(stringToolResponse, 5000, 5000)
216+
if (isResponseAnswerText) {
217+
workflowStreamResponse?.({
218+
event: SseResponseEventEnum.toolResponse,
219+
data: {
220+
tool: {
221+
id: call.id,
222+
toolName: '',
223+
toolAvatar: '',
224+
params: '',
225+
response: sliceStrStartEnd(stringToolResponse, 5000, 5000)
226+
}
221227
}
222-
}
223-
});
228+
});
229+
}
224230

225231
toolRunResponses.push(toolRunResponse);
226232

@@ -258,18 +264,20 @@ export const runToolCall = async (props: DispatchToolModuleProps): Promise<RunTo
258264
// console.dir(runtimeEdges, { depth: null });
259265
const stringToolResponse = formatToolResponse(toolRunResponse.toolResponses);
260266

261-
workflowStreamResponse?.({
262-
event: SseResponseEventEnum.toolResponse,
263-
data: {
264-
tool: {
265-
id: toolParams.toolCallId,
266-
toolName: '',
267-
toolAvatar: '',
268-
params: '',
269-
response: sliceStrStartEnd(stringToolResponse, 5000, 5000)
267+
if (isResponseAnswerText) {
268+
workflowStreamResponse?.({
269+
event: SseResponseEventEnum.toolResponse,
270+
data: {
271+
tool: {
272+
id: toolParams.toolCallId,
273+
toolName: '',
274+
toolAvatar: '',
275+
params: '',
276+
response: sliceStrStartEnd(stringToolResponse, 5000, 5000)
277+
}
270278
}
271-
}
272-
});
279+
});
280+
}
273281

274282
toolRunResponses.push(toolRunResponse);
275283
const assistantMessages = chats2GPTMessages({

packages/service/core/workflow/dispatch/ai/tool/type.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export type DispatchToolModuleProps = ModuleDispatchProps<{
3131
[NodeInputKeyEnum.aiSystemPrompt]: string;
3232
[NodeInputKeyEnum.aiChatTemperature]: number;
3333
[NodeInputKeyEnum.aiChatMaxToken]: number;
34+
[NodeInputKeyEnum.aiChatIsResponseText]: boolean;
3435
[NodeInputKeyEnum.aiChatVision]?: boolean;
3536
[NodeInputKeyEnum.aiChatReasoning]?: boolean;
3637
[NodeInputKeyEnum.aiChatTopP]?: number;

0 commit comments

Comments
 (0)