Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ title: Query Enhancement
description: FastGPT Query Enhancement node overview and usage
---

> **Deprecated**: The Query Enhancement node can no longer be added to new workflows. Existing nodes remain runnable for compatibility.

## Characteristics

- Can be added multiple times
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ title: 问题优化
description: 问题优化模块介绍和使用
---

> **已弃用**:问题优化节点已停止新增。已存在于画布中的节点仍可继续运行。

## 特点

- 可重复添加
Expand Down
8 changes: 4 additions & 4 deletions document/data/doc-last-modified.json
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@
"content/guide/dataset/websync.mdx": "2026-05-07T15:06:40+08:00",
"content/guide/getting-started/index.en.mdx": "2026-07-17T19:17:14+08:00",
"content/guide/getting-started/index.mdx": "2026-07-17T19:17:14+08:00",
"content/guide/getting-started/quick-start.en.mdx": "2026-08-10T19:59:02+08:00",
"content/guide/getting-started/quick-start.mdx": "2026-08-10T19:59:02+08:00",
"content/guide/getting-started/quick-start.en.mdx": "2026-08-11T10:31:10+08:00",
"content/guide/getting-started/quick-start.mdx": "2026-08-11T10:31:10+08:00",
"content/guide/index.en.mdx": "2026-05-07T15:06:40+08:00",
"content/guide/index.mdx": "2026-05-07T15:06:40+08:00",
"content/guide/version/cloud/faq.en.mdx": "2026-07-17T19:17:14+08:00",
Expand Down Expand Up @@ -337,8 +337,8 @@
"content/self-host/upgrading/4-15/4157.mdx": "2026-08-07T16:45:18+08:00",
"content/self-host/upgrading/4-16/41601.en.mdx": "2026-08-07T16:45:18+08:00",
"content/self-host/upgrading/4-16/41601.mdx": "2026-08-07T16:45:18+08:00",
"content/self-host/upgrading/4-16/41602.en.mdx": "2026-08-11T09:51:05+08:00",
"content/self-host/upgrading/4-16/41602.mdx": "2026-08-11T09:51:05+08:00",
"content/self-host/upgrading/4-16/41602.en.mdx": "2026-08-11T10:31:10+08:00",
"content/self-host/upgrading/4-16/41602.mdx": "2026-08-11T10:31:10+08:00",
"content/self-host/upgrading/outdated/40.en.mdx": "2026-07-25T00:27:20+08:00",
"content/self-host/upgrading/outdated/40.mdx": "2026-07-25T00:27:20+08:00",
"content/self-host/upgrading/outdated/41.en.mdx": "2026-07-25T00:27:20+08:00",
Expand Down
37 changes: 21 additions & 16 deletions packages/global/core/app/formEdit/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,19 @@ type InputRenderTypeState = {
};

type SavedToolInputTypeState = InputRenderTypeState &
Pick<Partial<FlowNodeInputItemType>, 'isToolParam' | 'toolDescription'>;
Pick<Partial<FlowNodeInputItemType>, 'isToolParam' | 'defaultAgentGenerated' | 'toolDescription'>;

type ToolInputTypeState = InputRenderTypeState &
Pick<FlowNodeInputItemType, 'key' | 'renderTypeList'> &
Pick<
Partial<FlowNodeInputItemType>,
'isToolParam' | 'toolDescription' | 'list' | 'enums' | 'enum' | 'valueType'
| 'isToolParam'
| 'defaultAgentGenerated'
| 'toolDescription'
| 'list'
| 'enums'
| 'enum'
| 'valueType'
>;

type ToolInputDefaultModeOptions = {
Expand Down Expand Up @@ -131,16 +137,17 @@ export const normalizeLegacyWorkflowHttpToolInputsDefaultMode = <T extends FlowN

return {
...input,
isToolParam: true
isToolParam: true,
defaultAgentGenerated: true
};
});

/**
* 将节点输入升级为 selectedType 协议。
*
* 显式 selectedType 优先;旧 selectedTypeIndex 仅在没有新字段时用于恢复选择。
* 所有支持 AI 生成的输入都会补充 agentGenerated;工具上下文才允许选中该类型,
* 并在没有明确选择时按 isToolParam 应用默认值。
* 只有工具参数才会补充 agentGenerated;工具上下文才允许选中该类型,
* 并在没有明确选择时按 defaultAgentGenerated 应用默认值。
* 返回值始终移除 deprecated selectedTypeIndex,供画布兼容层和 runtime 边界共用。
*/
export const normalizeFlowNodeInputType = <T extends FlowNodeInputItemType>(
Expand All @@ -160,17 +167,15 @@ export const normalizeFlowNodeInputType = <T extends FlowNodeInputItemType>(
: inputRenderTypeList[input.selectedTypeIndex];
const hasExplicitSelectedType = input.selectedType !== undefined;
const recommendsAgentGenerated =
input.isToolParam === true ||
(input.isToolParam !== false && isTool && input.key === NodeInputKeyEnum.userChatInput) ||
(allowLegacyToolDescriptionFallback &&
input.isToolParam === undefined &&
!!input.toolDescription);
input.defaultAgentGenerated === true ||
(allowLegacyToolDescriptionFallback && input.isToolParam === true && !!input.toolDescription);
const isLegacyDefaultSelection =
!hasExplicitSelectedType &&
input.selectedTypeIndex === 0 &&
(isTool || deferDefaultSelection) &&
recommendsAgentGenerated;
const supportsAgentGenerated = canInputBeAgentGenerated(input);
const supportsAgentGenerated =
input.isToolParam === true && input.canEdit !== true && canInputBeAgentGenerated(input);
const canUseAgentGenerated = isTool && supportsAgentGenerated;
const renderTypeList = Array.from(
new Set([
Expand Down Expand Up @@ -322,7 +327,7 @@ export const getToolInputDisplayRenderTypeList = ({
input: FlowNodeInputItemType;
showAgentGenerated: boolean;
}) => {
if (!(showAgentGenerated && canInputBeAgentGenerated(input))) {
if (!(showAgentGenerated && input.isToolParam === true && canInputBeAgentGenerated(input))) {
return Array.from(
new Set(input.renderTypeList.filter((type) => type !== FlowNodeInputTypeEnum.agentGenerated))
);
Expand Down Expand Up @@ -482,13 +487,13 @@ export const getSavedToolInputSelectedType = ({
};

/**
* 删除工具定义携带的默认输入方式,避免把它当成用户在配置页的最终选择持久化。
* 删除工具定义携带的默认 AI 生成方式,避免把它当成用户在配置页的最终选择持久化。
*/
export const stripToolInputDefaultMode = <T extends FlowNodeInputItemType>(
input: T
): Omit<T, 'isToolParam'> => {
): Omit<T, 'defaultAgentGenerated'> => {
const inputWithoutDefaultMode = { ...input };
delete inputWithoutDefaultMode.isToolParam;
delete inputWithoutDefaultMode.defaultAgentGenerated;
return inputWithoutDefaultMode;
};

Expand Down Expand Up @@ -538,7 +543,7 @@ export const filterToolConfiguredParams = ({

/**
* 工具首次加入工作流/Agent 时,将默认输入方式固化为 selectedType。
* isToolParam 是插件/schema 声明的默认输入方式;toolDescription 只作为模型参数描述
* isToolParam 声明输入是否属于工具参数;defaultAgentGenerated 只决定首次默认来源
*/
export const initToolInputTypeByDefaultMode = <T extends FlowNodeInputItemType>(
input: T,
Expand Down
4 changes: 2 additions & 2 deletions packages/global/core/app/jsonschema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ export const JsonSchemaPropertiesItemSchema = z
// 自定义扩展(FastGPT 专用)
'x-tool-description': z.string().optional(), // 工具描述
toolDescription: z.string().optional(), // 工具描述 for System Tool
isToolParam: z.boolean().optional(), // 是否默认作为工具调用参数
isToolParam: z.boolean().optional(), // 是否作为工具调用参数
isSecret: z.boolean().optional(), // System Tool
[JsonSchemaNodeInputMetadataKey]: z.any().optional(),
[JsonSchemaNodeOutputMetadataKey]: z.any().optional()
Expand Down Expand Up @@ -857,7 +857,7 @@ export const nodeInputs2JsonSchema = ({
};
};

const modelSchemaIgnoredKeys = new Set(['title', 'default']);
const modelSchemaIgnoredKeys = new Set(['title', 'default', 'isToolParam']);
const schemaDataKeywords = new Set(['const', 'enum', 'examples']);

/** 生成模型 schema 副本时移除不会参与工具调用协议的展示与默认值 annotation。 */
Expand Down
3 changes: 2 additions & 1 deletion packages/global/core/app/tool/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ const createToolInputDefinitions = ({
jsonSchema?: JSONSchemaInputType;
}): ToolInputDefinition[] =>
inputs.map((input) => {
const canAgentGenerate = canInputBeAgentGenerated(input);
const canAgentGenerate =
input.isToolParam === true && input.canEdit !== true && canInputBeAgentGenerated(input);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里的 input.canEdit !== true 会把本 PR 新增的 HTTP/Code 工具参数排除出模型 Schema。EditFieldModal 创建的工具参数是 { canEdit: true, isToolParam: true },旧 HTTP 字段迁移为工具参数后也仍保留 canEdit: true。按当前约定,旧自定义输入可以继续保留,但只有 isToolParam 的那部分传给 AI,因此 canEdit 不应作为禁止 AI 生成的条件;否则这些参数既不进入模型参数,通常也没有固定 value 可注入。建议以 isToolParam && canInputBeAgentGenerated 判定,并补测“未标工具参数的旧自定义输入不进入 Schema、已标工具参数的输入进入 Schema”。

// reference 在工作流执行前已解析为固定值,不受 Agent 配置页手动控件范围限制。
const canUseFixedBinding =
canInputBeManuallyConfigured({ renderTypeList: input.renderTypeList ?? [] }) ||
Expand Down
3 changes: 2 additions & 1 deletion packages/global/core/app/tool/workflowTool/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ export const normalizeWorkflowToolInputDefaultMode = <T extends FlowNodeInputIte

return {
...input,
isToolParam: true
isToolParam: true,
defaultAgentGenerated: true
};
};

Expand Down
6 changes: 3 additions & 3 deletions packages/global/core/workflow/template/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { AgentNode } from './system/agent';
import { RunAppModule } from './system/abandoned/runApp/index';
import { PluginInputModule } from './system/pluginInput';
import { PluginOutputModule } from './system/pluginOutput';
import { AiQueryExtension } from './system/queryExtension';
import { AiQueryExtension } from './system/abandoned/queryExtension';
import { RunAppNode } from './system/runApp';
import { RunPluginModule } from './system/runPlugin';

Expand Down Expand Up @@ -54,7 +54,6 @@ const systemNodes: FlowNodeTemplateType[] = [
AgentNode,
ReadFilesNode,
HttpNode468,
AiQueryExtension,
IfElseNode,
VariableUpdateNode,
CodeNode,
Expand Down Expand Up @@ -94,5 +93,6 @@ export const moduleTemplatesFlat: FlowNodeTemplateType[] = [
LoopEndNode,
LoopRunStartNode,
RunToolNode,
RunToolSetNode
RunToolSetNode,
AiQueryExtension
];
92 changes: 92 additions & 0 deletions packages/global/core/workflow/template/context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import type { FlowNodeTypeEnum } from '../node/constant';
import { NodeOutputKeyEnum } from '../constants';
import type {
FlowNodeTemplateType,
FlowNodeItemType,
NodeTemplateContext,
NodeTemplateContextPredicate
} from '../type/node';

/**
* 模板展示上下文规则:规则字段全部为空时匹配任何上下文。
*/
export type NodeTemplateContextRule = {
sourceType?: FlowNodeTypeEnum;
handleId?: string;
parentType?: FlowNodeTypeEnum;
};

const matchRule = (rule: NodeTemplateContextRule, ctx: NodeTemplateContext): boolean => {
if (rule.sourceType !== undefined && rule.sourceType !== ctx.sourceType) return false;
if (rule.handleId !== undefined && rule.handleId !== ctx.handleId) return false;
if (rule.parentType !== undefined && rule.parentType !== ctx.parentType) return false;
return true;
};

/**
* 白名单工厂:上下文存在且匹配任一规则时展示。
*/
export const createShowInContext = (
rules: NodeTemplateContextRule[]
): NodeTemplateContextPredicate => {
return (ctx) => !!ctx && rules.some((rule) => matchRule(rule, ctx));
};

/**
* 黑名单工厂:匹配任一规则时隐藏;无上下文时展示。
*/
export const createHideInContext = (
rules: NodeTemplateContextRule[]
): NodeTemplateContextPredicate => {
return (ctx) => !ctx || !rules.some((rule) => matchRule(rule, ctx));
};

/**
* 模板在给定上下文中是否可见:未声明谓词的模板为顶级节点,处处可见。
*/
export const isTemplateVisible = (
template: Pick<FlowNodeTemplateType, 'isShowInContext'>,
ctx: NodeTemplateContext | null
): boolean => {
return !template.isShowInContext || template.isShowInContext(ctx);
};

/**
* 由源节点信息构建快捷添加/连线共用的展示上下文;sourceNode 不存在时返回 null。
*/
export const buildNodeTemplateContext = ({
sourceNode,
edges,
handleId,
getNodeById,
isSidebar = false,
hasToolNode = false,
hasLoopRunNode = false
}: {
sourceNode:
| Pick<FlowNodeItemType, 'nodeId' | 'flowNodeType' | 'isTool' | 'parentNodeId'>
| undefined;
edges: { target: string; targetHandle?: string | null }[];
handleId?: string | null;
getNodeById: (nodeId: string | undefined | null) => FlowNodeItemType | undefined;
isSidebar?: boolean;
hasToolNode?: boolean;
hasLoopRunNode?: boolean;
}): NodeTemplateContext | null => {
if (!sourceNode && !isSidebar) return null;
const parentNode = sourceNode?.parentNodeId ? getNodeById(sourceNode.parentNodeId) : undefined;
return {
isSidebar,
sourceNodeId: sourceNode?.nodeId ?? null,
sourceType: sourceNode?.flowNodeType ?? null,
sourceIsTool: !!sourceNode?.isTool,
isConnectedTool: edges.some(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里的 isConnectedTool 只识别直接通过 selectedTools 连入的第一层节点,不能表示整个 Tool 子流程。文档展示的 Tool Call → Knowledge Search → HTTP → Stop Tool 中,HTTP 的入边已经是普通边,因此这里会返回 false,后续 Stop Tool 会被隐藏或禁止连接。建议计算从 selectedTools 根节点出发的传递可达性,或显式维护 Tool 子流程归属,并增加至少两跳的连线测试。

(edge) =>
edge.target === sourceNode?.nodeId && edge.targetHandle === NodeOutputKeyEnum.selectedTools
),
handleId: handleId ?? null,
parentType: parentNode?.flowNodeType ?? null,
hasToolNode,
hasLoopRunNode
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,28 @@ import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
} from '../../node/constant';
import { type FlowNodeTemplateType } from '../../type/node';
} from '../../../node/constant';
import { type FlowNodeTemplateType } from '../../../type/node';
import {
WorkflowIOValueTypeEnum,
NodeInputKeyEnum,
NodeOutputKeyEnum,
FlowNodeTemplateTypeEnum
} from '../../constants';
} from '../../../constants';
import {
Input_Template_History,
Input_Template_UserChatInput,
Input_Template_SelectAIModel
} from '../input';
import { i18nT } from '../../../../common/i18n/utils';
} from '../../input';
import { i18nT } from '../../../../../common/i18n/utils';
import { PluginStatusEnum } from '../../../../plugin/type';

/** @deprecated Retained for existing workflow compatibility; hidden from new-node templates. */
export const AiQueryExtension: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.queryExtension,
templateType: FlowNodeTemplateTypeEnum.other,
flowNodeType: FlowNodeTypeEnum.queryExtension,
status: PluginStatusEnum.SoonOffline,
showSourceHandle: true,
showTargetHandle: true,
avatar: 'core/workflow/template/queryExtension',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const ClassifyQuestionModule: FlowNodeTemplateType = {
name: i18nT('workflow:question_classification'),
intro: i18nT('workflow:intro_question_classification'),
showStatus: true,
isTool: true,
version: '4.9.2',
courseUrl: '/guide/build/workflow/nodes/question_classify',
inputs: [
Expand All @@ -38,10 +39,18 @@ export const ClassifyQuestionModule: FlowNodeTemplateType = {
...Input_Template_System_Prompt,
label: i18nT('common:core.module.input.label.Background'),
description: i18nT('common:core.module.input.description.Background'),
placeholder: i18nT('common:core.module.input.placeholder.Classify background')
placeholder: i18nT('common:core.module.input.placeholder.Classify background'),
toolDescription: i18nT('common:core.module.input.label.Background'),
isToolParam: true,
defaultAgentGenerated: true
},
Input_Template_History,
Input_Template_UserChatInput,
{
...Input_Template_History,
toolDescription: i18nT('common:core.module.input.label.chat history'),
isToolParam: true,
defaultAgentGenerated: true
},
{ ...Input_Template_UserChatInput, isToolParam: true, defaultAgentGenerated: true },
{
key: NodeInputKeyEnum.agents,
renderTypeList: [FlowNodeInputTypeEnum.custom],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,17 @@ export const CustomFeedbackNode: FlowNodeTemplateType = {
colorSchema: 'yellowGreen',
name: i18nT('workflow:custom_feedback'),
intro: i18nT('workflow:intro_custom_feedback'),
isTool: true,
courseUrl: '/guide/build/workflow/nodes/custom_feedback',
inputs: [
{
key: NodeInputKeyEnum.textareaInput,
renderTypeList: [FlowNodeInputTypeEnum.textarea, FlowNodeInputTypeEnum.reference],
valueType: WorkflowIOValueTypeEnum.string,
required: true,
label: i18nT('workflow:feedback_text')
label: i18nT('workflow:feedback_text'),
toolDescription: i18nT('workflow:feedback_text'),
isToolParam: true
}
],
outputs: []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
NodeOutputKeyEnum,
FlowNodeTemplateTypeEnum
} from '../../constants';
import { createHideInContext } from '../context';
import { getNanoid } from '../../../../common/string/tools';
import { type FlowNodeInputItemType } from '../../type/io';
import { i18nT } from '../../../../common/i18n/utils';
Expand Down Expand Up @@ -44,6 +45,9 @@ export const DatasetConcatModule: FlowNodeTemplateType = {
intro: i18nT('workflow:intro_knowledge_base_search_merge'),

showStatus: false,
isShowInContext: createHideInContext([
{ sourceType: FlowNodeTypeEnum.toolCall, handleId: NodeOutputKeyEnum.selectedTools }
]),
courseUrl: '/guide/build/workflow/nodes/knowledge_base_search_merge',
inputs: [
{
Expand Down
Loading
Loading