feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { useFormDefaultValues } from './use-form-default-values';
|
||||
export { useOpenWorkflow } from './use-open-workflow';
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type IFormSchema } from '@coze-workflow/test-run-next';
|
||||
import { useTestFormService } from '@coze-workflow/test-run';
|
||||
|
||||
import { useGlobalState, useTestRunReporterService } from '@/hooks';
|
||||
|
||||
import { getNodeExecuteHistoryInput } from '../utils';
|
||||
|
||||
export const useFormDefaultValues = () => {
|
||||
const testFormService = useTestFormService();
|
||||
const globalState = useGlobalState();
|
||||
const reporter = useTestRunReporterService();
|
||||
const getDefaultValues = async (schema: IFormSchema) => {
|
||||
if (!schema) {
|
||||
return;
|
||||
}
|
||||
const nodeId = schema['x-node-id'] || '';
|
||||
const nodeType = schema['x-node-type'] || '';
|
||||
|
||||
// 最高优:用户上次填写的值
|
||||
const cacheData = testFormService.getCacheValues(nodeId);
|
||||
if (cacheData) {
|
||||
reporter.formGenDataOrigin({ gen_data_origin: 'cache' });
|
||||
return cacheData;
|
||||
}
|
||||
|
||||
const historyValues = await getNodeExecuteHistoryInput({
|
||||
workflowId: globalState.workflowId,
|
||||
spaceId: globalState.spaceId,
|
||||
nodeId,
|
||||
nodeType,
|
||||
});
|
||||
if (historyValues) {
|
||||
reporter.formGenDataOrigin({ gen_data_origin: 'history' });
|
||||
return historyValues;
|
||||
}
|
||||
};
|
||||
|
||||
return { getDefaultValues };
|
||||
};
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/** pick from master,若有冲突请以 master 为准 */
|
||||
import { useGlobalState } from '@/hooks';
|
||||
|
||||
/**
|
||||
* 打开 workflow
|
||||
* TODO:有一部分依赖还没有迁移完,暂时先把这个hook放在这里,后面还需要迁移
|
||||
*/
|
||||
export const useOpenWorkflow = () => {
|
||||
const { projectId, getProjectApi } = useGlobalState();
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const open = (data: any) => {
|
||||
const { workflowId, executeId, subExecuteId } = data;
|
||||
const projectApi = getProjectApi();
|
||||
|
||||
if (projectId && projectApi) {
|
||||
// 应用内跳转
|
||||
projectApi.sendMsgOpenWidget(`/workflow/${workflowId}`, {
|
||||
name: 'debug',
|
||||
data: {
|
||||
executeId,
|
||||
subExecuteId,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
// 资源库或者运维平台跳转
|
||||
const url = new URL(window.location.href);
|
||||
const params = new URLSearchParams();
|
||||
|
||||
// 新增/更新查询参数,只保留这 4 个参数,包括 space_id
|
||||
params.append('space_id', url.searchParams.get('space_id') || '0');
|
||||
params.append('workflow_id', workflowId);
|
||||
params.append('execute_id', executeId);
|
||||
params.append('sub_execute_id', subExecuteId);
|
||||
|
||||
// 构建新 URL
|
||||
url.search = params.toString();
|
||||
|
||||
// 在新标签页打开
|
||||
window.open(url.toString(), '_blank');
|
||||
}
|
||||
};
|
||||
|
||||
return { open };
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { useFormDefaultValues, useOpenWorkflow } from './hooks';
|
||||
|
||||
export {
|
||||
generateFormSchema,
|
||||
generateParametersToProperties,
|
||||
generateFormNodeField,
|
||||
generateEnvToRelatedContextProperties,
|
||||
getRelatedInfo,
|
||||
} from './utils';
|
||||
|
||||
export type { NodeTestMeta, WorkflowNodeEntity } from './types';
|
||||
|
||||
export { generateField, type IFormSchema } from '@coze-workflow/test-run-next';
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type WorkflowNodeEntity } from '@flowgram-adapter/free-layout-editor';
|
||||
import { type IFormSchema } from '@coze-workflow/test-run-next';
|
||||
/**
|
||||
* 目前项目中从 flow-sdk 导入的类型位置比较混乱
|
||||
* test run 全部收口到 kit
|
||||
*/
|
||||
export { type WorkflowNodeEntity } from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
interface Context {
|
||||
isChatflow: boolean;
|
||||
isInProject: boolean;
|
||||
workflowId: string;
|
||||
spaceId: string;
|
||||
}
|
||||
/**
|
||||
* Node Registry Test Meta
|
||||
*/
|
||||
export type NodeTestMeta =
|
||||
| {
|
||||
/**
|
||||
* 是否支持测试集
|
||||
*/
|
||||
testset?: boolean;
|
||||
/**
|
||||
* TestRun 运行所需的关联上下文
|
||||
*/
|
||||
generateRelatedContext?: (
|
||||
node: WorkflowNodeEntity,
|
||||
context: Context,
|
||||
) => IFormSchema | null | Promise<IFormSchema | null>;
|
||||
generateFormInputProperties?: (
|
||||
node: WorkflowNodeEntity,
|
||||
) => IFormSchema['properties'] | Promise<IFormSchema['properties']>;
|
||||
generateFormBatchProperties?: (
|
||||
node: WorkflowNodeEntity,
|
||||
) => IFormSchema['properties'] | Promise<IFormSchema['properties']>;
|
||||
generateFormSettingProperties?: (
|
||||
node: WorkflowNodeEntity,
|
||||
) => IFormSchema['properties'] | Promise<IFormSchema['properties']>;
|
||||
}
|
||||
| boolean;
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import {
|
||||
type IFormSchema,
|
||||
TestFormFieldName,
|
||||
} from '@coze-workflow/test-run-next';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IntelligenceType } from '@coze-arch/bot-api/intelligence_api';
|
||||
interface GenerateEnvToRelatedContextPropertiesOptions {
|
||||
isNeedBot: boolean;
|
||||
isNeedConversation?: boolean;
|
||||
hasVariableAssignNode?: boolean;
|
||||
hasLTMNode?: boolean;
|
||||
hasConversationNode?: boolean;
|
||||
disableBot?: boolean;
|
||||
disableBotTooltip?: string;
|
||||
disableProject?: boolean;
|
||||
disableProjectTooltip?: string;
|
||||
}
|
||||
|
||||
export const generateEnvToRelatedContextProperties = (
|
||||
options: GenerateEnvToRelatedContextPropertiesOptions,
|
||||
) => {
|
||||
const field: IFormSchema = {
|
||||
['x-component']: 'RelatedFieldCollapse',
|
||||
};
|
||||
|
||||
const { isNeedBot, isNeedConversation } = options;
|
||||
if (!isNeedBot && !isNeedConversation) {
|
||||
return null;
|
||||
}
|
||||
field['x-component-props'] = options as any;
|
||||
field['x-validator'] = (({ value }) => {
|
||||
const botValue = value?.[TestFormFieldName.Bot];
|
||||
const conversationValue = value?.[TestFormFieldName.Conversation];
|
||||
if (isNeedBot && !botValue) {
|
||||
return {
|
||||
type: 'bot',
|
||||
message: I18n.t('workflow_testset_required_tip', {
|
||||
param_name: 'Bot',
|
||||
}),
|
||||
};
|
||||
}
|
||||
if (
|
||||
isNeedConversation &&
|
||||
botValue?.type === IntelligenceType.Project &&
|
||||
!conversationValue
|
||||
) {
|
||||
return {
|
||||
type: 'conversation',
|
||||
message: I18n.t('workflow_testset_required_tip', {
|
||||
param_name: 'Conversation',
|
||||
}),
|
||||
};
|
||||
}
|
||||
}) as any;
|
||||
|
||||
return field;
|
||||
};
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
type IFormSchema,
|
||||
isFormSchemaPropertyEmpty,
|
||||
TestFormFieldName,
|
||||
} from '@coze-workflow/test-run-next';
|
||||
|
||||
import type { WorkflowNodeEntity } from '../types';
|
||||
|
||||
interface GroupOptions {
|
||||
node: WorkflowNodeEntity;
|
||||
fnName: string;
|
||||
groupName: string;
|
||||
properties: Required<IFormSchema>['properties'];
|
||||
}
|
||||
|
||||
const generateNodeFieldGroup = async (options: GroupOptions) => {
|
||||
const { node, fnName, groupName, properties } = options;
|
||||
const registry = node.getNodeRegistry();
|
||||
const fn = registry?.meta?.test?.[fnName];
|
||||
if (fn) {
|
||||
const group = await fn(node);
|
||||
if (!isFormSchemaPropertyEmpty(group)) {
|
||||
properties[groupName] = {
|
||||
type: 'object',
|
||||
properties: group,
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
interface GenerateFormNodeFieldOptions {
|
||||
node: WorkflowNodeEntity;
|
||||
}
|
||||
|
||||
export const generateFormNodeField = async ({
|
||||
node,
|
||||
}: GenerateFormNodeFieldOptions) => {
|
||||
const properties = {};
|
||||
|
||||
await Promise.all([
|
||||
generateNodeFieldGroup({
|
||||
node,
|
||||
fnName: 'generateFormBatchProperties',
|
||||
groupName: TestFormFieldName.Batch,
|
||||
properties,
|
||||
}),
|
||||
generateNodeFieldGroup({
|
||||
node,
|
||||
fnName: 'generateFormSettingProperties',
|
||||
groupName: TestFormFieldName.Setting,
|
||||
properties,
|
||||
}),
|
||||
generateNodeFieldGroup({
|
||||
node,
|
||||
fnName: 'generateFormInputProperties',
|
||||
groupName: TestFormFieldName.Input,
|
||||
properties,
|
||||
}),
|
||||
]);
|
||||
|
||||
if (isFormSchemaPropertyEmpty(properties)) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
type: 'object',
|
||||
properties,
|
||||
['x-decorator']: 'NodeFieldCollapse',
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { WorkflowNodeRefVariablesData } from '@coze-workflow/variable';
|
||||
import { type IFormSchema } from '@coze-workflow/test-run-next';
|
||||
|
||||
import type { WorkflowNodeEntity } from '../types';
|
||||
import { generateEnvToRelatedContextProperties } from './generate-env-to-related-context-properties';
|
||||
|
||||
interface GenerateFormRelatedFieldOptions {
|
||||
node: WorkflowNodeEntity;
|
||||
isChatflow: boolean;
|
||||
isInProject: boolean;
|
||||
spaceId: string;
|
||||
workflowId: string;
|
||||
}
|
||||
|
||||
export const generateFormRelatedField = async ({
|
||||
node,
|
||||
isChatflow,
|
||||
isInProject,
|
||||
spaceId,
|
||||
workflowId,
|
||||
}: GenerateFormRelatedFieldOptions) => {
|
||||
const registry = node.getNodeRegistry();
|
||||
|
||||
let field: IFormSchema | null = null;
|
||||
if (registry?.meta?.test?.generateRelatedContext) {
|
||||
field = await registry.meta.test.generateRelatedContext(node, {
|
||||
isChatflow,
|
||||
isInProject,
|
||||
spaceId,
|
||||
workflowId,
|
||||
});
|
||||
}
|
||||
/** 若自定义逻辑判定无需选择环境,则还需要判定一下变量引用 */
|
||||
if (
|
||||
!field &&
|
||||
!isInProject &&
|
||||
node.getData(WorkflowNodeRefVariablesData).hasGlobalRef
|
||||
) {
|
||||
field = generateEnvToRelatedContextProperties({ isNeedBot: true });
|
||||
}
|
||||
|
||||
return field;
|
||||
};
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
type IFormSchema,
|
||||
TestFormFieldName,
|
||||
isFormSchemaPropertyEmpty,
|
||||
} from '@coze-workflow/test-run-next';
|
||||
import { PUBLIC_SPACE_ID } from '@coze-workflow/base';
|
||||
|
||||
import type { WorkflowNodeEntity } from '../types';
|
||||
import { getTestsetField } from './generate-form-schema/testset-field';
|
||||
import { generateFormRelatedField } from './generate-form-related-field';
|
||||
import { generateFormNodeField } from './generate-form-node-field';
|
||||
|
||||
interface GenerateFormSchemaOptions {
|
||||
node: WorkflowNodeEntity;
|
||||
workflowId: string;
|
||||
spaceId: string;
|
||||
isChatflow: boolean;
|
||||
isInProject: boolean;
|
||||
isPreview?: boolean;
|
||||
}
|
||||
|
||||
export const generateFormSchema = async (
|
||||
options: GenerateFormSchemaOptions,
|
||||
) => {
|
||||
const { node, spaceId, isPreview } = options;
|
||||
const formSchema = {
|
||||
type: 'object',
|
||||
['x-node-id']: node.id,
|
||||
['x-node-type']: node.flowNodeType,
|
||||
properties: {},
|
||||
};
|
||||
|
||||
const relatedField = await generateFormRelatedField(options);
|
||||
if (relatedField) {
|
||||
formSchema.properties[TestFormFieldName.Related] = relatedField;
|
||||
}
|
||||
|
||||
/**
|
||||
* step1: 计算节点输入
|
||||
*/
|
||||
const nodeField = await generateFormNodeField(options);
|
||||
if (nodeField) {
|
||||
formSchema.properties[TestFormFieldName.Node] = nodeField;
|
||||
}
|
||||
|
||||
const testset = node.getNodeRegistry().meta?.test?.testset;
|
||||
/**
|
||||
* 若支持测试集且输入不为空,则添加测试集的组件
|
||||
*/
|
||||
/* The community version does not currently support testset, for future expansion */
|
||||
if (
|
||||
!IS_OPEN_SOURCE &&
|
||||
spaceId !== PUBLIC_SPACE_ID &&
|
||||
!isPreview &&
|
||||
testset &&
|
||||
!isFormSchemaPropertyEmpty(formSchema.properties)
|
||||
) {
|
||||
Object.assign(formSchema.properties, getTestsetField());
|
||||
}
|
||||
|
||||
return formSchema as IFormSchema;
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { getTestsetField } from './testset-field';
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { TestFormFieldName } from '@coze-workflow/test-run-next';
|
||||
|
||||
export const getTestsetField = () => ({
|
||||
[TestFormFieldName.TestsetSelect]: {
|
||||
// 排序在最前面
|
||||
['x-index']: 0,
|
||||
['x-component']: 'TestsetSelect',
|
||||
},
|
||||
[TestFormFieldName.TestsetSave]: {
|
||||
['x-component']: 'TestsetSave',
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { type WorkflowNodeEntity } from '@flowgram-adapter/free-layout-editor';
|
||||
import {
|
||||
generateInputJsonSchema,
|
||||
variableUtils,
|
||||
} from '@coze-workflow/variable';
|
||||
import { generateField } from '@coze-workflow/test-run-next';
|
||||
import {
|
||||
ValueExpressionType,
|
||||
type VariableMetaDTO,
|
||||
ViewVariableType,
|
||||
} from '@coze-workflow/base';
|
||||
|
||||
/**
|
||||
* 将结构化的 input 转化为 Field
|
||||
* fork from packages/workflow/playground/src/components/test-run/utils/generate-test-form-fields.ts
|
||||
* 在全量前需要及时观测两者变动
|
||||
*/
|
||||
|
||||
export const generateInputToField = (
|
||||
data: any,
|
||||
{ node }: { node: WorkflowNodeEntity },
|
||||
) => {
|
||||
if (data.input.type === ValueExpressionType.OBJECT_REF) {
|
||||
const dtoMeta = variableUtils.inputValueToDTO(
|
||||
data,
|
||||
node.context.variableService,
|
||||
{ node },
|
||||
);
|
||||
const jsonSchema = generateInputJsonSchema(
|
||||
(dtoMeta || {}) as VariableMetaDTO,
|
||||
(v: any) => ({
|
||||
name: v?.name,
|
||||
...(v?.input || {}),
|
||||
}),
|
||||
);
|
||||
return generateField({
|
||||
type: ViewVariableType.Object,
|
||||
title: data.title || data.label || data.name,
|
||||
name: data.name,
|
||||
description: data.description,
|
||||
required: data?.required,
|
||||
validateJsonSchema: jsonSchema,
|
||||
extra: {
|
||||
['x-dto-meta']: dtoMeta,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const workflowVariable =
|
||||
node.context.variableService.getWorkflowVariableByKeyPath(
|
||||
data.input.content.keyPath,
|
||||
{ node },
|
||||
);
|
||||
|
||||
const viewVariable = workflowVariable?.viewMeta;
|
||||
const type: ViewVariableType =
|
||||
variableUtils.getValueExpressionViewType(
|
||||
data.input,
|
||||
node.context.variableService,
|
||||
{ node },
|
||||
) || ViewVariableType.String;
|
||||
const dtoMeta: VariableMetaDTO | undefined =
|
||||
variableUtils.getValueExpressionDTOMeta(
|
||||
data.input,
|
||||
node.context.variableService,
|
||||
{ node },
|
||||
);
|
||||
|
||||
const jsonSchema = generateInputJsonSchema(
|
||||
(dtoMeta || {}) as VariableMetaDTO,
|
||||
);
|
||||
return generateField({
|
||||
title: data.title || data.label || data.name,
|
||||
name: data.name,
|
||||
type,
|
||||
required: data?.required,
|
||||
description: data.description,
|
||||
validateJsonSchema: jsonSchema,
|
||||
/**
|
||||
* 部分创建变量的位置可以设置变量的默认值
|
||||
* 在引用变量的位置,通过 meta 拿到默认值作为表单默认值
|
||||
*/
|
||||
defaultValue: viewVariable?.defaultValue,
|
||||
extra: {
|
||||
['x-dto-meta']: dtoMeta,
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { isGlobalVariableKey } from '@coze-workflow/variable';
|
||||
import { getSortedInputParameters } from '@coze-workflow/nodes';
|
||||
import { ValueExpressionType } from '@coze-workflow/base';
|
||||
|
||||
import { isStaticObjectRef } from '@/components/test-run/utils/is-static-object-ref';
|
||||
|
||||
import type { WorkflowNodeEntity } from '../types';
|
||||
import { generateInputToField } from './generate-input-to-field';
|
||||
|
||||
export const generateParametersToProperties = (
|
||||
parameters: any[],
|
||||
{ node }: { node: WorkflowNodeEntity },
|
||||
) => {
|
||||
if (!parameters || !Array.isArray(parameters)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const fields = parameters.filter(i => {
|
||||
/** 对象引用类型不需要过滤,全是静态字段的需要过滤 */
|
||||
if (i.input?.type === ValueExpressionType.OBJECT_REF) {
|
||||
return !isStaticObjectRef(i);
|
||||
}
|
||||
/** 非引用类型直接过滤,引用值不存在直接过滤 */
|
||||
if (i.input?.type !== 'ref' || !i.input?.content) {
|
||||
return false;
|
||||
}
|
||||
/** 如果引用来自于自身,则不需要再填写 */
|
||||
const [nodeId] = i.input.content.keyPath || [];
|
||||
if (nodeId && nodeId === node.id) {
|
||||
return false;
|
||||
}
|
||||
if (isGlobalVariableKey(nodeId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
const sortedFields = getSortedInputParameters(fields);
|
||||
|
||||
return sortedFields
|
||||
.map(field => generateInputToField(field, { node }))
|
||||
.reduce((properties, field) => {
|
||||
if (field.name) {
|
||||
properties[field.name] = field;
|
||||
}
|
||||
return properties;
|
||||
}, {});
|
||||
};
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { invert } from 'lodash-es';
|
||||
import {
|
||||
safeJsonParse,
|
||||
TestFormFieldName,
|
||||
stringifyFormValuesFromBacked,
|
||||
} from '@coze-workflow/test-run-next';
|
||||
import { workflowApi, StandardNodeType } from '@coze-workflow/base';
|
||||
import { NodeHistoryScene } from '@coze-arch/bot-api/workflow_api';
|
||||
|
||||
interface GetNodeExecuteHistoryInputOptions {
|
||||
workflowId: string;
|
||||
spaceId: string;
|
||||
nodeId: string;
|
||||
nodeType: string;
|
||||
}
|
||||
|
||||
export const getNodeExecuteHistoryInput = async (
|
||||
options: GetNodeExecuteHistoryInputOptions,
|
||||
) => {
|
||||
const { spaceId, workflowId, nodeId, nodeType } = options;
|
||||
const map = invert(StandardNodeType);
|
||||
const nodeTypeStr = map[nodeType];
|
||||
if (!nodeId || !nodeTypeStr) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const res = await workflowApi.GetNodeExecuteHistory({
|
||||
workflow_id: workflowId,
|
||||
space_id: spaceId,
|
||||
node_id: nodeId,
|
||||
node_type: nodeTypeStr,
|
||||
execute_id: '',
|
||||
node_history_scene: NodeHistoryScene.TestRunInput,
|
||||
});
|
||||
const inputValues = safeJsonParse(res.data?.input);
|
||||
if (inputValues) {
|
||||
return {
|
||||
[TestFormFieldName.Node]: {
|
||||
[TestFormFieldName.Input]: stringifyFormValuesFromBacked(inputValues),
|
||||
},
|
||||
};
|
||||
}
|
||||
// eslint-disable-next-line @coze-arch/no-empty-catch
|
||||
} catch {
|
||||
//
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { intersection } from 'lodash-es';
|
||||
import {
|
||||
workflowApi,
|
||||
CONVERSATION_NODES,
|
||||
StandardNodeType,
|
||||
} from '@coze-workflow/base';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
|
||||
interface GetRelatedInfoOptions {
|
||||
workflowId: string;
|
||||
spaceId: string;
|
||||
}
|
||||
function checkHasConversationNode(typeList: StandardNodeType[]) {
|
||||
return intersection(typeList, CONVERSATION_NODES).length > 0;
|
||||
}
|
||||
|
||||
export const getRelatedInfo = async (options: GetRelatedInfoOptions) => {
|
||||
const { workflowId, spaceId } = options;
|
||||
const { data: nodeTypes } = await workflowApi.QueryWorkflowNodeTypes({
|
||||
workflow_id: workflowId,
|
||||
space_id: spaceId,
|
||||
});
|
||||
const flowTypeList = nodeTypes?.node_types ?? [];
|
||||
const subFlowTypeList = nodeTypes?.sub_workflow_node_types ?? [];
|
||||
const sumTypeList = [
|
||||
...flowTypeList,
|
||||
...subFlowTypeList,
|
||||
] as StandardNodeType[];
|
||||
|
||||
const flowPropsList = nodeTypes?.nodes_properties ?? [];
|
||||
const subFlowPropsList = nodeTypes?.sub_workflow_nodes_properties ?? [];
|
||||
const sumPropsList = [...flowPropsList, ...subFlowPropsList];
|
||||
|
||||
const hasVariableNode = sumTypeList.includes(StandardNodeType.Variable);
|
||||
const hasVariableAssignNode = sumTypeList.includes(
|
||||
StandardNodeType.VariableAssign,
|
||||
);
|
||||
|
||||
const hasIntentNode = sumTypeList.includes(StandardNodeType.Intent);
|
||||
const hasLLMNode = sumTypeList.includes(StandardNodeType.LLM);
|
||||
const hasLTMNode = sumTypeList.includes(StandardNodeType.LTM);
|
||||
const hasConversationNode = checkHasConversationNode(sumTypeList);
|
||||
const propsEnableChatHistory = sumPropsList.some(
|
||||
item => item.is_enable_chat_history,
|
||||
);
|
||||
const hasNodeUseGlobalVariable = !!sumPropsList.find(
|
||||
item => item.is_ref_global_variable,
|
||||
);
|
||||
|
||||
const hasChatHistoryEnabledLLM =
|
||||
(hasLLMNode || hasIntentNode) && propsEnableChatHistory;
|
||||
|
||||
const hasSubFlowNode = subFlowTypeList.some(it =>
|
||||
[StandardNodeType.SubWorkflow].includes(it as StandardNodeType),
|
||||
);
|
||||
|
||||
// 流程中(包含 subflow 下钻节点)有 Variable、Database、开启 chat history 的LLM || subflow 节点有 subflow
|
||||
const isNeedBot =
|
||||
hasNodeUseGlobalVariable ||
|
||||
hasVariableAssignNode ||
|
||||
hasVariableNode ||
|
||||
hasLTMNode ||
|
||||
hasChatHistoryEnabledLLM ||
|
||||
hasSubFlowNode ||
|
||||
hasConversationNode;
|
||||
|
||||
const isNeedConversation = hasChatHistoryEnabledLLM;
|
||||
|
||||
return {
|
||||
isNeedBot,
|
||||
isNeedConversation,
|
||||
hasVariableNode,
|
||||
hasVariableAssignNode,
|
||||
hasNodeUseGlobalVariable,
|
||||
hasLTMNode,
|
||||
hasChatHistoryEnabledLLM,
|
||||
hasConversationNode,
|
||||
// 当包含会话类节点,需要禁用 bot 选项
|
||||
disableBot: hasConversationNode,
|
||||
disableBotTooltip: hasConversationNode ? I18n.t('wf_chatflow_141') : '',
|
||||
// 包含 LTM 节点,需要禁用项目选项
|
||||
disableProject: hasLTMNode,
|
||||
disableProjectTooltip: hasLTMNode ? I18n.t('wf_chatflow_142') : '',
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { generateParametersToProperties } from './generate-parameters-to-properties';
|
||||
export { generateFormNodeField } from './generate-form-node-field';
|
||||
export { generateFormSchema } from './generate-form-schema';
|
||||
export { getNodeExecuteHistoryInput } from './get-node-execute-history-input';
|
||||
export { generateEnvToRelatedContextProperties } from './generate-env-to-related-context-properties';
|
||||
export { getRelatedInfo } from './get-related-info';
|
||||
Reference in New Issue
Block a user