Support define is tool logic function (#17926)
- supports isTool and timeout settings in defineLogicFunction in apps and in setting tabs definition - compute for all toolInputSchema for logic funciton, in settings and in code steps <img width="991" height="802" alt="image" src="https://github.com/user-attachments/assets/05dc1221-cac9-45a3-87b0-3b13161446fd" />
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
import {
|
||||
type ArrayTypeNode,
|
||||
type ArrowFunction,
|
||||
createSourceFile,
|
||||
type FunctionDeclaration,
|
||||
type FunctionLikeDeclaration,
|
||||
type LiteralTypeNode,
|
||||
type Node,
|
||||
type PropertySignature,
|
||||
ScriptTarget,
|
||||
type StringLiteral,
|
||||
SyntaxKind,
|
||||
type TypeNode,
|
||||
type UnionTypeNode,
|
||||
type VariableStatement,
|
||||
} from 'typescript';
|
||||
|
||||
import { type InputJsonSchema } from '@/logic-function';
|
||||
import { isDefined } from '@/utils/validation/isDefined';
|
||||
|
||||
const getTypeString = (typeNode: TypeNode): InputJsonSchema => {
|
||||
switch (typeNode.kind) {
|
||||
case SyntaxKind.NumberKeyword:
|
||||
return { type: 'number' };
|
||||
case SyntaxKind.StringKeyword:
|
||||
return { type: 'string' };
|
||||
case SyntaxKind.BooleanKeyword:
|
||||
return { type: 'boolean' };
|
||||
case SyntaxKind.ArrayType:
|
||||
return {
|
||||
type: 'array',
|
||||
items: getTypeString((typeNode as ArrayTypeNode).elementType),
|
||||
};
|
||||
case SyntaxKind.ObjectKeyword:
|
||||
return { type: 'object' };
|
||||
case SyntaxKind.TypeLiteral: {
|
||||
const properties: InputJsonSchema['properties'] = {};
|
||||
|
||||
(typeNode as any).members.forEach((member: PropertySignature) => {
|
||||
if (isDefined(member.name) && isDefined(member.type)) {
|
||||
const memberName = (member.name as any).text;
|
||||
|
||||
properties[memberName] = getTypeString(member.type);
|
||||
}
|
||||
});
|
||||
|
||||
return { type: 'object', properties };
|
||||
}
|
||||
case SyntaxKind.UnionType: {
|
||||
const unionNode = typeNode as UnionTypeNode;
|
||||
const enumValues: string[] = [];
|
||||
|
||||
let isEnum = true;
|
||||
|
||||
unionNode.types.forEach((subType) => {
|
||||
if (subType.kind === SyntaxKind.LiteralType) {
|
||||
const literal = (subType as LiteralTypeNode).literal;
|
||||
|
||||
if (literal.kind === SyntaxKind.StringLiteral) {
|
||||
enumValues.push((literal as StringLiteral).text);
|
||||
} else {
|
||||
isEnum = false;
|
||||
}
|
||||
} else {
|
||||
isEnum = false;
|
||||
}
|
||||
});
|
||||
|
||||
if (isEnum) {
|
||||
return { type: 'string', enum: enumValues };
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
const computeFunctionParameters = (
|
||||
funcNode: FunctionDeclaration | FunctionLikeDeclaration | ArrowFunction,
|
||||
schema: InputJsonSchema[],
|
||||
): InputJsonSchema[] => {
|
||||
const params = funcNode.parameters;
|
||||
|
||||
return params.reduce((updatedSchema, param) => {
|
||||
const typeNode = param.type;
|
||||
|
||||
if (isDefined(typeNode)) {
|
||||
return [...updatedSchema, getTypeString(typeNode)];
|
||||
} else {
|
||||
return [...updatedSchema, {}];
|
||||
}
|
||||
}, schema);
|
||||
};
|
||||
|
||||
const extractFunctions = (node: Node): FunctionLikeDeclaration[] => {
|
||||
if (node.kind === SyntaxKind.FunctionDeclaration) {
|
||||
return [node as FunctionDeclaration];
|
||||
}
|
||||
|
||||
if (node.kind === SyntaxKind.VariableStatement) {
|
||||
const varStatement = node as VariableStatement;
|
||||
|
||||
return varStatement.declarationList.declarations
|
||||
.filter(
|
||||
(declaration) =>
|
||||
isDefined(declaration.initializer) &&
|
||||
declaration.initializer.kind === SyntaxKind.ArrowFunction,
|
||||
)
|
||||
.map((declaration) => declaration.initializer as ArrowFunction);
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
export const getFunctionInputSchema = (
|
||||
fileContent: string,
|
||||
): InputJsonSchema[] => {
|
||||
const sourceFile = createSourceFile(
|
||||
'temp.ts',
|
||||
fileContent,
|
||||
ScriptTarget.ESNext,
|
||||
true,
|
||||
);
|
||||
let schema: InputJsonSchema[] = [];
|
||||
|
||||
sourceFile.forEachChild((node) => {
|
||||
if (
|
||||
node.kind === SyntaxKind.FunctionDeclaration ||
|
||||
node.kind === SyntaxKind.VariableStatement
|
||||
) {
|
||||
const functions = extractFunctions(node);
|
||||
|
||||
functions.forEach((func) => {
|
||||
schema = computeFunctionParameters(func, schema);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return schema;
|
||||
};
|
||||
Reference in New Issue
Block a user