UNPKG

@autobe/agent

Version:

AI backend server code generator

191 lines (157 loc) 6.63 kB
import { AutoBeDatabase, AutoBeOpenApi } from "@autobe/interface"; import { StringUtil } from "@autobe/utils"; import { v7 } from "uuid"; import { AutoBeSystemPromptConstant } from "../../../constants/AutoBeSystemPromptConstant"; import { AutoBeState } from "../../../context/AutoBeState"; import { IAutoBeOrchestrateHistory } from "../../../structures/IAutoBeOrchestrateHistory"; import { AutoBePreliminaryController } from "../../common/AutoBePreliminaryController"; import { transformInterfaceOperationParameterHistory } from "./transformInterfaceOperationParameterHistory"; export const transformInterfaceSchemaRefineHistory = (props: { state: AutoBeState; instruction: string; preliminary: AutoBePreliminaryController< | "analysisSections" | "databaseSchemas" | "interfaceOperations" | "interfaceSchemas" | "previousAnalysisSections" | "previousDatabaseSchemas" | "previousInterfaceOperations" | "previousInterfaceSchemas" | "complete" >; typeName: string; operations: AutoBeOpenApi.IOperation[]; schema: AutoBeOpenApi.IJsonSchema.IObject; }): IAutoBeOrchestrateHistory => { const everyModels: AutoBeDatabase.IModel[] = props.state.database?.result.data.files.flatMap((f) => f.models) ?? []; const model: AutoBeDatabase.IModel | undefined = props.schema[ "x-autobe-database-schema" ] ? everyModels.find( (m) => m.name === props.schema["x-autobe-database-schema"], ) : undefined; const result: IAutoBeOrchestrateHistory = { histories: [ { type: "systemMessage", id: v7(), created_at: new Date().toISOString(), text: AutoBeSystemPromptConstant.INTERFACE_SCHEMA_REFINE, }, ...props.preliminary.getHistories(), { type: "assistantMessage", id: v7(), created_at: new Date().toISOString(), text: StringUtil.trim` ## API Design Instructions The following API-specific instructions were extracted from the user's requirements. These focus on API interface design aspects relevant to the refinement task. Follow these instructions when enriching schemas with documentation and metadata. Carefully distinguish between: - Suggestions or recommendations (consider these as guidance) - Direct specifications or explicit commands (these must be followed exactly) When instructions contain direct specifications or explicit design decisions, follow them precisely even if you believe you have better alternatives. ${props.instruction} `, }, { id: v7(), type: "assistantMessage", created_at: new Date().toISOString(), text: StringUtil.trim` ## Operations (Filtered for Target Schema) Here are the API operations that directly use the schema to refine. These operations reference the target schema "${props.typeName}" via requestBody.typeName or responseBody.typeName. This FILTERED list helps you understand the exact usage context for the schema you're enriching: \`\`\`json ${JSON.stringify(props.operations)} \`\`\` ${transformInterfaceOperationParameterHistory({ typeName: props.typeName, operations: props.operations, })} ## DTO type to refine Here is the SPECIFIC schema that needs refinement for type "${props.typeName}": \`\`\`json ${JSON.stringify(props.schema)} \`\`\` Also, here is the list of properties currently defined in this schema, so you have to enrich them one by one. Note that, only this schema needs refinement. Other schemas in the complete schema set are provided for reference only. ${Object.keys(props.schema.properties) .map((k) => `- ${k}`) .join("\n")} ${transformDatabaseSchemaProperties({ everyModels, model, })} `, }, ], userMessage: StringUtil.trim` Refine ${JSON.stringify(props.typeName)} schema by enriching each property with \`databaseSchemaProperty\`, \`specification\`, and \`description\`. **Object-level**: \`databaseSchema\` (nullable), \`specification\` (MANDATORY), \`description\` (MANDATORY). **Property-level**: Use \`depict\`, \`create\`, \`update\`, or \`erase\` for each property in \`revises\`. DB properties not in this DTO go in \`excludes\`. When \`databaseSchemaProperty\` or \`databaseSchema\` is \`null\`, the \`specification\` becomes the ONLY source of truth for downstream agents. You MUST provide a refinement for every single property without exception: ${Object.keys(props.schema.properties) .map((k) => `- ${k}`) .join("\n")} ${transformDatabaseSchemaProperties({ everyModels, model, })} `, }; return result; }; function transformDatabaseSchemaProperties(props: { everyModels: AutoBeDatabase.IModel[]; model: AutoBeDatabase.IModel | undefined; }): string { if (props.model === undefined) return ""; // Columns: primary key, plain fields, FK columns const columns: string[] = [ props.model.primaryField.name, ...props.model.plainFields.map((f) => f.name), ...props.model.foreignFields.map((f) => f.name), ]; // Belongs-to relations (from FK) const belongsTo: string[] = props.model.foreignFields.map( (f) => f.relation.name, ); // Has-many/has-one relations (opposite side) const hasRelations: string[] = props.everyModels .flatMap((m) => m.foreignFields .filter((f) => f.relation.targetModel === props.model!.name) .map((f) => f.relation.oppositeName), ) .filter((name): name is string => name !== undefined); return StringUtil.trim` ## Database Schema Properties for \`${props.model.name}\` If you keep \`databaseSchema\` as \`${JSON.stringify(props.model.name)}\`, every DB property below must be explicitly handled: either mapped to a DTO property in \`revises\`, or declared in \`excludes\` with a reason. **Columns** (scalar fields): ${columns.map((c) => `- \`${c}\``).join("\n")} **Belongs-to Relations** (FK → object): ${belongsTo.length > 0 ? belongsTo.map((r) => `- \`${r}\``).join("\n") : "- (none)"} **Has-many/Has-one Relations** (reverse side): ${hasRelations.length > 0 ? hasRelations.map((r) => `- \`${r}\``).join("\n") : "- (none)"} `; }