mirror of
https://github.com/labring/FastGPT.git
synced 2025-10-13 22:56:28 +00:00
plan params
This commit is contained in:
@@ -170,7 +170,9 @@ export enum NodeInputKeyEnum {
|
||||
|
||||
// agent
|
||||
subApps = 'subApps',
|
||||
planAgentConfig = 'planAgentConfig',
|
||||
isAskAgent = 'isAskAgent',
|
||||
isPlanAgent = 'isPlanAgent',
|
||||
isConfirmPlanAgent = 'isConfirmPlanAgent',
|
||||
|
||||
// dataset
|
||||
datasetSelectList = 'datasets',
|
||||
|
@@ -1,40 +1,5 @@
|
||||
import { SubAppIds } from './sub/constants';
|
||||
|
||||
export const getMasterAgentDefaultPrompt = () => {
|
||||
return `## 工作流程
|
||||
你需要严格按照 [${SubAppIds.plan}] 提供的步骤逐步完成执行任务。`;
|
||||
// return `## 角色定位
|
||||
// 你是一个高级任务调度器(Task Orchestrator),负责分析用户需求、拆解并分派子任务、整合多Agent成果,确保最终产出具备高度专业性、系统性与洞见力。
|
||||
|
||||
// ## 核心职责
|
||||
// ### 粒度控制
|
||||
// - **原子任务原则**:每个子任务必须是单一、明确、可独立完成的
|
||||
// - **专业匹配原则**:根据任务属性,将子任务分配给最合适的专业Agent
|
||||
// - **避免任务过载**:不得将多个复杂任务打包给单个Agent
|
||||
|
||||
// ### 过程管理
|
||||
// - 制定清晰的执行顺序,保证任务逻辑链条完整
|
||||
// - 动态监控子任务进展,必要时调整分工或策略
|
||||
// - 保持信息透明,确保上下游Agent输出可直接衔接
|
||||
|
||||
// ### 结果验证
|
||||
// - 校验每个子任务是否达成预期目标
|
||||
// - 严格检查输出的准确性、完整性和格式规范
|
||||
// - 确保所有结果的一致性、逻辑连贯性和互补性
|
||||
|
||||
// ## 最终产出标准
|
||||
// 1. **专业性**:输出必须具备专家级深度,避免表面化结论
|
||||
// 2. **系统性**:结果需结构化呈现,覆盖任务的各个核心维度
|
||||
// 3. **多视角**:从战略、执行、风险、机遇等不同角度进行分析
|
||||
// 4. **洞见力**:在满足需求的基础上,提出更高层次的见解、趋势判断或改进建议
|
||||
// 5. **可操作性**:输出不仅是分析,还应包含可执行的步骤、优先级和资源需求
|
||||
// 6. **用户导向**:确保最终成果切合用户需求,且超出用户的预期价值
|
||||
|
||||
// ## 关键原则
|
||||
// 1. **分而治之**:复杂任务必须拆解,禁止直接交由单个Agent
|
||||
// 2. **专业对口**:匹配最合适的Agent来执行对应任务
|
||||
// 3. **循序渐进**:按照逻辑顺序推进,确保结果可堆叠与传递
|
||||
// 4. **结果导向**:始终聚焦最终输出的质量与用户满意度
|
||||
// 5. **灵活调整**:在任务推进中,根据结果反馈动态优化策略
|
||||
// 6. **高标准产出**:最终结果必须是专业、详细、系统且具备洞见的完整方案`;
|
||||
return ``;
|
||||
};
|
||||
|
@@ -47,6 +47,7 @@ import { dispatchFileRead } from './sub/file';
|
||||
import { dispatchApp, dispatchPlugin } from './sub/app';
|
||||
import { getSubAppsPrompt } from './sub/plan/prompt';
|
||||
import { parseAgentSystemPrompt } from './utils';
|
||||
import type { AgentPlanType } from './sub/plan/type';
|
||||
|
||||
export type DispatchAgentModuleProps = ModuleDispatchProps<{
|
||||
[NodeInputKeyEnum.history]?: ChatItemType[];
|
||||
@@ -59,7 +60,9 @@ export type DispatchAgentModuleProps = ModuleDispatchProps<{
|
||||
[NodeInputKeyEnum.aiChatTopP]?: number;
|
||||
|
||||
[NodeInputKeyEnum.subApps]?: FlowNodeTemplateType[];
|
||||
[NodeInputKeyEnum.planAgentConfig]?: Record<string, any>;
|
||||
[NodeInputKeyEnum.isAskAgent]?: boolean;
|
||||
[NodeInputKeyEnum.isPlanAgent]?: boolean;
|
||||
[NodeInputKeyEnum.isConfirmPlanAgent]?: boolean;
|
||||
}>;
|
||||
|
||||
type Response = DispatchNodeResultType<{
|
||||
@@ -94,42 +97,38 @@ export const dispatchRunAgent = async (props: DispatchAgentModuleProps): Promise
|
||||
temperature,
|
||||
aiChatTopP,
|
||||
subApps = [],
|
||||
planAgentConfig
|
||||
isPlanAgent = false,
|
||||
isAskAgent = false,
|
||||
isConfirmPlanAgent = false
|
||||
}
|
||||
} = props;
|
||||
const agentModel = getLLMModel(model);
|
||||
const chatHistories = getHistories(history, histories);
|
||||
|
||||
const masterMessagesKey = `masterMessages-${nodeId}`;
|
||||
const planMessagesKey = `planMessages-${nodeId}`;
|
||||
const planToolCallMessagesKey = `planToolCallMessages-${nodeId}`;
|
||||
const contextKey = `context-${nodeId}`;
|
||||
const plansKey = `plans-${nodeId}`;
|
||||
|
||||
// Get history messages
|
||||
let { masterHistoryMessages, planHistoryMessages, planToolCallMessages } = (() => {
|
||||
let { planHistoryMessages, contextMap, plans } = (() => {
|
||||
const lastHistory = chatHistories[chatHistories.length - 1];
|
||||
if (lastHistory && lastHistory.obj === ChatRoleEnum.AI) {
|
||||
return {
|
||||
masterHistoryMessages: (lastHistory.memories?.[masterMessagesKey] ||
|
||||
[]) as ChatCompletionMessageParam[],
|
||||
planHistoryMessages: (lastHistory.memories?.[planMessagesKey] ||
|
||||
[]) as ChatCompletionMessageParam[],
|
||||
planToolCallMessages: (lastHistory.memories?.[planToolCallMessagesKey] ||
|
||||
[]) as ChatCompletionMessageParam[]
|
||||
contextMap: (lastHistory.memories?.[contextKey] || []) as ChatCompletionMessageParam[],
|
||||
plans: (lastHistory.memories?.[plansKey] || []) as AgentPlanType
|
||||
};
|
||||
}
|
||||
return {
|
||||
masterHistoryMessages: [],
|
||||
planHistoryMessages: [],
|
||||
planToolCallMessages: []
|
||||
contextMap: {}
|
||||
};
|
||||
})();
|
||||
|
||||
// Check interactive entry
|
||||
props.node.isEntry = false;
|
||||
|
||||
// 交互模式进来的话,这个值才是交互输入的值
|
||||
const interactiveInput = lastInteractive ? chatValue2RuntimePrompt(query).text : '';
|
||||
|
||||
try {
|
||||
// Get files
|
||||
const fileUrlInput = inputs.find((item) => item.key === NodeInputKeyEnum.fileUrlList);
|
||||
@@ -181,6 +180,9 @@ export const dispatchRunAgent = async (props: DispatchAgentModuleProps): Promise
|
||||
};
|
||||
};
|
||||
|
||||
// 交互模式进来的话,这个值才是交互输入的值
|
||||
const interactiveInput = lastInteractive ? chatValue2RuntimePrompt(query).text : '';
|
||||
|
||||
/* ===== Plan Agent ===== */
|
||||
let planMessages: ChatCompletionMessageParam[] = [];
|
||||
/*
|
||||
@@ -195,8 +197,13 @@ export const dispatchRunAgent = async (props: DispatchAgentModuleProps): Promise
|
||||
*/
|
||||
if (
|
||||
// 如果是 userSelect 和 userInput,说明不是 plan 触发的交互。
|
||||
lastInteractive?.type !== 'userSelect' &&
|
||||
lastInteractive?.type !== 'userInput'
|
||||
lastInteractive?.type &&
|
||||
[
|
||||
'agentPlanAskQuery',
|
||||
'agentPlanAskUserForm',
|
||||
'agentPlanAskUserSelect',
|
||||
'agentPlanCheck'
|
||||
].includes(lastInteractive?.type)
|
||||
) {
|
||||
// Confirm 操作
|
||||
if (lastInteractive?.type === 'agentPlanCheck' && interactiveInput === ConfirmPlanAgentText) {
|
||||
@@ -242,7 +249,7 @@ export const dispatchRunAgent = async (props: DispatchAgentModuleProps): Promise
|
||||
});
|
||||
|
||||
planMessages = completeMessages;
|
||||
planToolCallMessages = newPlanToolCallMessages;
|
||||
plans = planList;
|
||||
|
||||
// TODO: usage 合并
|
||||
// Sub agent plan 不会有交互响应。Top agent plan 肯定会有。
|
||||
@@ -251,7 +258,7 @@ export const dispatchRunAgent = async (props: DispatchAgentModuleProps): Promise
|
||||
[DispatchNodeResponseKeyEnum.answerText]: `${tmpText}${text}`,
|
||||
[DispatchNodeResponseKeyEnum.memories]: {
|
||||
[planMessagesKey]: filterMemoryMessages(planMessages),
|
||||
[planToolCallMessagesKey]: planToolCallMessages
|
||||
[plansKey]: plans
|
||||
},
|
||||
[DispatchNodeResponseKeyEnum.interactive]: interactiveResponse
|
||||
};
|
||||
@@ -259,7 +266,7 @@ export const dispatchRunAgent = async (props: DispatchAgentModuleProps): Promise
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== Master agent ===== */
|
||||
/* ===== Master agent, 逐步执行 plan ===== */
|
||||
|
||||
// Get master request messages
|
||||
const systemMessages = chats2GPTMessages({
|
||||
@@ -267,10 +274,6 @@ export const dispatchRunAgent = async (props: DispatchAgentModuleProps): Promise
|
||||
reserveId: false
|
||||
});
|
||||
const historyMessages: ChatCompletionMessageParam[] = (() => {
|
||||
if (masterHistoryMessages && masterHistoryMessages.length > 0) {
|
||||
return masterHistoryMessages;
|
||||
}
|
||||
|
||||
return [];
|
||||
})();
|
||||
|
||||
@@ -286,12 +289,7 @@ export const dispatchRunAgent = async (props: DispatchAgentModuleProps): Promise
|
||||
],
|
||||
reserveId: false
|
||||
});
|
||||
const requestMessages = [
|
||||
...systemMessages,
|
||||
...historyMessages,
|
||||
...userMessages,
|
||||
...planToolCallMessages
|
||||
];
|
||||
const requestMessages = [...historyMessages, ...userMessages];
|
||||
console.log(JSON.stringify({ requestMessages }, null, 2));
|
||||
|
||||
const dispatchFlowResponse: ChatHistoryItemResType[] = [];
|
||||
|
@@ -4,7 +4,10 @@ import { filterSystemVariables } from '../../../../../../../core/workflow/dispat
|
||||
import { authAppByTmbId } from '../../../../../../../support/permission/app/auth';
|
||||
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||
import { getAppVersionById } from '../../../../../../../core/app/version/controller';
|
||||
import { getRunningUserInfoByTmbId } from '../../../../../../../support/user/team/utils';
|
||||
import {
|
||||
getRunningUserInfoByTmbId,
|
||||
getUserChatInfo
|
||||
} from '../../../../../../../support/user/team/utils';
|
||||
import { runWorkflow } from '../../../../../../../core/workflow/dispatch';
|
||||
import {
|
||||
getWorkflowEntryNodeIds,
|
||||
@@ -13,7 +16,6 @@ import {
|
||||
storeNodes2RuntimeNodes
|
||||
} from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
import { chatValue2RuntimePrompt } from '@fastgpt/global/core/chat/adapt';
|
||||
import { getUserChatInfoAndAuthTeamPoints } from '../../../../../../../support/permission/auth/team';
|
||||
import { getChildAppRuntimeById } from '../../../../../../app/plugin/controller';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { getPluginRunUserQuery } from '@fastgpt/global/core/workflow/utils';
|
||||
@@ -61,7 +63,7 @@ export const dispatchApp = async (props: Props): Promise<DispatchSubAppResponse>
|
||||
|
||||
// Rewrite children app variables
|
||||
const systemVariables = filterSystemVariables(variables);
|
||||
const { externalProvider } = await getUserChatInfoAndAuthTeamPoints(appData.tmbId);
|
||||
const { externalProvider } = await getUserChatInfo(appData.tmbId);
|
||||
const childrenRunVariables = {
|
||||
...systemVariables,
|
||||
histories: [],
|
||||
@@ -79,6 +81,7 @@ export const dispatchApp = async (props: Props): Promise<DispatchSubAppResponse>
|
||||
...props,
|
||||
runningAppInfo: {
|
||||
id: String(appData._id),
|
||||
name: appData.name,
|
||||
teamId: String(appData.teamId),
|
||||
tmbId: String(appData.tmbId),
|
||||
isChildApp: true
|
||||
@@ -154,7 +157,7 @@ export const dispatchPlugin = async (props: Props): Promise<DispatchSubAppRespon
|
||||
};
|
||||
});
|
||||
|
||||
const { externalProvider } = await getUserChatInfoAndAuthTeamPoints(tmbId);
|
||||
const { externalProvider } = await getUserChatInfo(tmbId);
|
||||
const runtimeVariables = {
|
||||
...filterSystemVariables(props.variables),
|
||||
appId: String(plugin.id),
|
||||
@@ -167,6 +170,7 @@ export const dispatchPlugin = async (props: Props): Promise<DispatchSubAppRespon
|
||||
runningAppInfo: {
|
||||
id: String(plugin.id),
|
||||
// 如果系统插件有 teamId 和 tmbId,则使用系统插件的 teamId 和 tmbId(管理员指定了插件作为系统插件)
|
||||
name: plugin.name,
|
||||
teamId: plugin.teamId || runningAppInfo.teamId,
|
||||
tmbId: plugin.tmbId || runningAppInfo.tmbId,
|
||||
isChildApp: true
|
||||
|
@@ -16,10 +16,10 @@ export const getSubAppsPrompt = ({
|
||||
.map((item) => {
|
||||
const info = getSubAppInfo(item.function.name);
|
||||
if (!info) return '';
|
||||
return `@${info.name}(${info.toolDescription})`;
|
||||
return `- [@${info.name}]: ${info.toolDescription};`;
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join('; ');
|
||||
.join('\n');
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -28,87 +28,121 @@ export const getSubAppsPrompt = ({
|
||||
*/
|
||||
export const getPlanAgentPrompt = (subAppsPrompt: string, systemPrompt?: string) => {
|
||||
return `<role>
|
||||
你是一个专业的项目规划助手,擅长将复杂任务分解为结构化的执行计划。
|
||||
你是一个智能任务规划助手,能够根据任务执行的实时反馈动态调整和生成执行计划。你采用渐进式规划策略,基于当前已知信息生成适应性步骤,而非试图预测所有可能路径。
|
||||
</role>
|
||||
|
||||
${
|
||||
systemPrompt
|
||||
? `<user_required>
|
||||
${systemPrompt}
|
||||
</user_required>`
|
||||
: ''
|
||||
}
|
||||
|
||||
|
||||
<planning_philosophy>
|
||||
核心原则:
|
||||
1. **渐进式规划**:只规划到下一个关键信息点或决策点
|
||||
2. **适应性标记**:通过 'replan' 标识需要基于执行结果调整的任务
|
||||
3. **最小化假设**:不对未知信息做过多预设,而是通过执行步骤获取
|
||||
</planning_philosophy>
|
||||
<toolset>
|
||||
${subAppsPrompt}
|
||||
</toolset>
|
||||
<process>
|
||||
- 解析用户输入,提取核心目标、关键要素、约束与本地化偏好。
|
||||
- 在缺少完成任务的关键信息时,使用 [${SubAppIds.ask}] 工具来询问用户(如:未指定目的地、预算、时间等必要细节)
|
||||
- 你还可以使用这些工具来设计本轮执行计划: """${subAppsPrompt}"""。注意,你只有这些工具可以进行调用。
|
||||
${systemPrompt ? '- 制定本轮计划时,严格参考 <user_required></user_required> 中的内容进行设计,设计的计划不偏离<user_required></user_required>。' : ''}
|
||||
- 输出语言风格本地化(根据用户输入语言进行术语与语序调整)。
|
||||
- 严格按照 JSON Schema 生成完整计划,不得输出多余内容。
|
||||
- 解析用户输入,识别任务模式(线性/探索/并行/迭代)
|
||||
- 提取核心目标、关键要素、约束与本地化偏好
|
||||
- 如果用户提供了前置规划信息,优先基于用户的步骤安排和偏好来生成计划
|
||||
- 在缺少前置的关键信息或用户的问题不明确时,使用 [interactivePromptTool] 工具来询问用户获取必要信息
|
||||
- 输出语言风格本地化(根据用户输入语言进行术语与语序调整)。
|
||||
- 如果用户有自己输入的plan,应该按照他的plan流程来规划,但是在需要决策的地方进行中断,并把 replan 字段设置为需要决策的步骤id
|
||||
- 严格按照 JSON Schema 生成完整计划,不得输出多余内容。
|
||||
</process>
|
||||
|
||||
<requirements>
|
||||
- 必须严格输出 JSON,不能包含代码块标记(如 \`\`\`)、注释或额外说明文字。
|
||||
- 输出结构必须符合以下 JSON Schema:
|
||||
\`\`\`json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"task": {
|
||||
"type": "string",
|
||||
"description": "任务主题, 准确覆盖本次所有执行步骤的核心内容和维度"
|
||||
},
|
||||
"steps": {
|
||||
"type": "array",
|
||||
"description": "完成任务的步骤列表",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "步骤的唯一标识"
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"description": "步骤标题"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "步骤的具体描述, 可以使用@符号声明需要用到的工具。"
|
||||
},
|
||||
},
|
||||
"required": ["id", "title", "description"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["title", "description", "steps"]
|
||||
}
|
||||
\`\`\`
|
||||
</requirements>
|
||||
|
||||
<guardrails>
|
||||
- 不生成违法、不道德或有害内容;敏感主题输出合规替代方案。
|
||||
- 避免过于具体的时间/预算承诺与无法验证的保证。
|
||||
- 保持中立、客观;必要时指出风险与依赖。
|
||||
</guardrails>
|
||||
|
||||
<example>
|
||||
- 必须严格输出 JSON
|
||||
- 输出结构必须符合以下 JSON Schema:
|
||||
\`\`\`json
|
||||
{
|
||||
"task": "[主题] 深度调研计划",
|
||||
"steps": [
|
||||
{
|
||||
"id": "step1",
|
||||
"title": "[步骤名称]",
|
||||
"description": "[步骤描述] @网络搜索"
|
||||
},
|
||||
{
|
||||
"id": "step2",
|
||||
"title": "[步骤名称]",
|
||||
"description": "[步骤描述] @webhook机器人"
|
||||
}
|
||||
]
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"task": {
|
||||
"type": "string",
|
||||
"description": "任务主题, 准确覆盖本次所有执行步骤的核心内容和维度"
|
||||
},
|
||||
"steps": {
|
||||
"type": "array",
|
||||
"description": "完成任务的步骤列表",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "步骤的唯一标识"
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"description": "步骤标题"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "步骤的具体描述, 可以使用@符号声明需要用到的工具。"
|
||||
},
|
||||
"depends_on": {
|
||||
"type": "object",
|
||||
"description": "该步骤依赖的前置步骤的id,比如["step1","step2"]"
|
||||
}
|
||||
},
|
||||
"required": ["id", "title", "description"]
|
||||
}
|
||||
},
|
||||
"replan": {
|
||||
"type": "array",
|
||||
"description": "需要二次规划时,列出依赖的步骤。如果为空数组则表示不需要二次规划",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": []
|
||||
}
|
||||
},
|
||||
"required": ["task", "steps"]
|
||||
}
|
||||
</example>`;
|
||||
\`\`\`
|
||||
</requirements>
|
||||
<guardrails>
|
||||
- 不生成违法、不道德或有害内容;敏感主题输出合规替代方案。
|
||||
- 避免过于具体的时间/预算承诺与无法验证的保证。
|
||||
- 保持中立、客观;必要时指出风险与依赖。
|
||||
- 只输出[interactivePromptTool]的工具调用或 JSON 计划内容, 不能输出其他内容。
|
||||
</guardrails>
|
||||
<best-practices>
|
||||
### 步骤指导
|
||||
#### 颗粒度把控
|
||||
|
||||
- **保持平衡**:步骤既不过于宏观(难以执行),也不过于细碎(失去灵活性)
|
||||
- **可执行性**:每个步骤应该是一个独立可执行的任务单元
|
||||
- **结果明确**:每个步骤应产生明确的输出,为后续决策提供依据
|
||||
|
||||
#### 步骤数量的自然边界
|
||||
|
||||
- **认知负载**:单次规划保持在用户可理解的复杂度内
|
||||
- **执行周期**:考虑合理的执行和反馈周期
|
||||
- **依赖关系**:强依赖的步骤可以规划在一起,弱依赖的分开
|
||||
- **不确定性**:不确定性越高,初始规划应该越保守
|
||||
|
||||
### description 字段最佳实践
|
||||
|
||||
- **明确工具和目标**:"使用 @research_agent 搜索X的最新进展,重点关注Y方面"
|
||||
- **标注关键信息点**:"了解A的特性,特别注意是否支持B功能(这将影响后续方案选择)"
|
||||
- **预示可能分支**:"调研市场反馈,如果正面则深入了解优势,如果负面则分析原因"
|
||||
- **说明探索重点**:"搜索相关案例,关注:1)实施成本 2)成功率 3)常见问题"
|
||||
|
||||
### requires_replan 判定规则
|
||||
|
||||
设置为 **true** 当:
|
||||
- 存在"如果...则..."的条件逻辑
|
||||
- 下一步行动依赖当前步骤的具体发现
|
||||
- 任务需要迭代执行直到满足条件
|
||||
- 初始信息不足以规划完整路径
|
||||
- 任务复杂度高,需要分阶段执行
|
||||
|
||||
设置为 **false** 当:
|
||||
- 所有步骤可以预先确定
|
||||
- 任务简单直接
|
||||
- 步骤间是简单的顺序关系
|
||||
- 目标明确且路径唯一
|
||||
### 元计划规范
|
||||
- 你生成的计划必须是元计划 (Meta-plan),即关于“如何制定计划”的计划,而不是直接给用户的最终执行方案
|
||||
- 当用户请求制定一份计划时,你需要先生成一份 制定计划的计划,用于指导如何收集信息、明确目标、分析需求和设计步骤
|
||||
</best-practices>
|
||||
`;
|
||||
};
|
||||
|
@@ -2,8 +2,11 @@ export type AgentPlanStepType = {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string;
|
||||
depends_on?: string[];
|
||||
response?: string;
|
||||
};
|
||||
export type AgentPlanType = {
|
||||
task: string;
|
||||
steps: AgentPlanStepType[];
|
||||
replan?: string[];
|
||||
};
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import { Box, Flex } from '@chakra-ui/react';
|
||||
import { Box, Button, Flex } from '@chakra-ui/react';
|
||||
import { Controller, useForm, type UseFormHandleSubmit } from 'react-hook-form';
|
||||
import Markdown from '@/components/Markdown';
|
||||
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
|
||||
|
Reference in New Issue
Block a user