Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions document/content/docs/upgrading/4-14/4145.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,11 @@ description: 'FastGPT V4.14.5 更新说明'
5. 加载默认模型时,maxTokens 字段未赋值,导致模型最大响应值配置为空。
6. S3 文件清理队列因网络稳定问题出现阻塞,导致删除任务不再执行。
7. 对话日志接口适配 mongo4.x 语法。
8. 变量更新节点将文件 URL 字符串数组错误转换为对象数组。
9. 多个表单输入节点共享 sessionStorage 导致默认值不显示。
10. 代码运行节点切换语言后,AI 仍使用旧语言生成代码。
11. 多个自定义反馈节点并发写入触发数据库写入冲突。
12. 交互节点后续的自定义反馈节点写入失败。


## 插件
4 changes: 2 additions & 2 deletions document/data/doc-last-modified.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@
"document/content/docs/protocol/terms.en.mdx": "2025-12-15T23:36:54+08:00",
"document/content/docs/protocol/terms.mdx": "2025-12-15T23:36:54+08:00",
"document/content/docs/toc.en.mdx": "2025-08-04T13:42:36+08:00",
"document/content/docs/toc.mdx": "2026-01-06T18:19:42+08:00",
"document/content/docs/toc.mdx": "2026-01-06T13:25:46+08:00",
"document/content/docs/upgrading/4-10/4100.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-10/4101.mdx": "2025-09-08T20:07:20+08:00",
"document/content/docs/upgrading/4-11/4110.mdx": "2025-08-05T23:20:39+08:00",
Expand Down Expand Up @@ -204,4 +204,4 @@
"document/content/docs/use-cases/external-integration/openapi.mdx": "2025-09-29T11:34:11+08:00",
"document/content/docs/use-cases/external-integration/wecom.mdx": "2025-12-10T20:07:05+08:00",
"document/content/docs/use-cases/index.mdx": "2025-07-24T14:23:04+08:00"
}
}
3 changes: 2 additions & 1 deletion packages/global/core/workflow/runtime/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ export enum DispatchNodeResponseKeyEnum {
interactive = 'INTERACTIVE', // is interactive
runTimes = 'runTimes', // run times
newVariables = 'newVariables', // new variables
memories = 'system_memories' // memories
memories = 'system_memories', // memories
customFeedbacks = 'customFeedbacks' // custom feedbacks
}

export const needReplaceReferenceInputTypeList = [
Expand Down
2 changes: 1 addition & 1 deletion packages/global/core/workflow/runtime/type.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ export type ChatDispatchProps = {
responseChatItemId?: string;
histories: ChatItemType[];
variables: Record<string, any>; // global variable
cloneVariables: Record<string, any>;
query: UserChatItemValueItemType[]; // trigger query
chatConfig: AppSchema['chatConfig'];
lastInteractive?: WorkflowInteractiveResponseType; // last interactive response
Expand Down Expand Up @@ -274,6 +273,7 @@ export type DispatchNodeResultType<T = {}, ERR = { [NodeOutputKeyEnum.errorText]
[DispatchNodeResponseKeyEnum.newVariables]?: Record<string, any>;
[DispatchNodeResponseKeyEnum.memories]?: Record<string, any>;
[DispatchNodeResponseKeyEnum.interactive]?: InteractiveNodeResponseType;
[DispatchNodeResponseKeyEnum.customFeedbacks]?: string[];

data?: T;
error?: ERR;
Expand Down
16 changes: 4 additions & 12 deletions packages/service/core/chat/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,29 +205,21 @@ export const addCustomFeedbacks = async ({
dataId?: string;
feedbacks: string[];
}) => {
if (!chatId || !dataId) return;
if (!chatId || !dataId || !feedbacks || feedbacks.length === 0) return;

try {
await mongoSessionRun(async (session) => {
// Add custom feedbacks to ChatItem
await MongoChatItem.updateOne(
{
appId,
appId: new Types.ObjectId(appId),
chatId,
dataId
},
{
$push: { customFeedbacks: { $each: feedbacks } }
},
{ $push: { customFeedbacks: { $each: feedbacks } } },
{ session }
);

// Update ChatLog feedback statistics
await updateChatFeedbackCount({
appId,
chatId,
session
});
await updateChatFeedbackCount({ appId, chatId, session });
});
} catch (error) {
addLog.error('addCustomFeedbacks error', error);
Expand Down
6 changes: 4 additions & 2 deletions packages/service/core/workflow/dispatch/child/runApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ export const dispatchRunAppNode = async (props: Props): Promise<Response> => {
assistantResponses,
runTimes,
workflowInteractiveResponse,
system_memories
system_memories,
customFeedbacks
} = await runWorkflow({
...props,
usageId: undefined,
Expand Down Expand Up @@ -205,7 +206,8 @@ export const dispatchRunAppNode = async (props: Props): Promise<Response> => {
totalPoints: usagePoints
}
],
[DispatchNodeResponseKeyEnum.toolResponses]: text
[DispatchNodeResponseKeyEnum.toolResponses]: text,
[DispatchNodeResponseKeyEnum.customFeedbacks]: customFeedbacks
};
} catch (error) {
return getNodeErrResponse({ error });
Expand Down
39 changes: 27 additions & 12 deletions packages/service/core/workflow/dispatch/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import type {
} from '@fastgpt/global/core/workflow/runtime/type';
import type { RuntimeNodeItemType } from '@fastgpt/global/core/workflow/runtime/type.d';
import { getErrText, UserError } from '@fastgpt/global/common/error/utils';
import { ChatItemValueTypeEnum } from '@fastgpt/global/core/chat/constants';
import { ChatItemValueTypeEnum, ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
import { filterPublicNodeResponseData } from '@fastgpt/global/core/chat/utils';
import {
checkNodeRunStatus,
Expand Down Expand Up @@ -57,13 +57,12 @@ import { addPreviewUrlToChatItems, presignVariablesFileUrls } from '../../chat/u
import type { MCPClient } from '../../app/mcp';
import { TeamErrEnum } from '@fastgpt/global/common/error/code/team';
import { i18nT } from '../../../../web/i18n/utils';
import { clone } from 'lodash';
import { validateFileUrlDomain } from '../../../common/security/fileUrlValidator';
import { delAgentRuntimeStopSign, shouldWorkflowStop } from './workflowStatus';

type Props = Omit<
ChatDispatchProps,
'checkIsStopping' | 'workflowDispatchDeep' | 'timezone' | 'externalProvider' | 'cloneVariables'
'checkIsStopping' | 'workflowDispatchDeep' | 'timezone' | 'externalProvider'
> & {
runtimeNodes: RuntimeNodeItemType[];
runtimeEdges: RuntimeEdgeItemType[];
Expand Down Expand Up @@ -100,6 +99,16 @@ export async function dispatchWorkFlow({
apiVersion
} = data;

const responseChatItemId = (() => {
if (!!lastInteractive) {
const lastAiChat = histories.findLast((item) => item.obj === ChatRoleEnum.AI);
if (lastAiChat?.dataId) {
return lastAiChat.dataId;
}
}
return data.responseChatItemId;
})();

// Check url valid
const invalidInput = query.some((item) => {
if (item.type === ChatItemValueTypeEnum.file && item.file?.url) {
Expand Down Expand Up @@ -182,14 +191,14 @@ export async function dispatchWorkFlow({
}

// Get default variables
const cloneVariables = clone(data.variables);
const defaultVariables = {
...externalProvider.externalWorkflowVariables,
...(await getSystemVariables({
...data,
query,
histories,
timezone
timezone,
responseChatItemId
}))
};
// MCP
Expand Down Expand Up @@ -219,6 +228,7 @@ export async function dispatchWorkFlow({
// Init some props
return runWorkflow({
...data,
responseChatItemId,
checkIsStopping,
query,
histories,
Expand All @@ -228,8 +238,7 @@ export async function dispatchWorkFlow({
workflowDispatchDeep: 0,
usageId: newUsageId,
concatUsage,
mcpClientMemory,
cloneVariables
mcpClientMemory
}).finally(async () => {
if (streamCheckTimer) {
clearInterval(streamCheckTimer);
Expand Down Expand Up @@ -273,8 +282,7 @@ export const runWorkflow = async (data: RunWorkflowProps): Promise<DispatchFlowR
usageId,
concatUsage,
runningUserInfo: { teamId },
mcpClientMemory,
cloneVariables
mcpClientMemory
} = data;

// Over max depth
Expand All @@ -296,7 +304,6 @@ export const runWorkflow = async (data: RunWorkflowProps): Promise<DispatchFlowR
[DispatchNodeResponseKeyEnum.toolResponses]: null,
[DispatchNodeResponseKeyEnum.newVariables]: runtimeSystemVar2StoreType({
variables,
cloneVariables,
removeObj: externalProvider.externalWorkflowVariables,
userVariablesConfigs: data.chatConfig?.variables
}),
Expand Down Expand Up @@ -343,6 +350,7 @@ export const runWorkflow = async (data: RunWorkflowProps): Promise<DispatchFlowR
}
| undefined;
system_memories: Record<string, any> = {}; // Workflow node memories
customFeedbackList: string[] = []; // Custom feedbacks collected from nodes

// Debug
debugNextStepRunNodes: RuntimeNodeItemType[] = []; // 记录 Debug 模式下,下一个阶段需要执行的节点。
Expand Down Expand Up @@ -720,7 +728,8 @@ export const runWorkflow = async (data: RunWorkflowProps): Promise<DispatchFlowR
assistantResponses,
rewriteHistories,
runTimes = 1,
system_memories: newMemories
system_memories: newMemories,
customFeedbacks
}: NodeResponseCompleteType) => {
// Add run times
this.workflowRunTimes += runTimes;
Expand All @@ -737,6 +746,11 @@ export const runWorkflow = async (data: RunWorkflowProps): Promise<DispatchFlowR
this.chatResponses.push(responseData);
}

// Collect custom feedbacks
if (customFeedbacks && Array.isArray(customFeedbacks)) {
this.customFeedbackList = this.customFeedbackList.concat(customFeedbacks);
}

// Push usage in real time. Avoid a workflow usage a large number of points
if (nodeDispatchUsages) {
if (usageId) {
Expand Down Expand Up @@ -1120,14 +1134,15 @@ export const runWorkflow = async (data: RunWorkflowProps): Promise<DispatchFlowR
[DispatchNodeResponseKeyEnum.toolResponses]: workflowQueue.toolRunResponse,
[DispatchNodeResponseKeyEnum.newVariables]: runtimeSystemVar2StoreType({
variables,
cloneVariables,
removeObj: externalProvider.externalWorkflowVariables,
userVariablesConfigs: data.chatConfig?.variables
}),
[DispatchNodeResponseKeyEnum.memories]:
Object.keys(workflowQueue.system_memories).length > 0
? workflowQueue.system_memories
: undefined,
[DispatchNodeResponseKeyEnum.customFeedbacks]:
workflowQueue.customFeedbackList.length > 0 ? workflowQueue.customFeedbackList : undefined,
durationSeconds
};
};
Expand Down
10 changes: 9 additions & 1 deletion packages/service/core/workflow/dispatch/loop/runLoop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export const dispatchLoop = async (props: Props): Promise<Response> => {
const outputValueArr = interactiveData ? interactiveData.loopResult : [];
const loopResponseDetail: ChatHistoryItemResType[] = [];
let assistantResponses: AIChatItemValueItemType[] = [];
const customFeedbacks: string[] = [];
let totalPoints = 0;
let newVariables: Record<string, any> = props.variables;
let interactiveResponse: WorkflowInteractiveResponseType | undefined = undefined;
Expand Down Expand Up @@ -116,6 +117,11 @@ export const dispatchLoop = async (props: Props): Promise<Response> => {
assistantResponses.push(...response.assistantResponses);
totalPoints += response.flowUsages.reduce((acc, usage) => acc + usage.totalPoints, 0);

// Collect custom feedbacks
if (response[DispatchNodeResponseKeyEnum.customFeedbacks]) {
customFeedbacks.push(...response[DispatchNodeResponseKeyEnum.customFeedbacks]);
}

// Concat new variables
newVariables = {
...newVariables,
Expand Down Expand Up @@ -163,6 +169,8 @@ export const dispatchLoop = async (props: Props): Promise<Response> => {
}
]
: [],
[DispatchNodeResponseKeyEnum.newVariables]: newVariables
[DispatchNodeResponseKeyEnum.newVariables]: newVariables,
[DispatchNodeResponseKeyEnum.customFeedbacks]:
customFeedbacks.length > 0 ? customFeedbacks : undefined
};
};
65 changes: 36 additions & 29 deletions packages/service/core/workflow/dispatch/plugin/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,35 +132,41 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
appId: String(plugin.id),
...(externalProvider ? externalProvider.externalWorkflowVariables : {})
};
const { flowResponses, flowUsages, assistantResponses, runTimes, system_memories } =
await runWorkflow({
...props,
usageId: undefined,
// Rewrite stream mode
...(system_forbid_stream
? {
stream: false,
workflowStreamResponse: undefined
}
: {}),
runningAppInfo: {
id: String(plugin.id),
name: plugin.name,
// 如果系统插件有 teamId 和 tmbId,则使用系统插件的 teamId 和 tmbId(管理员指定了插件作为系统插件)
teamId: plugin.teamId || runningAppInfo.teamId,
tmbId: plugin.tmbId || runningAppInfo.tmbId,
isChildApp: true
},
const {
flowResponses,
flowUsages,
assistantResponses,
runTimes,
system_memories,
[DispatchNodeResponseKeyEnum.customFeedbacks]: customFeedbacks
} = await runWorkflow({
...props,
usageId: undefined,
// Rewrite stream mode
...(system_forbid_stream
? {
stream: false,
workflowStreamResponse: undefined
}
: {}),
runningAppInfo: {
id: String(plugin.id),
name: plugin.name,
// 如果系统插件有 teamId 和 tmbId,则使用系统插件的 teamId 和 tmbId(管理员指定了插件作为系统插件)
teamId: plugin.teamId || runningAppInfo.teamId,
tmbId: plugin.tmbId || runningAppInfo.tmbId,
isChildApp: true
},
variables: runtimeVariables,
query: serverGetWorkflowToolRunUserQuery({
pluginInputs: getWorkflowToolInputsFromStoreNodes(plugin.nodes),
variables: runtimeVariables,
query: serverGetWorkflowToolRunUserQuery({
pluginInputs: getWorkflowToolInputsFromStoreNodes(plugin.nodes),
variables: runtimeVariables,
files
}).value,
chatConfig: {},
runtimeNodes,
runtimeEdges: storeEdges2RuntimeEdges(plugin.edges)
});
files
}).value,
chatConfig: {},
runtimeNodes,
runtimeEdges: storeEdges2RuntimeEdges(plugin.edges)
});
const output = flowResponses.find((item) => item.moduleType === FlowNodeTypeEnum.pluginOutput);

const usagePoints = await computedAppToolUsage({
Expand Down Expand Up @@ -200,7 +206,8 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
acc[key] = output.pluginOutput![key];
return acc;
}, {})
: null
: null,
[DispatchNodeResponseKeyEnum.customFeedbacks]: customFeedbacks
};
} catch (error) {
return getNodeErrResponse({
Expand Down
Loading
Loading