feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
25
frontend/packages/data/memory/variables/src/store/index.ts
Normal file
25
frontend/packages/data/memory/variables/src/store/index.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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 {
|
||||
useVariableGroupsStore,
|
||||
type VariableGroup,
|
||||
type Variable,
|
||||
type VariableMeta,
|
||||
VariableTypeDTO,
|
||||
VariableSchemaDTO,
|
||||
ViewVariableType,
|
||||
} from './variable-groups';
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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 {
|
||||
useVariableGroupsStore,
|
||||
type VariableGroup,
|
||||
type Variable,
|
||||
type VariableMeta,
|
||||
} from './store';
|
||||
export { ViewVariableType, VariableTypeDTO, VariableSchemaDTO } from './types';
|
||||
@@ -0,0 +1,359 @@
|
||||
/*
|
||||
* 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 @coze-arch/max-line-per-function */
|
||||
import { devtools, subscribeWithSelector } from 'zustand/middleware';
|
||||
import { create } from 'zustand';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { produce } from 'immer';
|
||||
import {
|
||||
type project_memory as ProjectMemory,
|
||||
type VariableChannel,
|
||||
VariableType,
|
||||
} from '@coze-arch/bot-api/memory';
|
||||
|
||||
import { traverse } from '../../utils/traverse';
|
||||
import { type ViewVariableType, ObjectLikeTypes } from './types';
|
||||
import { getDtoVariable } from './transform/vo2dto';
|
||||
import { getGroupListByDto } from './transform/dto2vo';
|
||||
|
||||
export interface Variable {
|
||||
variableId: string;
|
||||
type: ViewVariableType;
|
||||
name: string;
|
||||
children: Variable[];
|
||||
defaultValue: string;
|
||||
description: string;
|
||||
enabled: boolean;
|
||||
channel: VariableChannel;
|
||||
effectiveChannelList: string[];
|
||||
variableType: VariableType;
|
||||
readonly: boolean;
|
||||
groupId: string;
|
||||
parentId: string;
|
||||
meta: VariableMeta;
|
||||
}
|
||||
|
||||
export interface VariableMeta {
|
||||
isHistory: boolean;
|
||||
level?: number;
|
||||
hasObjectLike?: boolean;
|
||||
field?: string;
|
||||
}
|
||||
|
||||
export interface VariableGroup {
|
||||
groupId: string;
|
||||
groupName: string;
|
||||
groupDesc: string;
|
||||
groupExtDesc: string;
|
||||
isReadOnly: boolean;
|
||||
channel: VariableChannel;
|
||||
subGroupList: VariableGroup[];
|
||||
varInfoList: Variable[];
|
||||
raw: ProjectMemory.GroupVariableInfo;
|
||||
}
|
||||
|
||||
export interface VariableGroupsStore {
|
||||
variableGroups: VariableGroup[];
|
||||
canEdit: boolean;
|
||||
}
|
||||
|
||||
export const getDefaultVariableGroupStore = (): VariableGroupsStore => ({
|
||||
canEdit: false,
|
||||
variableGroups: [],
|
||||
});
|
||||
|
||||
export interface VariableGroupsAction {
|
||||
setVariableGroups: (variableGroups: VariableGroup[]) => void;
|
||||
createVariable: (variableInfo: {
|
||||
variableType: ViewVariableType;
|
||||
groupId: string;
|
||||
parentId: string;
|
||||
channel: VariableChannel;
|
||||
}) => Variable;
|
||||
// 更新变量, 根据groupId和variableId更新
|
||||
updateVariable: (newVariable: Variable) => void;
|
||||
// 更新变量的meta信息
|
||||
updateMeta: (params: {
|
||||
variables: Variable[];
|
||||
level?: number;
|
||||
parentId?: string;
|
||||
}) => void;
|
||||
// 新增根节点变量
|
||||
addRootVariable: (variable: Omit<Variable, 'channel'>) => void;
|
||||
// 新增子节点变量
|
||||
addChildVariable: (variable: Variable) => void;
|
||||
// 删除变量
|
||||
deleteVariable: (variable: Variable) => void;
|
||||
// 保存后作为历史变量对待
|
||||
saveHistory: () => void;
|
||||
// 获取DTO variable
|
||||
getDtoVariable: (variable: Variable) => ProjectMemory.Variable;
|
||||
// 获取groups下所有的变量
|
||||
getAllRootVariables: () => Variable[];
|
||||
// 获取groups下所有的变量
|
||||
getAllVariables: () => Variable[];
|
||||
transformDto2Vo: (data: ProjectMemory.GroupVariableInfo[]) => VariableGroup[];
|
||||
initStore: (data: {
|
||||
variableGroups: ProjectMemory.GroupVariableInfo[];
|
||||
canEdit: boolean;
|
||||
}) => void;
|
||||
clear: () => void;
|
||||
// 在变量树中查找变量,并可选地修改或删除
|
||||
findAndModifyVariable: (
|
||||
groupId: string,
|
||||
predicate: (variable: Variable) => boolean,
|
||||
options?: {
|
||||
modifyVariable?: (variable: Variable) => void;
|
||||
removeVariable?: boolean;
|
||||
mark?: string;
|
||||
},
|
||||
) => Variable | null;
|
||||
}
|
||||
|
||||
export const useVariableGroupsStore = create<
|
||||
VariableGroupsStore & VariableGroupsAction
|
||||
>()(
|
||||
devtools(
|
||||
subscribeWithSelector((set, get) => ({
|
||||
...getDefaultVariableGroupStore(),
|
||||
setVariableGroups: variableGroups =>
|
||||
set({ variableGroups }, false, 'setVariableGroups'),
|
||||
createVariable: baseInfo => ({
|
||||
variableId: nanoid(),
|
||||
type: baseInfo.variableType,
|
||||
name: '',
|
||||
enabled: true,
|
||||
children: [],
|
||||
defaultValue: '',
|
||||
description: '',
|
||||
channel: baseInfo.channel,
|
||||
effectiveChannelList: [],
|
||||
variableType: VariableType.KVVariable,
|
||||
readonly: false,
|
||||
groupId: baseInfo.groupId,
|
||||
parentId: baseInfo.parentId,
|
||||
meta: {
|
||||
isHistory: false,
|
||||
},
|
||||
}),
|
||||
addRootVariable: variable => {
|
||||
set(
|
||||
produce<VariableGroupsStore>(state => {
|
||||
const findGroup = state.variableGroups.find(
|
||||
item => item.groupId === variable.groupId,
|
||||
);
|
||||
if (!findGroup) {
|
||||
return;
|
||||
}
|
||||
findGroup.varInfoList.push({
|
||||
...variable,
|
||||
channel: findGroup.channel,
|
||||
});
|
||||
get().updateMeta({
|
||||
variables: findGroup.varInfoList,
|
||||
level: 0,
|
||||
parentId: '',
|
||||
});
|
||||
}),
|
||||
false,
|
||||
'addRootVariable',
|
||||
);
|
||||
},
|
||||
addChildVariable: variable => {
|
||||
get().findAndModifyVariable(
|
||||
variable.groupId,
|
||||
item => item.variableId === variable.parentId,
|
||||
{
|
||||
modifyVariable: parentNode => {
|
||||
parentNode.children.push(variable);
|
||||
get().updateMeta({
|
||||
variables: parentNode.children,
|
||||
level: (parentNode.meta.level || 0) + 1,
|
||||
parentId: parentNode.variableId,
|
||||
});
|
||||
},
|
||||
mark: 'addChildVariable',
|
||||
},
|
||||
);
|
||||
},
|
||||
deleteVariable: variable => {
|
||||
get().findAndModifyVariable(
|
||||
variable.groupId,
|
||||
item => item.variableId === variable.variableId,
|
||||
{ removeVariable: true, mark: 'deleteVariable' },
|
||||
);
|
||||
},
|
||||
findAndModifyVariable: (groupId, predicate, options) => {
|
||||
let foundVariable: Variable | null = null;
|
||||
|
||||
set(
|
||||
produce<VariableGroupsStore>(state => {
|
||||
const findInGroups = (groups: VariableGroup[]): boolean => {
|
||||
for (const group of groups) {
|
||||
if (group.groupId === groupId) {
|
||||
if (findInTree(group.varInfoList, predicate, options)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (group.subGroupList?.length) {
|
||||
if (findInGroups(group.subGroupList)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const findInTree = (
|
||||
variables: Variable[],
|
||||
predicateIn: (variable: Variable) => boolean,
|
||||
optionsIn?: {
|
||||
modifyVariable?: (variable: Variable) => void;
|
||||
removeVariable?: boolean;
|
||||
},
|
||||
): boolean => {
|
||||
for (let i = 0; i < variables.length; i++) {
|
||||
if (predicateIn(variables[i])) {
|
||||
foundVariable = cloneDeep(variables[i]);
|
||||
if (optionsIn?.removeVariable) {
|
||||
variables.splice(i, 1);
|
||||
}
|
||||
if (optionsIn?.modifyVariable) {
|
||||
optionsIn.modifyVariable(variables[i]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (variables[i].children?.length) {
|
||||
if (
|
||||
findInTree(variables[i].children, predicateIn, optionsIn)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
findInGroups(state.variableGroups);
|
||||
}),
|
||||
false,
|
||||
options?.mark || 'findVariableInTree',
|
||||
);
|
||||
|
||||
return foundVariable;
|
||||
},
|
||||
updateVariable: newVariable => {
|
||||
get().findAndModifyVariable(
|
||||
newVariable.groupId,
|
||||
variable => variable.variableId === newVariable.variableId,
|
||||
{
|
||||
mark: 'updateVariable',
|
||||
modifyVariable: variable => {
|
||||
Object.assign(variable, newVariable);
|
||||
get().updateMeta({
|
||||
variables: [variable],
|
||||
level: variable.meta.level,
|
||||
parentId: variable.parentId,
|
||||
});
|
||||
},
|
||||
},
|
||||
);
|
||||
},
|
||||
updateMeta: ({ variables, level = 0, parentId = '' }) => {
|
||||
variables.forEach(item => {
|
||||
item.meta.level = level;
|
||||
item.meta.hasObjectLike = ObjectLikeTypes.includes(item.type);
|
||||
item.parentId = parentId;
|
||||
if (item.children?.length) {
|
||||
get().updateMeta({
|
||||
variables: item.children,
|
||||
level: level + 1,
|
||||
parentId: item.variableId,
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
saveHistory: () => {
|
||||
set(
|
||||
produce<VariableGroupsStore>(state => {
|
||||
state.variableGroups.forEach(item => {
|
||||
traverse(item.varInfoList, itemIn => {
|
||||
itemIn.meta.isHistory = true;
|
||||
});
|
||||
});
|
||||
}),
|
||||
false,
|
||||
'saveHistory',
|
||||
);
|
||||
},
|
||||
getAllRootVariables: () => {
|
||||
const { variableGroups } = get();
|
||||
const res: Variable[] = [];
|
||||
traverse(
|
||||
variableGroups,
|
||||
item => {
|
||||
res.push(...item.varInfoList);
|
||||
},
|
||||
'subGroupList',
|
||||
);
|
||||
return res;
|
||||
},
|
||||
getAllVariables: () => {
|
||||
const { variableGroups } = get();
|
||||
const variables = variableGroups.map(item => item.varInfoList).flat();
|
||||
const res: Variable[] = [];
|
||||
traverse(
|
||||
variables,
|
||||
item => {
|
||||
res.push(item);
|
||||
},
|
||||
'children',
|
||||
);
|
||||
return res;
|
||||
},
|
||||
transformDto2Vo: data => {
|
||||
const transformedData = getGroupListByDto(data);
|
||||
// 在数据转换完成后,立即更新meta信息
|
||||
transformedData.forEach(group => {
|
||||
get().updateMeta({ variables: group.varInfoList });
|
||||
});
|
||||
return transformedData;
|
||||
},
|
||||
getDtoVariable: (variable: Variable) => getDtoVariable(variable),
|
||||
initStore: data => {
|
||||
const { transformDto2Vo } = get();
|
||||
const transformedData = transformDto2Vo(data.variableGroups);
|
||||
set(
|
||||
{
|
||||
variableGroups: transformedData,
|
||||
canEdit: data.canEdit,
|
||||
},
|
||||
false,
|
||||
'initStore',
|
||||
);
|
||||
},
|
||||
clear: () => {
|
||||
set({ ...getDefaultVariableGroupStore() }, false, 'clear');
|
||||
},
|
||||
})),
|
||||
{
|
||||
enabled: IS_DEV_MODE,
|
||||
name: 'knowledge.variableGroups',
|
||||
},
|
||||
),
|
||||
);
|
||||
@@ -0,0 +1,353 @@
|
||||
/*
|
||||
* 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 { nanoid } from 'nanoid';
|
||||
import {
|
||||
exhaustiveCheckSimple,
|
||||
safeAsyncThrow,
|
||||
} from '@coze-common/chat-area-utils';
|
||||
import { typeSafeJSONParse } from '@coze-arch/bot-utils';
|
||||
import {
|
||||
type project_memory as ProjectMemory,
|
||||
VariableChannel,
|
||||
VariableType,
|
||||
} from '@coze-arch/bot-api/memory';
|
||||
|
||||
import {
|
||||
VariableTypeDTO,
|
||||
type VariableSchemaDTO,
|
||||
ViewVariableType,
|
||||
} from '../types';
|
||||
import { type VariableGroup, type Variable } from '../store';
|
||||
|
||||
export const getGroupListByDto = (
|
||||
dtoGroups: ProjectMemory.GroupVariableInfo[],
|
||||
): VariableGroup[] => {
|
||||
const groups = dtoGroups?.map(group => {
|
||||
const baseGroupInfo = getBaseGroupInfoByDto(group);
|
||||
const { groupId } = baseGroupInfo;
|
||||
const varInfoList = getGroupVariableListByDto({
|
||||
group,
|
||||
groupId,
|
||||
});
|
||||
return {
|
||||
...baseGroupInfo,
|
||||
varInfoList,
|
||||
subGroupList: getSubGroupListByDto({
|
||||
group,
|
||||
groupId,
|
||||
}),
|
||||
};
|
||||
});
|
||||
return groups || [];
|
||||
};
|
||||
|
||||
const getBaseGroupInfoByDto = (
|
||||
group: Partial<ProjectMemory.GroupVariableInfo>,
|
||||
): Omit<VariableGroup, 'subGroupList' | 'varInfoList'> => {
|
||||
const {
|
||||
GroupName: groupName = '',
|
||||
GroupDesc: groupDesc = '',
|
||||
GroupExtDesc: groupExtDesc = '',
|
||||
IsReadOnly: isReadOnly = false,
|
||||
DefaultChannel: channel = VariableChannel.Custom,
|
||||
} = group;
|
||||
const groupId = nanoid();
|
||||
return {
|
||||
groupId,
|
||||
groupName,
|
||||
groupDesc,
|
||||
groupExtDesc,
|
||||
channel,
|
||||
isReadOnly,
|
||||
raw: group,
|
||||
};
|
||||
};
|
||||
|
||||
const getGroupVariableListByDto = ({
|
||||
group,
|
||||
groupId,
|
||||
}: {
|
||||
group: Partial<ProjectMemory.GroupVariableInfo>;
|
||||
groupId: string;
|
||||
}): Variable[] => {
|
||||
const { VarInfoList: varInfoList = [] } = group;
|
||||
return (
|
||||
varInfoList?.map(dtoVariable =>
|
||||
getViewVariableByDto(dtoVariable, groupId),
|
||||
) ?? []
|
||||
);
|
||||
};
|
||||
|
||||
const getSubGroupListByDto = ({
|
||||
group,
|
||||
groupId,
|
||||
}: {
|
||||
group: Partial<ProjectMemory.GroupVariableInfo>;
|
||||
groupId: string;
|
||||
}): VariableGroup[] => {
|
||||
const { SubGroupList: subGroupList = [] } = group;
|
||||
return (
|
||||
subGroupList?.map(subGroup => ({
|
||||
...getBaseGroupInfoByDto({
|
||||
...subGroup,
|
||||
DefaultChannel: group.DefaultChannel, // 服务端返回的 subGroup 没有 DefaultChannel需要手动设置
|
||||
}),
|
||||
groupId,
|
||||
varInfoList: getGroupVariableListByDto({
|
||||
group: subGroup,
|
||||
groupId,
|
||||
}),
|
||||
subGroupList: [],
|
||||
})) ?? []
|
||||
);
|
||||
};
|
||||
|
||||
export function getViewVariableByDto(
|
||||
dtoVariable: ProjectMemory.Variable,
|
||||
groupId: string,
|
||||
): Variable {
|
||||
const variableSchema = typeSafeJSONParse(
|
||||
dtoVariable.Schema || '{}',
|
||||
) as VariableSchemaDTO;
|
||||
|
||||
const { type } = variableSchema;
|
||||
|
||||
const baseVariable = createBaseVariable({
|
||||
dtoVariable,
|
||||
groupId,
|
||||
});
|
||||
|
||||
if (type === VariableTypeDTO.List) {
|
||||
return convertListVariable(baseVariable, variableSchema);
|
||||
}
|
||||
|
||||
if (type === VariableTypeDTO.Object) {
|
||||
return convertObjectVariable(baseVariable, variableSchema);
|
||||
}
|
||||
|
||||
return {
|
||||
...baseVariable,
|
||||
type: dTOTypeToViewType(variableSchema.type),
|
||||
children: [],
|
||||
};
|
||||
}
|
||||
|
||||
export function dTOTypeToViewType(
|
||||
type: VariableTypeDTO,
|
||||
{
|
||||
arrayItemType,
|
||||
}: {
|
||||
arrayItemType?: VariableTypeDTO;
|
||||
} = {},
|
||||
): ViewVariableType {
|
||||
switch (type) {
|
||||
case VariableTypeDTO.Boolean:
|
||||
return ViewVariableType.Boolean;
|
||||
case VariableTypeDTO.Integer:
|
||||
return ViewVariableType.Integer;
|
||||
case VariableTypeDTO.Float:
|
||||
return ViewVariableType.Number;
|
||||
case VariableTypeDTO.String:
|
||||
return ViewVariableType.String;
|
||||
case VariableTypeDTO.Object:
|
||||
return ViewVariableType.Object;
|
||||
case VariableTypeDTO.List:
|
||||
if (!arrayItemType) {
|
||||
throw new Error(
|
||||
`Unkown variable DTO list need sub type but get ${arrayItemType}`,
|
||||
);
|
||||
}
|
||||
|
||||
switch (arrayItemType) {
|
||||
case VariableTypeDTO.Boolean:
|
||||
return ViewVariableType.ArrayBoolean;
|
||||
case VariableTypeDTO.Integer:
|
||||
return ViewVariableType.ArrayInteger;
|
||||
case VariableTypeDTO.Float:
|
||||
return ViewVariableType.ArrayNumber;
|
||||
case VariableTypeDTO.String:
|
||||
return ViewVariableType.ArrayString;
|
||||
case VariableTypeDTO.Object:
|
||||
return ViewVariableType.ArrayObject;
|
||||
case VariableTypeDTO.List:
|
||||
safeAsyncThrow(
|
||||
`List type variable can't have sub list type: ${type}:${arrayItemType}`,
|
||||
);
|
||||
return ViewVariableType.String;
|
||||
default:
|
||||
exhaustiveCheckSimple(arrayItemType);
|
||||
safeAsyncThrow(`Unknown variable DTO Type: ${type}:${arrayItemType}`);
|
||||
return ViewVariableType.String;
|
||||
}
|
||||
default:
|
||||
exhaustiveCheckSimple(type);
|
||||
safeAsyncThrow(`Unknown variable DTO Type: ${type}:${arrayItemType}`);
|
||||
return ViewVariableType.String;
|
||||
}
|
||||
}
|
||||
|
||||
function createBaseVariable({
|
||||
dtoVariable,
|
||||
groupId,
|
||||
}: {
|
||||
dtoVariable: ProjectMemory.Variable;
|
||||
groupId: string;
|
||||
}): Omit<Variable, 'type' | 'children'> {
|
||||
return {
|
||||
variableId: nanoid(),
|
||||
name: dtoVariable.Keyword ?? '',
|
||||
description: dtoVariable.Description ?? '',
|
||||
enabled: dtoVariable.Enable ?? true,
|
||||
defaultValue: dtoVariable.DefaultValue ?? '',
|
||||
channel: dtoVariable.Channel ?? VariableChannel.Custom,
|
||||
effectiveChannelList: dtoVariable.EffectiveChannelList ?? [],
|
||||
variableType: dtoVariable.VariableType ?? VariableType.KVVariable,
|
||||
readonly: dtoVariable.IsReadOnly ?? false,
|
||||
groupId,
|
||||
parentId: '',
|
||||
meta: {
|
||||
isHistory: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function convertListVariable(
|
||||
baseVariable: Omit<Variable, 'type' | 'children'>,
|
||||
variableSchema: VariableSchemaDTO,
|
||||
): Variable {
|
||||
const subVariableSchema = variableSchema.schema as VariableSchemaDTO;
|
||||
|
||||
const { type: subVariableType } = subVariableSchema;
|
||||
|
||||
if (subVariableType === VariableTypeDTO.Object) {
|
||||
return convertListObjectVariable(baseVariable, variableSchema);
|
||||
}
|
||||
|
||||
return {
|
||||
...baseVariable,
|
||||
type: dTOTypeToViewType(variableSchema.type, {
|
||||
arrayItemType: subVariableType,
|
||||
}),
|
||||
children: [],
|
||||
} as unknown as Variable;
|
||||
}
|
||||
|
||||
/**
|
||||
*@example schema: array<object>
|
||||
{
|
||||
"type": "list",
|
||||
"name": "arr_obj",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"schema": [{
|
||||
"type": "string",
|
||||
"name": "name",
|
||||
"required": false
|
||||
}, {
|
||||
"type": "integer",
|
||||
"name": "age",
|
||||
"required": false
|
||||
}]
|
||||
},
|
||||
}
|
||||
*/
|
||||
function convertListObjectVariable(
|
||||
baseVariable: Omit<Variable, 'type' | 'children'>,
|
||||
variableSchema: VariableSchemaDTO,
|
||||
): Variable {
|
||||
const subVariableSchema = variableSchema.schema;
|
||||
|
||||
if (!subVariableSchema) {
|
||||
throw new Error('List object variable schema is invalid');
|
||||
}
|
||||
|
||||
const { type: subVariableType } = subVariableSchema;
|
||||
|
||||
return {
|
||||
...baseVariable,
|
||||
type: dTOTypeToViewType(VariableTypeDTO.List, {
|
||||
arrayItemType: subVariableType,
|
||||
}),
|
||||
children: Array.isArray(subVariableSchema.schema)
|
||||
? subVariableSchema.schema.map(schema =>
|
||||
createVariableBySchema(schema, {
|
||||
groupId: baseVariable.groupId,
|
||||
parentId: baseVariable.variableId,
|
||||
}),
|
||||
)
|
||||
: [],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @example schema: object
|
||||
* object
|
||||
{
|
||||
"type": "object",
|
||||
"name": "obj",
|
||||
"schema": [{
|
||||
"type": "string",
|
||||
"name": "name",
|
||||
"required": false
|
||||
}, {
|
||||
"type": "integer",
|
||||
"name": "age",
|
||||
"required": false
|
||||
}],
|
||||
}
|
||||
* @returns
|
||||
*/
|
||||
function convertObjectVariable(
|
||||
baseVariable: Omit<Variable, 'type' | 'children'>,
|
||||
variableSchema: VariableSchemaDTO,
|
||||
): Variable {
|
||||
const schema = variableSchema.schema || [];
|
||||
|
||||
return {
|
||||
...baseVariable,
|
||||
type: dTOTypeToViewType(variableSchema.type),
|
||||
children: Array.isArray(schema)
|
||||
? schema.map(subMeta =>
|
||||
createVariableBySchema(subMeta, {
|
||||
groupId: baseVariable.groupId,
|
||||
parentId: baseVariable.variableId,
|
||||
}),
|
||||
)
|
||||
: [],
|
||||
};
|
||||
}
|
||||
function createVariableBySchema(
|
||||
subMeta: VariableSchemaDTO,
|
||||
{
|
||||
groupId,
|
||||
parentId,
|
||||
}: {
|
||||
groupId: string;
|
||||
parentId: string;
|
||||
},
|
||||
): Variable {
|
||||
return getViewVariableByDto(
|
||||
{
|
||||
Keyword: subMeta.name,
|
||||
Description: subMeta.description,
|
||||
Schema: JSON.stringify(subMeta),
|
||||
Enable: true,
|
||||
IsReadOnly: subMeta.readonly,
|
||||
},
|
||||
groupId,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* 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 {
|
||||
exhaustiveCheckSimple,
|
||||
safeAsyncThrow,
|
||||
} from '@coze-common/chat-area-utils';
|
||||
import { type project_memory as ProjectMemory } from '@coze-arch/bot-api/memory';
|
||||
|
||||
import { type VariableSchemaDTO, VariableTypeDTO } from '../types';
|
||||
import { type Variable } from '../store';
|
||||
|
||||
/**
|
||||
* 前端变量类型
|
||||
*/
|
||||
export enum ViewVariableType {
|
||||
String = 1,
|
||||
Integer,
|
||||
Boolean,
|
||||
Number,
|
||||
Object = 6,
|
||||
// 上面是 api 中定义的 InputType。下面是整合后的。从 99 开始,避免和后端定义撞车
|
||||
ArrayString = 99,
|
||||
ArrayInteger,
|
||||
ArrayBoolean,
|
||||
ArrayNumber,
|
||||
ArrayObject,
|
||||
}
|
||||
|
||||
export function viewTypeToDTO(type: ViewVariableType): {
|
||||
type: VariableTypeDTO;
|
||||
arrayItemType?: VariableTypeDTO;
|
||||
} {
|
||||
switch (type) {
|
||||
case ViewVariableType.Boolean:
|
||||
return { type: VariableTypeDTO.Boolean };
|
||||
case ViewVariableType.Integer:
|
||||
return { type: VariableTypeDTO.Integer };
|
||||
case ViewVariableType.Number:
|
||||
return { type: VariableTypeDTO.Float };
|
||||
case ViewVariableType.String:
|
||||
return { type: VariableTypeDTO.String };
|
||||
case ViewVariableType.Object:
|
||||
return { type: VariableTypeDTO.Object };
|
||||
case ViewVariableType.ArrayBoolean:
|
||||
return {
|
||||
type: VariableTypeDTO.List,
|
||||
arrayItemType: VariableTypeDTO.Boolean,
|
||||
};
|
||||
case ViewVariableType.ArrayInteger:
|
||||
return {
|
||||
type: VariableTypeDTO.List,
|
||||
arrayItemType: VariableTypeDTO.Integer,
|
||||
};
|
||||
case ViewVariableType.ArrayNumber:
|
||||
return {
|
||||
type: VariableTypeDTO.List,
|
||||
arrayItemType: VariableTypeDTO.Float,
|
||||
};
|
||||
case ViewVariableType.ArrayString:
|
||||
return {
|
||||
type: VariableTypeDTO.List,
|
||||
arrayItemType: VariableTypeDTO.String,
|
||||
};
|
||||
case ViewVariableType.ArrayObject:
|
||||
return {
|
||||
type: VariableTypeDTO.List,
|
||||
arrayItemType: VariableTypeDTO.Object,
|
||||
};
|
||||
default:
|
||||
exhaustiveCheckSimple(type);
|
||||
safeAsyncThrow(`Unknown view variable type: ${type}`);
|
||||
return { type: VariableTypeDTO.String };
|
||||
}
|
||||
}
|
||||
|
||||
export const getDtoVariable = (
|
||||
viewVariable: Variable,
|
||||
): ProjectMemory.Variable => {
|
||||
const { type, arrayItemType } = viewTypeToDTO(viewVariable.type);
|
||||
|
||||
const schema: VariableSchemaDTO = {
|
||||
name: viewVariable.name,
|
||||
enable: viewVariable.enabled,
|
||||
description: viewVariable.description || '',
|
||||
type,
|
||||
readonly: Boolean(viewVariable.readonly),
|
||||
schema: '',
|
||||
};
|
||||
|
||||
// 处理数组类型
|
||||
if (type === VariableTypeDTO.List && arrayItemType) {
|
||||
if (arrayItemType === VariableTypeDTO.Object) {
|
||||
schema.schema = {
|
||||
type: VariableTypeDTO.Object,
|
||||
schema: viewVariable.children?.map(child => {
|
||||
const childDTO = getDtoVariable(child);
|
||||
return JSON.parse(childDTO.Schema || '{}');
|
||||
}),
|
||||
};
|
||||
} else {
|
||||
schema.schema = {
|
||||
type: arrayItemType,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 处理对象类型
|
||||
if (type === VariableTypeDTO.Object) {
|
||||
schema.schema = viewVariable.children?.map(child => {
|
||||
const childDTO = getDtoVariable(child);
|
||||
return JSON.parse(childDTO.Schema || '{}');
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
Keyword: viewVariable.name,
|
||||
Channel: viewVariable.channel,
|
||||
VariableType: viewVariable.variableType ?? 1,
|
||||
DefaultValue: viewVariable.defaultValue,
|
||||
Description: viewVariable.description,
|
||||
EffectiveChannelList: viewVariable.effectiveChannelList,
|
||||
Enable: Boolean(viewVariable.enabled),
|
||||
IsReadOnly: Boolean(viewVariable.readonly),
|
||||
Schema: JSON.stringify(schema, null, 0),
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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 enum VariableTypeDTO {
|
||||
Object = 'object',
|
||||
List = 'list',
|
||||
String = 'string',
|
||||
Integer = 'integer',
|
||||
Boolean = 'boolean',
|
||||
Float = 'float',
|
||||
}
|
||||
|
||||
export interface VariableSchemaDTO {
|
||||
type: VariableTypeDTO;
|
||||
name: string;
|
||||
enable: boolean;
|
||||
description: string;
|
||||
readonly: boolean;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
schema?: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* 前端变量类型
|
||||
*/
|
||||
export enum ViewVariableType {
|
||||
String = 1,
|
||||
Integer,
|
||||
Boolean,
|
||||
Number,
|
||||
Object = 6,
|
||||
// 上面是 api 中定义的 InputType。下面是整合后的。从 99 开始,避免和后端定义撞车
|
||||
ArrayString = 99,
|
||||
ArrayInteger,
|
||||
ArrayBoolean,
|
||||
ArrayNumber,
|
||||
ArrayObject,
|
||||
}
|
||||
|
||||
export const BASE_ARRAY_PAIR: [ViewVariableType, ViewVariableType][] = [
|
||||
[ViewVariableType.String, ViewVariableType.ArrayString],
|
||||
[ViewVariableType.Integer, ViewVariableType.ArrayInteger],
|
||||
[ViewVariableType.Boolean, ViewVariableType.ArrayBoolean],
|
||||
[ViewVariableType.Number, ViewVariableType.ArrayNumber],
|
||||
[ViewVariableType.Object, ViewVariableType.ArrayObject],
|
||||
];
|
||||
|
||||
export const VARIABLE_TYPE_ALIAS_MAP: Record<ViewVariableType, string> = {
|
||||
[ViewVariableType.String]: 'String',
|
||||
[ViewVariableType.Integer]: 'Integer',
|
||||
[ViewVariableType.Boolean]: 'Boolean',
|
||||
[ViewVariableType.Number]: 'Number',
|
||||
[ViewVariableType.Object]: 'Object',
|
||||
[ViewVariableType.ArrayString]: 'Array<String>',
|
||||
[ViewVariableType.ArrayInteger]: 'Array<Integer>',
|
||||
[ViewVariableType.ArrayBoolean]: 'Array<Boolean>',
|
||||
[ViewVariableType.ArrayNumber]: 'Array<Number>',
|
||||
[ViewVariableType.ArrayObject]: 'Array<Object>',
|
||||
};
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
export namespace ViewVariableType {
|
||||
/**
|
||||
* 获取所有变量类型的补集
|
||||
* @param inputTypes
|
||||
*/
|
||||
export function getComplement(inputTypes: ViewVariableType[]) {
|
||||
const allTypes: ViewVariableType[] = [
|
||||
...BASE_ARRAY_PAIR.map(_pair => _pair[0]),
|
||||
...BASE_ARRAY_PAIR.map(_pair => _pair[1]),
|
||||
];
|
||||
|
||||
return allTypes.filter(type => !inputTypes.includes(type));
|
||||
}
|
||||
|
||||
export function isArrayType(type: ViewVariableType): boolean {
|
||||
const arrayTypes = BASE_ARRAY_PAIR.map(_pair => _pair[1]);
|
||||
return arrayTypes.includes(type);
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
export const ObjectLikeTypes = [
|
||||
ViewVariableType.Object,
|
||||
ViewVariableType.ArrayObject,
|
||||
];
|
||||
Reference in New Issue
Block a user