mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-22 04:06:18 +00:00
Test version (#4792)
* plugin node version select (#4760) * plugin node version select * type * fix * fix * perf: version list * fix node version (#4787) * change my select * fix-ui * fix test * add test * fix * remove invalid version field * filter deprecated field * fix: claude tool call * fix: test --------- Co-authored-by: heheer <heheer@sealos.io>
This commit is contained in:
@@ -331,7 +331,7 @@ export const getQuotePrompt = (version?: string, role: 'user' | 'system' = 'user
|
||||
};
|
||||
|
||||
// Document quote prompt
|
||||
export const getDocumentQuotePrompt = (version: string) => {
|
||||
export const getDocumentQuotePrompt = (version?: string) => {
|
||||
const promptMap = {
|
||||
['4.9.2']: `将 <FilesContent></FilesContent> 中的内容作为本次对话的参考:
|
||||
<FilesContent>
|
||||
|
@@ -1,4 +1,5 @@
|
||||
export const getPromptByVersion = (version?: string, promptMap: Record<string, string> = {}) => {
|
||||
// 版本号大的在前面
|
||||
const versions = Object.keys(promptMap).sort((a, b) => {
|
||||
const [majorA, minorA, patchA] = a.split('.').map(Number);
|
||||
const [majorB, minorB, patchB] = b.split('.').map(Number);
|
||||
@@ -15,5 +16,5 @@ export const getPromptByVersion = (version?: string, promptMap: Record<string, s
|
||||
if (version in promptMap) {
|
||||
return promptMap[version];
|
||||
}
|
||||
return promptMap[versions[versions.length - 1]];
|
||||
return promptMap[versions[0]];
|
||||
};
|
||||
|
@@ -218,7 +218,6 @@ export const FlowValueTypeMap: Record<
|
||||
};
|
||||
|
||||
export const EDGE_TYPE = 'default';
|
||||
export const defaultNodeVersion = '481';
|
||||
|
||||
export const chatHistoryValueDesc = `{
|
||||
obj: System | Human | AI;
|
||||
@@ -236,3 +235,10 @@ export const datasetQuoteValueDesc = `{
|
||||
export const datasetSelectValueDesc = `{
|
||||
datasetId: string;
|
||||
}[]`;
|
||||
|
||||
export const AppNodeFlowNodeTypeMap: Record<any, boolean> = {
|
||||
[FlowNodeTypeEnum.pluginModule]: true,
|
||||
[FlowNodeTypeEnum.appModule]: true,
|
||||
[FlowNodeTypeEnum.tool]: true,
|
||||
[FlowNodeTypeEnum.toolSet]: true
|
||||
};
|
||||
|
@@ -101,7 +101,7 @@ export type RuntimeNodeItemType = {
|
||||
outputs: FlowNodeOutputItemType[];
|
||||
|
||||
pluginId?: string; // workflow id / plugin id
|
||||
version: string;
|
||||
version?: string;
|
||||
};
|
||||
|
||||
export type RuntimeEdgeItemType = StoreEdgeItemType & {
|
||||
|
@@ -25,7 +25,6 @@ export const RunAppModule: FlowNodeTemplateType = {
|
||||
name: i18nT('workflow:application_call'),
|
||||
intro: i18nT('workflow:select_another_application_to_call'),
|
||||
showStatus: true,
|
||||
version: '481',
|
||||
isTool: true,
|
||||
inputs: [
|
||||
{
|
||||
|
@@ -19,7 +19,6 @@ import {
|
||||
Input_Template_UserChatInput,
|
||||
Input_Template_File_Link
|
||||
} from '../../input';
|
||||
import { chatNodeSystemPromptTip, systemPromptTip } from '../../tip';
|
||||
import { getHandleConfig } from '../../utils';
|
||||
import { i18nT } from '../../../../../../web/i18n/utils';
|
||||
|
||||
@@ -121,12 +120,7 @@ export const AiChatModule: FlowNodeTemplateType = {
|
||||
valueType: WorkflowIOValueTypeEnum.string
|
||||
},
|
||||
// settings modal ---
|
||||
{
|
||||
...Input_Template_System_Prompt,
|
||||
label: i18nT('common:core.ai.Prompt'),
|
||||
description: systemPromptTip,
|
||||
placeholder: chatNodeSystemPromptTip
|
||||
},
|
||||
Input_Template_System_Prompt,
|
||||
Input_Template_History,
|
||||
Input_Template_Dataset_Quote,
|
||||
Input_Template_File_Link,
|
||||
|
@@ -18,7 +18,6 @@ export const AssignedAnswerModule: FlowNodeTemplateType = {
|
||||
name: i18nT('workflow:assigned_reply'),
|
||||
intro: i18nT('workflow:intro_assigned_reply'),
|
||||
courseUrl: '/docs/guide/dashboard/workflow/reply/',
|
||||
version: '481',
|
||||
isTool: true,
|
||||
inputs: [
|
||||
{
|
||||
|
@@ -18,7 +18,6 @@ export const CustomFeedbackNode: FlowNodeTemplateType = {
|
||||
name: i18nT('workflow:custom_feedback'),
|
||||
intro: i18nT('workflow:intro_custom_feedback'),
|
||||
courseUrl: '/docs/guide/dashboard/workflow/custom_feedback/',
|
||||
version: '486',
|
||||
inputs: [
|
||||
{
|
||||
key: NodeInputKeyEnum.textareaInput,
|
||||
|
@@ -42,7 +42,6 @@ export const DatasetConcatModule: FlowNodeTemplateType = {
|
||||
intro: i18nT('workflow:intro_knowledge_base_search_merge'),
|
||||
|
||||
showStatus: false,
|
||||
version: '486',
|
||||
courseUrl: '/docs/guide/dashboard/workflow/knowledge_base_search_merge/',
|
||||
inputs: [
|
||||
{
|
||||
|
@@ -28,7 +28,6 @@ export const HttpNode468: FlowNodeTemplateType = {
|
||||
showStatus: true,
|
||||
isTool: true,
|
||||
courseUrl: '/docs/guide/dashboard/workflow/http/',
|
||||
version: '481',
|
||||
inputs: [
|
||||
{
|
||||
...Input_Template_DynamicInput,
|
||||
|
@@ -24,7 +24,6 @@ export const IfElseNode: FlowNodeTemplateType = {
|
||||
intro: i18nT('workflow:execute_different_branches_based_on_conditions'),
|
||||
showStatus: true,
|
||||
courseUrl: '/docs/guide/dashboard/workflow/tfswitch/',
|
||||
version: '481',
|
||||
inputs: [
|
||||
{
|
||||
key: NodeInputKeyEnum.ifElseList,
|
||||
|
@@ -23,7 +23,6 @@ export const FormInputNode: FlowNodeTemplateType = {
|
||||
name: i18nT('app:workflow.form_input'),
|
||||
intro: i18nT(`app:workflow.form_input_tip`),
|
||||
isTool: true,
|
||||
version: '4811',
|
||||
inputs: [
|
||||
{
|
||||
key: NodeInputKeyEnum.description,
|
||||
|
@@ -24,7 +24,6 @@ export const UserSelectNode: FlowNodeTemplateType = {
|
||||
name: i18nT('app:workflow.user_select'),
|
||||
intro: i18nT(`app:workflow.user_select_tip`),
|
||||
isTool: true,
|
||||
version: '489',
|
||||
courseUrl: '/docs/guide/dashboard/workflow/user-selection/',
|
||||
inputs: [
|
||||
{
|
||||
|
@@ -33,7 +33,6 @@ export const LafModule: FlowNodeTemplateType = {
|
||||
showStatus: true,
|
||||
isTool: true,
|
||||
courseUrl: '/docs/guide/dashboard/workflow/laf/',
|
||||
version: '481',
|
||||
inputs: [
|
||||
{
|
||||
...Input_Template_DynamicInput,
|
||||
|
@@ -29,7 +29,6 @@ export const LoopNode: FlowNodeTemplateType = {
|
||||
name: i18nT('workflow:loop'),
|
||||
intro: i18nT('workflow:intro_loop'),
|
||||
showStatus: true,
|
||||
version: '4811',
|
||||
courseUrl: '/docs/guide/dashboard/workflow/loop/',
|
||||
inputs: [
|
||||
{
|
||||
|
@@ -19,7 +19,6 @@ export const LoopEndNode: FlowNodeTemplateType = {
|
||||
avatar: 'core/workflow/template/loopEnd',
|
||||
name: i18nT('workflow:loop_end'),
|
||||
showStatus: false,
|
||||
version: '4811',
|
||||
inputs: [
|
||||
{
|
||||
key: NodeInputKeyEnum.loopEndInput,
|
||||
|
@@ -24,7 +24,6 @@ export const LoopStartNode: FlowNodeTemplateType = {
|
||||
unique: true,
|
||||
forbidDelete: true,
|
||||
showStatus: false,
|
||||
version: '4811',
|
||||
inputs: [
|
||||
{
|
||||
key: NodeInputKeyEnum.loopStartInput,
|
||||
|
@@ -15,7 +15,6 @@ export const PluginConfigNode: FlowNodeTemplateType = {
|
||||
intro: '',
|
||||
unique: true,
|
||||
forbidDelete: true,
|
||||
version: '4811',
|
||||
inputs: [],
|
||||
outputs: []
|
||||
};
|
||||
|
@@ -16,7 +16,6 @@ export const PluginInputModule: FlowNodeTemplateType = {
|
||||
name: i18nT('workflow:plugin_input'),
|
||||
intro: i18nT('workflow:intro_plugin_input'),
|
||||
showStatus: false,
|
||||
version: '481',
|
||||
inputs: [],
|
||||
outputs: []
|
||||
};
|
||||
|
@@ -16,7 +16,6 @@ export const PluginOutputModule: FlowNodeTemplateType = {
|
||||
name: i18nT('workflow:template.plugin_output'),
|
||||
intro: i18nT('workflow:intro_custom_plugin_output'),
|
||||
showStatus: false,
|
||||
version: '481',
|
||||
inputs: [],
|
||||
outputs: []
|
||||
};
|
||||
|
@@ -13,7 +13,6 @@ export const RunAppNode: FlowNodeTemplateType = {
|
||||
name: '',
|
||||
showStatus: false,
|
||||
isTool: false,
|
||||
version: '481',
|
||||
inputs: [], // [{key:'pluginId'},...]
|
||||
outputs: []
|
||||
};
|
||||
|
@@ -13,7 +13,6 @@ export const RunPluginModule: FlowNodeTemplateType = {
|
||||
name: '',
|
||||
showStatus: false,
|
||||
isTool: true,
|
||||
version: '481',
|
||||
inputs: [], // [{key:'pluginId'},...]
|
||||
outputs: []
|
||||
};
|
||||
|
@@ -13,7 +13,6 @@ export const RunToolNode: FlowNodeTemplateType = {
|
||||
name: '',
|
||||
showStatus: false,
|
||||
isTool: true,
|
||||
version: '4.9.6',
|
||||
inputs: [],
|
||||
outputs: []
|
||||
};
|
||||
|
@@ -13,7 +13,6 @@ export const RunToolSetNode: FlowNodeTemplateType = {
|
||||
name: '',
|
||||
showStatus: false,
|
||||
isTool: true,
|
||||
version: '4.9.6',
|
||||
inputs: [],
|
||||
outputs: []
|
||||
};
|
||||
|
@@ -27,7 +27,6 @@ export const CodeNode: FlowNodeTemplateType = {
|
||||
intro: i18nT('workflow:execute_a_simple_script_code_usually_for_complex_data_processing'),
|
||||
showStatus: true,
|
||||
courseUrl: '/docs/guide/dashboard/workflow/sandbox/',
|
||||
version: '482',
|
||||
inputs: [
|
||||
{
|
||||
...Input_Template_DynamicInput,
|
||||
|
@@ -13,7 +13,6 @@ export const StopToolNode: FlowNodeTemplateType = {
|
||||
avatar: 'core/workflow/template/stopTool',
|
||||
name: i18nT('workflow:tool_call_termination'),
|
||||
intro: i18nT('workflow:intro_tool_call_termination'),
|
||||
version: '481',
|
||||
inputs: [],
|
||||
outputs: []
|
||||
};
|
||||
|
@@ -15,7 +15,6 @@ export const SystemConfigNode: FlowNodeTemplateType = {
|
||||
intro: '',
|
||||
unique: true,
|
||||
forbidDelete: true,
|
||||
version: '481',
|
||||
inputs: [],
|
||||
outputs: []
|
||||
};
|
||||
|
@@ -24,7 +24,6 @@ export const TextEditorNode: FlowNodeTemplateType = {
|
||||
name: i18nT('workflow:text_concatenation'),
|
||||
intro: i18nT('workflow:intro_text_concatenation'),
|
||||
courseUrl: '/docs/guide/dashboard/workflow/text_editor/',
|
||||
version: '4813',
|
||||
inputs: [
|
||||
{
|
||||
key: NodeInputKeyEnum.textareaInput,
|
||||
|
@@ -13,7 +13,6 @@ export const ToolParamsNode: FlowNodeTemplateType = {
|
||||
avatar: 'core/workflow/template/toolParams',
|
||||
name: i18nT('workflow:tool_custom_field'),
|
||||
intro: i18nT('workflow:intro_tool_params_config'),
|
||||
version: '4811',
|
||||
isTool: true,
|
||||
inputs: [],
|
||||
outputs: []
|
||||
|
@@ -19,7 +19,6 @@ export const VariableUpdateNode: FlowNodeTemplateType = {
|
||||
intro: i18nT('workflow:update_specified_node_output_or_global_variable'),
|
||||
showStatus: false,
|
||||
isTool: true,
|
||||
version: '481',
|
||||
courseUrl: '/docs/guide/dashboard/workflow/variable_update/',
|
||||
inputs: [
|
||||
{
|
||||
|
@@ -30,7 +30,6 @@ export const WorkflowStart: FlowNodeTemplateType = {
|
||||
intro: '',
|
||||
forbidDelete: true,
|
||||
unique: true,
|
||||
version: '481',
|
||||
inputs: [{ ...Input_Template_UserChatInput, toolDescription: i18nT('workflow:user_question') }],
|
||||
outputs: [
|
||||
{
|
||||
|
@@ -37,7 +37,10 @@ export type WorkflowTemplateType = {
|
||||
intro?: string;
|
||||
author?: string;
|
||||
courseUrl?: string;
|
||||
version: string;
|
||||
|
||||
version?: string;
|
||||
versionLabel?: string;
|
||||
isLatestVersion?: boolean;
|
||||
|
||||
showStatus?: boolean;
|
||||
weight?: number;
|
||||
|
4
packages/global/core/workflow/type/io.d.ts
vendored
4
packages/global/core/workflow/type/io.d.ts
vendored
@@ -63,6 +63,8 @@ export type FlowNodeInputItemType = InputComponentPropsType & {
|
||||
canSelectFile?: boolean;
|
||||
canSelectImg?: boolean;
|
||||
maxFiles?: number;
|
||||
|
||||
deprecated?: boolean;
|
||||
};
|
||||
|
||||
export type FlowNodeOutputItemType = {
|
||||
@@ -86,6 +88,8 @@ export type FlowNodeOutputItemType = {
|
||||
|
||||
// component params
|
||||
customFieldConfig?: CustomFieldConfigType;
|
||||
|
||||
deprecated?: boolean;
|
||||
};
|
||||
|
||||
export type ReferenceItemValueType = [string, string | undefined];
|
||||
|
7
packages/global/core/workflow/type/node.d.ts
vendored
7
packages/global/core/workflow/type/node.d.ts
vendored
@@ -34,7 +34,10 @@ export type FlowNodeCommonType = {
|
||||
name: string;
|
||||
intro?: string; // template list intro
|
||||
showStatus?: boolean; // chatting response step status
|
||||
version: string;
|
||||
|
||||
version?: string;
|
||||
versionLabel?: string; // Just ui show
|
||||
isLatestVersion?: boolean; // Just ui show
|
||||
|
||||
// data
|
||||
inputs: FlowNodeInputItemType[];
|
||||
@@ -48,7 +51,7 @@ export type FlowNodeCommonType = {
|
||||
};
|
||||
|
||||
export type PluginDataType = {
|
||||
version: string;
|
||||
version?: string;
|
||||
diagram?: string;
|
||||
userGuide?: string;
|
||||
courseUrl?: string;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { type FlowNodeTemplateType } from '@fastgpt/global/core/workflow/type/node.d';
|
||||
import { FlowNodeTypeEnum, defaultNodeVersion } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import {
|
||||
appData2FlowNodeIO,
|
||||
pluginData2FlowNodeIO,
|
||||
@@ -14,10 +14,16 @@ import { cloneDeep } from 'lodash';
|
||||
import { MongoApp } from '../schema';
|
||||
import { type SystemPluginTemplateItemType } from '@fastgpt/global/core/workflow/type';
|
||||
import { getSystemPluginTemplates } from '../../../../plugins/register';
|
||||
import { getAppLatestVersion, getAppVersionById } from '../version/controller';
|
||||
import {
|
||||
checkIsLatestVersion,
|
||||
getAppLatestVersion,
|
||||
getAppVersionById
|
||||
} from '../version/controller';
|
||||
import { type PluginRuntimeType } from '@fastgpt/global/core/plugin/type';
|
||||
import { MongoSystemPlugin } from './systemPluginSchema';
|
||||
import { PluginErrEnum } from '@fastgpt/global/common/error/code/plugin';
|
||||
import { MongoAppVersion } from '../version/schema';
|
||||
import { i18nT } from '../../../../web/i18n/utils';
|
||||
|
||||
/*
|
||||
plugin id rule:
|
||||
@@ -90,20 +96,34 @@ const getSystemPluginTemplateById = async (
|
||||
|
||||
/* Format plugin to workflow preview node data */
|
||||
export async function getChildAppPreviewNode({
|
||||
id
|
||||
appId,
|
||||
versionId
|
||||
}: {
|
||||
id: string;
|
||||
appId: string;
|
||||
versionId?: string;
|
||||
}): Promise<FlowNodeTemplateType> {
|
||||
const app: ChildAppType = await (async () => {
|
||||
const { source, pluginId } = await splitCombinePluginId(id);
|
||||
const { source, pluginId } = await splitCombinePluginId(appId);
|
||||
|
||||
if (source === PluginSourceEnum.personal) {
|
||||
const item = await MongoApp.findById(id).lean();
|
||||
const item = await MongoApp.findById(appId).lean();
|
||||
if (!item) return Promise.reject('plugin not found');
|
||||
|
||||
const version = await getAppLatestVersion(id, item);
|
||||
const version = await getAppVersionById({ appId, versionId, app: item });
|
||||
|
||||
if (!version.versionId) return Promise.reject('App version not found');
|
||||
if (!version.versionId) return Promise.reject(i18nT('common:app_not_version'));
|
||||
|
||||
const versionData = await MongoAppVersion.findById(
|
||||
version.versionId,
|
||||
'_id versionName appId time'
|
||||
).lean();
|
||||
|
||||
const isLatest = versionData
|
||||
? await checkIsLatestVersion({
|
||||
appId,
|
||||
versionId: versionData._id
|
||||
})
|
||||
: true;
|
||||
|
||||
return {
|
||||
id: String(item._id),
|
||||
@@ -118,7 +138,11 @@ export async function getChildAppPreviewNode({
|
||||
chatConfig: version.chatConfig
|
||||
},
|
||||
templateType: FlowNodeTemplateTypeEnum.teamApp,
|
||||
|
||||
version: version.versionId,
|
||||
versionLabel: versionData?.versionName || '',
|
||||
isLatestVersion: isLatest,
|
||||
|
||||
originCost: 0,
|
||||
currentCost: 0,
|
||||
hasTokenFee: false,
|
||||
@@ -175,7 +199,11 @@ export async function getChildAppPreviewNode({
|
||||
userGuide: app.userGuide,
|
||||
showStatus: app.showStatus,
|
||||
isTool: true,
|
||||
|
||||
version: app.version,
|
||||
versionLabel: app.versionLabel,
|
||||
isLatestVersion: app.isLatestVersion,
|
||||
|
||||
sourceHandle: isToolSet
|
||||
? getHandleConfig(false, false, false, false)
|
||||
: getHandleConfig(true, true, true, true),
|
||||
@@ -224,7 +252,7 @@ export async function getChildAppRuntimeById(
|
||||
templateType: FlowNodeTemplateTypeEnum.teamApp,
|
||||
|
||||
// 用不到
|
||||
version: item?.pluginData?.nodeVersion || defaultNodeVersion,
|
||||
version: item?.pluginData?.nodeVersion,
|
||||
originCost: 0,
|
||||
currentCost: 0,
|
||||
hasTokenFee: false,
|
||||
|
@@ -1,8 +1,14 @@
|
||||
import { MongoDataset } from '../dataset/schema';
|
||||
import { getEmbeddingModel } from '../ai/model';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import {
|
||||
AppNodeFlowNodeTypeMap,
|
||||
FlowNodeTypeEnum
|
||||
} from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import type { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node';
|
||||
import { MongoAppVersion } from './version/schema';
|
||||
import { checkIsLatestVersion } from './version/controller';
|
||||
import { Types } from '../../common/mongo';
|
||||
|
||||
export async function listAppDatasetDataByTeamIdAndDatasetIds({
|
||||
teamId,
|
||||
@@ -35,6 +41,45 @@ export async function rewriteAppWorkflowToDetail({
|
||||
}) {
|
||||
const datasetIdSet = new Set<string>();
|
||||
|
||||
// Add node(App Type) versionlabel and latest sign
|
||||
const appNodes = nodes.filter((node) => AppNodeFlowNodeTypeMap[node.flowNodeType]);
|
||||
const versionIds = appNodes
|
||||
.filter((node) => node.version && Types.ObjectId.isValid(node.version))
|
||||
.map((node) => node.version);
|
||||
if (versionIds.length > 0) {
|
||||
const versionDataList = await MongoAppVersion.find(
|
||||
{
|
||||
_id: { $in: versionIds }
|
||||
},
|
||||
'_id versionName appId time'
|
||||
).lean();
|
||||
|
||||
const versionMap: Record<string, any> = {};
|
||||
|
||||
const isLatestChecks = await Promise.all(
|
||||
versionDataList.map(async (version) => {
|
||||
const isLatest = await checkIsLatestVersion({
|
||||
appId: version.appId,
|
||||
versionId: version._id
|
||||
});
|
||||
|
||||
return { versionId: String(version._id), isLatest };
|
||||
})
|
||||
);
|
||||
const isLatestMap = new Map(isLatestChecks.map((item) => [item.versionId, item.isLatest]));
|
||||
versionDataList.forEach((version) => {
|
||||
versionMap[String(version._id)] = version;
|
||||
});
|
||||
appNodes.forEach((node) => {
|
||||
if (!node.version) return;
|
||||
const versionData = versionMap[String(node.version)];
|
||||
if (versionData) {
|
||||
node.versionLabel = versionData.versionName;
|
||||
node.isLatestVersion = isLatestMap.get(String(node.version)) || false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Get all dataset ids from nodes
|
||||
nodes.forEach((node) => {
|
||||
if (node.flowNodeType !== FlowNodeTypeEnum.datasetSearchNode) return;
|
||||
|
@@ -57,3 +57,22 @@ export const getAppVersionById = async ({
|
||||
// If the version does not exist, the latest version is returned
|
||||
return getAppLatestVersion(appId, app);
|
||||
};
|
||||
|
||||
export const checkIsLatestVersion = async ({
|
||||
appId,
|
||||
versionId
|
||||
}: {
|
||||
appId: string;
|
||||
versionId: string;
|
||||
}) => {
|
||||
const version = await MongoAppVersion.findOne(
|
||||
{
|
||||
appId,
|
||||
isPublish: true,
|
||||
_id: { $gt: versionId }
|
||||
},
|
||||
'_id'
|
||||
).lean();
|
||||
|
||||
return !version;
|
||||
};
|
||||
|
@@ -723,8 +723,8 @@ async function streamResponse({
|
||||
}
|
||||
// Parse tool calls
|
||||
if (responseChoice?.tool_calls?.length) {
|
||||
responseChoice.tool_calls.forEach((toolCall) => {
|
||||
const index = toolCall.index;
|
||||
responseChoice.tool_calls.forEach((toolCall, i) => {
|
||||
const index = toolCall.index ?? i;
|
||||
|
||||
// Call new tool
|
||||
if (toolCall.id || callingTool) {
|
||||
|
@@ -464,7 +464,7 @@ async function getChatMessages({
|
||||
aiChatQuoteRole: AiChatQuoteRoleType; // user: replace user prompt; system: replace system prompt
|
||||
datasetQuotePrompt?: string;
|
||||
datasetQuoteText: string;
|
||||
version: string;
|
||||
version?: string;
|
||||
|
||||
useDatasetQuote: boolean;
|
||||
histories: ChatItemType[];
|
||||
|
@@ -11,6 +11,7 @@ import type {
|
||||
SystemVariablesType
|
||||
} from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import type { RuntimeNodeItemType } from '@fastgpt/global/core/workflow/runtime/type.d';
|
||||
import type { FlowNodeOutputItemType } from '@fastgpt/global/core/workflow/type/io.d';
|
||||
import type {
|
||||
AIChatItemValueItemType,
|
||||
ChatHistoryItemResType,
|
||||
@@ -549,7 +550,7 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
||||
// Skip some special key
|
||||
if (
|
||||
[NodeInputKeyEnum.childrenNodeIdList, NodeInputKeyEnum.httpJsonBody].includes(
|
||||
input.key as any
|
||||
input.key as NodeInputKeyEnum
|
||||
)
|
||||
) {
|
||||
params[input.key] = input.value;
|
||||
|
@@ -15,7 +15,6 @@ import {
|
||||
useDisclosure,
|
||||
MenuButton,
|
||||
Box,
|
||||
css,
|
||||
Flex,
|
||||
Input
|
||||
} from '@chakra-ui/react';
|
||||
@@ -32,13 +31,16 @@ import Avatar from '../Avatar';
|
||||
* list: 列表数据
|
||||
* isLoading: 是否加载中
|
||||
* ScrollData: 分页滚动数据控制器 [useScrollPagination] 的返回值
|
||||
* customOnOpen: 自定义打开回调
|
||||
* customOnClose: 自定义关闭回调
|
||||
* */
|
||||
export type SelectProps<T = any> = Omit<ButtonProps, 'onChange'> & {
|
||||
value?: T;
|
||||
valueLabel?: string | React.ReactNode;
|
||||
placeholder?: string;
|
||||
isSearch?: boolean;
|
||||
list: {
|
||||
alias?: string;
|
||||
alias?: string | React.ReactNode;
|
||||
icon?: string;
|
||||
iconSize?: string;
|
||||
label: string | React.ReactNode;
|
||||
@@ -49,18 +51,36 @@ export type SelectProps<T = any> = Omit<ButtonProps, 'onChange'> & {
|
||||
isLoading?: boolean;
|
||||
onChange?: (val: T) => any | Promise<any>;
|
||||
ScrollData?: ReturnType<typeof useScrollPagination>['ScrollData'];
|
||||
customOnOpen?: () => void;
|
||||
customOnClose?: () => void;
|
||||
};
|
||||
|
||||
export const menuItemStyles: MenuItemProps = {
|
||||
borderRadius: 'sm',
|
||||
py: 2,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
_hover: {
|
||||
backgroundColor: 'myGray.100'
|
||||
},
|
||||
_notLast: {
|
||||
mb: 1
|
||||
}
|
||||
};
|
||||
|
||||
const MySelect = <T = any,>(
|
||||
{
|
||||
placeholder,
|
||||
value,
|
||||
valueLabel,
|
||||
isSearch = false,
|
||||
width = '100%',
|
||||
list = [],
|
||||
onChange,
|
||||
isLoading = false,
|
||||
ScrollData,
|
||||
customOnOpen,
|
||||
customOnClose,
|
||||
...props
|
||||
}: SelectProps<T>,
|
||||
ref: ForwardedRef<{
|
||||
@@ -72,21 +92,19 @@ const MySelect = <T = any,>(
|
||||
const SelectedItemRef = useRef<HTMLDivElement>(null);
|
||||
const SearchInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const menuItemStyles: MenuItemProps = {
|
||||
borderRadius: 'sm',
|
||||
py: 2,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
_hover: {
|
||||
backgroundColor: 'myGray.100'
|
||||
},
|
||||
_notLast: {
|
||||
mb: 1
|
||||
}
|
||||
};
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const { isOpen, onOpen: defaultOnOpen, onClose: defaultOnClose } = useDisclosure();
|
||||
const selectItem = useMemo(() => list.find((item) => item.value === value), [list, value]);
|
||||
|
||||
const onOpen = () => {
|
||||
defaultOnOpen();
|
||||
customOnOpen?.();
|
||||
};
|
||||
|
||||
const onClose = () => {
|
||||
defaultOnClose();
|
||||
customOnClose?.();
|
||||
};
|
||||
|
||||
const [search, setSearch] = useState('');
|
||||
const filterList = useMemo(() => {
|
||||
if (!isSearch || !search) {
|
||||
@@ -105,6 +123,7 @@ const MySelect = <T = any,>(
|
||||
}
|
||||
}));
|
||||
|
||||
// Auto scroll
|
||||
useEffect(() => {
|
||||
if (isOpen && MenuListRef.current && SelectedItemRef.current) {
|
||||
const menu = MenuListRef.current;
|
||||
@@ -117,7 +136,7 @@ const MySelect = <T = any,>(
|
||||
}
|
||||
}, [isSearch, isOpen]);
|
||||
|
||||
const { runAsync: onclickChange, loading } = useRequest2((val: T) => onChange?.(val));
|
||||
const { runAsync: onClickChange, loading } = useRequest2((val: T) => onChange?.(val));
|
||||
|
||||
const ListRender = useMemo(() => {
|
||||
return (
|
||||
@@ -138,7 +157,7 @@ const MySelect = <T = any,>(
|
||||
})}
|
||||
onClick={() => {
|
||||
if (value !== item.value) {
|
||||
onclickChange(item.value);
|
||||
onClickChange(item.value);
|
||||
}
|
||||
}}
|
||||
whiteSpace={'pre-wrap'}
|
||||
@@ -161,7 +180,7 @@ const MySelect = <T = any,>(
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}, [filterList, value]);
|
||||
}, [filterList, onClickChange, value]);
|
||||
|
||||
const isSelecting = loading || isLoading;
|
||||
|
||||
@@ -200,36 +219,48 @@ const MySelect = <T = any,>(
|
||||
: {})}
|
||||
{...props}
|
||||
>
|
||||
<Flex alignItems={'center'}>
|
||||
{isSelecting && <MyIcon mr={2} name={'common/loading'} w={'1rem'} />}
|
||||
{isSearch && isOpen ? (
|
||||
<Input
|
||||
ref={SearchInputRef}
|
||||
autoFocus
|
||||
variant={'unstyled'}
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
placeholder={
|
||||
selectItem?.alias ||
|
||||
(typeof selectItem?.label === 'string' ? selectItem?.label : placeholder)
|
||||
}
|
||||
size={'sm'}
|
||||
w={'100%'}
|
||||
color={'myGray.700'}
|
||||
onBlur={() => {
|
||||
setTimeout(() => {
|
||||
SearchInputRef?.current?.focus();
|
||||
}, 0);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
{selectItem?.icon && (
|
||||
<Avatar mr={2} src={selectItem.icon as any} w={selectItem.iconSize ?? '1rem'} />
|
||||
)}
|
||||
{selectItem?.alias || selectItem?.label || placeholder}
|
||||
</>
|
||||
)}
|
||||
<Flex alignItems={'center'} justifyContent="space-between" w="100%">
|
||||
<Flex alignItems={'center'}>
|
||||
{isSelecting && <MyIcon mr={2} name={'common/loading'} w={'1rem'} />}
|
||||
{valueLabel ? (
|
||||
<>{valueLabel}</>
|
||||
) : (
|
||||
<>
|
||||
{isSearch && isOpen ? (
|
||||
<Input
|
||||
ref={SearchInputRef}
|
||||
autoFocus
|
||||
variant={'unstyled'}
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
placeholder={
|
||||
(typeof selectItem?.alias === 'string' ? selectItem?.alias : '') ||
|
||||
(typeof selectItem?.label === 'string' ? selectItem?.label : placeholder)
|
||||
}
|
||||
size={'sm'}
|
||||
w={'100%'}
|
||||
color={'myGray.700'}
|
||||
onBlur={() => {
|
||||
setTimeout(() => {
|
||||
SearchInputRef?.current?.focus();
|
||||
}, 0);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
{selectItem?.icon && (
|
||||
<Avatar
|
||||
mr={2}
|
||||
src={selectItem.icon as any}
|
||||
w={selectItem.iconSize ?? '1rem'}
|
||||
/>
|
||||
)}
|
||||
{selectItem?.alias || selectItem?.label || placeholder}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Flex>
|
||||
</Flex>
|
||||
</MenuButton>
|
||||
|
||||
@@ -252,7 +283,7 @@ const MySelect = <T = any,>(
|
||||
'0px 2px 4px rgba(161, 167, 179, 0.25), 0px 0px 1px rgba(121, 141, 159, 0.25);'
|
||||
}
|
||||
zIndex={99}
|
||||
maxH={'40vh'}
|
||||
maxH={'45vh'}
|
||||
overflowY={'auto'}
|
||||
>
|
||||
{ScrollData ? <ScrollData>{ListRender}</ScrollData> : ListRender}
|
||||
|
@@ -190,6 +190,7 @@ export function useScrollPagination<
|
||||
params = {},
|
||||
EmptyTip,
|
||||
showErrorToast = true,
|
||||
disalbed = false,
|
||||
...props
|
||||
}: {
|
||||
scrollLoadType?: 'top' | 'bottom';
|
||||
@@ -198,6 +199,7 @@ export function useScrollPagination<
|
||||
params?: Record<string, any>;
|
||||
EmptyTip?: React.JSX.Element;
|
||||
showErrorToast?: boolean;
|
||||
disalbed?: boolean;
|
||||
} & Parameters<typeof useRequest2>[1]
|
||||
) {
|
||||
const { t } = useTranslation();
|
||||
@@ -345,10 +347,10 @@ export function useScrollPagination<
|
||||
// Reload data
|
||||
useRequest2(
|
||||
async () => {
|
||||
if (disalbed) return;
|
||||
loadData(true);
|
||||
},
|
||||
{
|
||||
manual: false,
|
||||
...props
|
||||
}
|
||||
);
|
||||
|
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"Click_to_delete_this_field": "Click to delete this field",
|
||||
"Filed_is_deprecated": "This field is deprecated",
|
||||
"MCP_tools_list_is_empty": "MCP tool not resolved",
|
||||
"MCP_tools_parse_failed": "Failed to parse MCP address",
|
||||
"MCP_tools_url": "MCP Address",
|
||||
@@ -6,7 +8,6 @@
|
||||
"MCP_tools_url_placeholder": "After filling in the MCP address, click Analysis",
|
||||
"Role_setting": "Permission",
|
||||
"Run": "Execute",
|
||||
"team_tags_set": "Team tags",
|
||||
"Team_Tags": "Team tags",
|
||||
"ai_point_price": "Billing",
|
||||
"ai_settings": "AI Configuration",
|
||||
@@ -106,6 +107,7 @@
|
||||
"no_mcp_tools_list": "No data yet, the MCP address needs to be parsed first",
|
||||
"node_not_intro": "This node is not introduced",
|
||||
"not_json_file": "Please select a JSON file",
|
||||
"not_the_newest": "Not the latest",
|
||||
"oaste_curl_string": "Enter CURL code",
|
||||
"open_auto_execute": "Enable automatic execution",
|
||||
"open_vision_function_tip": "Models with icon switches have image recognition capabilities. \nAfter being turned on, the model will parse the pictures in the file link and automatically parse the pictures in the user's question (user question ≤ 500 words).",
|
||||
@@ -138,6 +140,7 @@
|
||||
"stop_sign_placeholder": "Multiple serial numbers are separated by |, for example: aaa|stop",
|
||||
"stream_response": "Stream",
|
||||
"stream_response_tip": "Turning this switch off forces the model to use non-streaming mode and will not output content directly. \nIn the output of the AI reply, the content output by this model can be obtained for secondary processing.",
|
||||
"team_tags_set": "Team tags",
|
||||
"temperature": "Temperature",
|
||||
"temperature_tip": "Range 0~10. \nThe larger the value, the more divergent the model’s answer is; the smaller the value, the more rigorous the answer.",
|
||||
"template.hard_strict": "Strict Q&A template",
|
||||
|
@@ -96,6 +96,7 @@
|
||||
"add_new_param": "Add new param",
|
||||
"all_quotes": "All quotes",
|
||||
"all_result": "Full Results",
|
||||
"app_not_version": "This application has not been published, please publish it first",
|
||||
"back": "Back",
|
||||
"base_config": "Basic Configuration",
|
||||
"bill_already_processed": "Order has been processed",
|
||||
|
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"Click_to_delete_this_field": "点击删除该字段",
|
||||
"Filed_is_deprecated": "该字段已弃用",
|
||||
"MCP_tools_debug": "调试",
|
||||
"MCP_tools_detail": "查看详情",
|
||||
"MCP_tools_list": "工具列表",
|
||||
@@ -10,7 +12,6 @@
|
||||
"MCP_tools_url_placeholder": "填入 MCP 地址后,点击解析",
|
||||
"Role_setting": "权限设置",
|
||||
"Run": "运行",
|
||||
"team_tags_set": "团队标签",
|
||||
"Team_Tags": "团队标签",
|
||||
"ai_point_price": "AI积分计费",
|
||||
"ai_settings": "AI 配置",
|
||||
@@ -110,6 +111,7 @@
|
||||
"no_mcp_tools_list": "暂无数据,需先解析 MCP 地址",
|
||||
"node_not_intro": "这个节点没有介绍",
|
||||
"not_json_file": "请选择JSON文件",
|
||||
"not_the_newest": "非最新版",
|
||||
"oaste_curl_string": "输入 CURL 代码",
|
||||
"open_auto_execute": "启用自动执行",
|
||||
"open_vision_function_tip": "有图示开关的模型即拥有图片识别能力。若开启,模型会解析文件链接里的图片,并自动解析用户问题中的图片(用户问题≤500字时生效)。",
|
||||
@@ -143,6 +145,7 @@
|
||||
"stop_sign_placeholder": "多个序列号通过 | 隔开,例如:aaa|stop",
|
||||
"stream_response": "流输出",
|
||||
"stream_response_tip": "关闭该开关,可以强制模型使用非流模式,并且不会直接进行内容输出。可以在 AI 回复的输出中,获取本次模型输出的内容进行二次处理。",
|
||||
"team_tags_set": "团队标签",
|
||||
"temperature": "温度",
|
||||
"temperature_tip": "范围 0~10。值越大,代表模型回答越发散;值越小,代表回答越严谨。",
|
||||
"template.hard_strict": "严格问答模板",
|
||||
|
@@ -96,6 +96,7 @@
|
||||
"add_new_param": "新增参数",
|
||||
"all_quotes": "全部引用",
|
||||
"all_result": "完整结果",
|
||||
"app_not_version": " 该应用未发布过,请先发布应用",
|
||||
"back": "返回",
|
||||
"base_config": "基础配置",
|
||||
"bill_already_processed": "订单已处理",
|
||||
|
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"Click_to_delete_this_field": "點擊刪除該字段",
|
||||
"Filed_is_deprecated": "該字段已棄用",
|
||||
"MCP_tools_list_is_empty": "未解析到 MCP 工具",
|
||||
"MCP_tools_parse_failed": "解析 MCP 地址失敗",
|
||||
"MCP_tools_url": "MCP 地址",
|
||||
@@ -6,7 +8,6 @@
|
||||
"MCP_tools_url_placeholder": "填入 MCP 地址後,點擊解析",
|
||||
"Role_setting": "權限設定",
|
||||
"Run": "執行",
|
||||
"team_tags_set": "團隊標籤",
|
||||
"Team_Tags": "團隊標籤",
|
||||
"ai_point_price": "AI 積分計費",
|
||||
"ai_settings": "AI 設定",
|
||||
@@ -106,6 +107,7 @@
|
||||
"no_mcp_tools_list": "暫無數據,需先解析 MCP 地址",
|
||||
"node_not_intro": "這個節點沒有介紹",
|
||||
"not_json_file": "請選擇 JSON 檔案",
|
||||
"not_the_newest": "非最新版",
|
||||
"oaste_curl_string": "輸入 CURL 代碼",
|
||||
"open_auto_execute": "啟用自動執行",
|
||||
"open_vision_function_tip": "有圖示開關的模型即擁有圖片辨識功能。若開啟,模型會解析檔案連結中的圖片,並自動解析使用者問題中的圖片(使用者問題 ≤ 500 字時生效)。",
|
||||
@@ -138,6 +140,7 @@
|
||||
"stop_sign_placeholder": "多個序列號透過 | 隔開,例如:aaa|stop",
|
||||
"stream_response": "流輸出",
|
||||
"stream_response_tip": "關閉該開關,可以強制模型使用非流模式,並且不會直接進行內容輸出。\n可在 AI 回覆的輸出中,取得本次模型輸出的內容進行二次處理。",
|
||||
"team_tags_set": "團隊標籤",
|
||||
"temperature": "溫度",
|
||||
"temperature_tip": "範圍 0~10。\n值越大,代表模型回答越發散;值越小,代表回答越嚴謹。",
|
||||
"template.hard_strict": "嚴格問答範本",
|
||||
|
@@ -96,6 +96,7 @@
|
||||
"add_new_param": "新增參數",
|
||||
"all_quotes": "全部引用",
|
||||
"all_result": "完整結果",
|
||||
"app_not_version": "該應用未發布過,請先發布應用",
|
||||
"back": "返回",
|
||||
"base_config": "基本設定",
|
||||
"bill_already_processed": "訂單已處理",
|
||||
|
Reference in New Issue
Block a user