UNPKG

@hashgraphonline/conversational-agent

Version:

Hashgraph Online conversational AI agent implementing HCS-10 communication, HCS-2 registries, and content inscription on Hedera. https://hol.org

320 lines (319 loc) 8.87 kB
import { ZodError } from "zod"; import { Logger } from "@hashgraphonline/standards-sdk"; import { FormGenerator } from "./index11.js"; import { isFormValidatable } from "@hashgraphonline/standards-agent-kit"; class FormEngine { constructor(logger) { this.formGenerator = new FormGenerator(); this.logger = logger || new Logger({ module: "FormEngine" }); } /** * Generate a form for a tool with the given input */ async generateForm(toolName, tool, input, context) { const fullContext = { tool, input, ...context }; try { if (isFormValidatable(tool)) { return await this.generateFormValidatableForm(tool, input, fullContext); } if (input instanceof ZodError) { return await this.generateErrorBasedForm(tool, input, fullContext); } if (this.hasRenderConfig(tool)) { return await this.generateRenderConfigForm(tool, input, fullContext); } if (this.isZodObject(tool.schema)) { return await this.generateSchemaBasedForm(tool, input, fullContext); } return null; } catch (error) { this.logger.error(`Failed to generate form for tool: ${toolName}`, { error: error instanceof Error ? error.message : String(error) }); throw error; } } /** * Process a form submission */ async processSubmission(submission, context) { this.validateSubmission(submission); const baseToolInput = this.extractBaseToolInput(context); const submissionData = this.extractSubmissionData(submission); return this.mergeInputData(baseToolInput, submissionData); } /** * Check if a tool requires form generation based on input */ shouldGenerateForm(tool, input) { const inputRecord = input; if (inputRecord?.__fromForm === true || inputRecord?.renderForm === false) { return false; } if (isFormValidatable(tool)) { try { const formValidatableTool = tool; return formValidatableTool.shouldGenerateForm(input); } catch (error) { this.logger.error( `Error calling shouldGenerateForm() on ${tool.name}:`, error ); return false; } } const validation = this.validateInput(tool, input); return !validation.isValid; } /** * Generate form from error context */ async generateFormFromError(error, toolName, toolSchema, originalPrompt) { return this.formGenerator.generateFormFromError( error, toolSchema, toolName, originalPrompt ); } /** * Generate form for FormValidatable tools */ async generateFormValidatableForm(tool, input, _context) { const { schemaToUse, isFocusedSchema } = this.resolveFormSchema(tool); const missingFields = this.determineMissingFields( tool, input, schemaToUse, isFocusedSchema ); return this.generateFormWithSchema(tool, input, schemaToUse, missingFields); } /** * Generate form based on schema validation */ async generateSchemaBasedForm(tool, input, context) { const schema = tool.schema; const formMessage = await this.formGenerator.generateFormFromSchema( schema, input, { toolName: tool.name, toolDescription: tool.description }, context.missingFields ); if (this.isZodObject(schema)) { try { const { jsonSchema, uiSchema } = this.formGenerator.generateJsonSchemaForm( schema, input, context.missingFields || /* @__PURE__ */ new Set() ); formMessage.jsonSchema = jsonSchema; formMessage.uiSchema = uiSchema; } catch (error) { this.logger.warn( "Failed to generate JSON Schema for schema-based tool:", error ); } } formMessage.partialInput = input; return formMessage; } /** * Generate form based on render config */ async generateRenderConfigForm(tool, input, context) { const schema = tool.schema; const renderConfig = this.extractRenderConfig(tool); const formMessage = await this.formGenerator.generateFormFromSchema( schema, input, { toolName: tool.name, toolDescription: tool.description }, context.missingFields ); if (renderConfig) { formMessage.formConfig.metadata = { ...formMessage.formConfig.metadata, renderConfig }; } formMessage.partialInput = input; return formMessage; } /** * Generate form from Zod validation error */ async generateErrorBasedForm(tool, error, context) { return this.formGenerator.generateFormFromError( error, tool.schema, tool.name, context.input ? String(context.input) : "" ); } /** * Validate input against tool schema */ validateInput(tool, input) { try { const zodSchema = tool.schema; zodSchema.parse(input); return { isValid: true }; } catch (error) { if (error instanceof ZodError) { const errors = error.errors.map( (err) => `${err.path.join(".")}: ${err.message}` ); return { isValid: false, errors }; } return { isValid: false, errors: ["Validation failed"] }; } } /** * Check if schema is ZodObject */ isZodObject(schema) { if (!schema || typeof schema !== "object") { return false; } const candidate = schema; return Boolean(candidate._def && candidate._def.typeName === "ZodObject"); } /** * Check if tool has render configuration */ hasRenderConfig(tool) { const schema = tool.schema; return !!(schema && schema._renderConfig); } /** * Extract render configuration from tool */ extractRenderConfig(tool) { const schema = tool.schema; return schema?._renderConfig; } /** * Resolve form schema for FormValidatable tools */ resolveFormSchema(tool) { const formValidatableTool = tool; if (formValidatableTool.getFormSchema) { const focusedSchema = formValidatableTool.getFormSchema(); if (focusedSchema) { return { schemaToUse: focusedSchema, isFocusedSchema: true }; } } return { schemaToUse: tool.schema, isFocusedSchema: false }; } /** * Determine missing fields for form generation */ determineMissingFields(tool, input, _schema, _isFocusedSchema) { const missingFields = /* @__PURE__ */ new Set(); if (!input || typeof input !== "object") { return missingFields; } const inputRecord = input; const formValidatableTool = tool; if (formValidatableTool.getEssentialFields) { const essentialFields = formValidatableTool.getEssentialFields(); for (const field of essentialFields) { if (!(field in inputRecord) || formValidatableTool.isFieldEmpty && formValidatableTool.isFieldEmpty(field, inputRecord[field])) { missingFields.add(field); } } } return missingFields; } /** * Generate form with resolved schema */ async generateFormWithSchema(tool, input, schema, missingFields) { const formMessage = await this.formGenerator.generateFormFromSchema( schema, input, { toolName: tool.name, toolDescription: tool.description }, missingFields ); if (this.isZodObject(schema)) { try { const { jsonSchema, uiSchema } = this.formGenerator.generateJsonSchemaForm( schema, input, missingFields ); formMessage.jsonSchema = jsonSchema; formMessage.uiSchema = uiSchema; } catch (error) { this.logger.warn("Failed to generate JSON Schema:", error); } } formMessage.partialInput = input; return formMessage; } /** * Validate form submission */ validateSubmission(submission) { if (!submission.toolName) { throw new Error("Tool name is required in form submission"); } if (!submission.parameters) { throw new Error("Parameters are required in form submission"); } } /** * Extract base tool input from context */ extractBaseToolInput(context) { return context?.originalInput || {}; } /** * Extract submission data */ extractSubmissionData(submission) { return { ...submission.parameters, __fromForm: true }; } /** * Merge input data */ mergeInputData(baseInput, submissionData) { return { ...baseInput, ...submissionData }; } /** * Get registered strategies */ getRegisteredStrategies() { return ["FormValidatable", "SchemaBased", "RenderConfig", "ZodErrorBased"]; } /** * Get registered middleware */ getRegisteredMiddleware() { return ["FormSubmissionValidator"]; } } export { FormEngine }; //# sourceMappingURL=index12.js.map