@autobe/agent
Version:
AI backend server code generator
188 lines (175 loc) • 6.87 kB
text/typescript
import {
AutoBeDatabase,
AutoBeOpenApi,
AutoBeProgressEventBase,
AutoBeRealizeTransformerFunction,
} from "@autobe/interface";
import { AutoBeOpenApiTypeChecker } from "@autobe/utils";
import typia, { ILlmApplication, IValidation } from "typia";
import { AutoBeContext } from "../../context/AutoBeContext";
import { AutoBePreliminaryController } from "../common/AutoBePreliminaryController";
import { orchestrateRealizeCorrectOverall } from "./correct/orchestrateRealizeCorrectOverall";
import { transformRealizeTransformerCorrectHistory } from "./histories/transformRealizeTransformerCorrectHistory";
import { AutoBeRealizeTransformerProgrammer } from "./programmers/AutoBeRealizeTransformerProgrammer";
import { IAutoBeRealizeFunctionResult } from "./structures/IAutoBeRealizeFunctionResult";
import { IAutoBeRealizeTransformerCorrectApplication } from "./structures/IAutoBeRealizeTransformerCorrectApplication";
export const orchestrateRealizeTransformerCorrectOverall = async (
ctx: AutoBeContext,
props: {
functions: AutoBeRealizeTransformerFunction[];
progress: AutoBeProgressEventBase;
},
): Promise<
IAutoBeRealizeFunctionResult<AutoBeRealizeTransformerFunction>[]
> => {
const prismaApplication: AutoBeDatabase.IApplication =
ctx.state().database!.result.data;
const document: AutoBeOpenApi.IDocument = ctx.state().interface!.document;
const getNeighbors = (
func: AutoBeRealizeTransformerFunction,
): AutoBeRealizeTransformerFunction[] => {
const visited: Set<string> = new Set();
AutoBeOpenApiTypeChecker.visit({
components: document.components,
schema: { $ref: `#/components/schemas/${func.plan.dtoTypeName}` },
closure: (next) => {
if (AutoBeOpenApiTypeChecker.isReference(next)) {
const key: string = next.$ref.split("/").pop()!;
visited.add(key);
}
},
});
return props.functions.filter(
(y) =>
y.plan.dtoTypeName !== func.plan.dtoTypeName &&
visited.has(y.plan.dtoTypeName),
);
};
return await orchestrateRealizeCorrectOverall(ctx, {
programmer: {
location: "src/transformers",
// Recalculate template for corrected transformer function
template: (func) => {
const model: AutoBeDatabase.IModel = prismaApplication.files
.map((f) => f.models)
.flat()
.find((m) => m.name === func.plan.databaseSchemaName)!;
return AutoBeRealizeTransformerProgrammer.writeTemplate({
plan: func.plan,
schema: document.components.schemas[
func.plan.dtoTypeName
] as AutoBeOpenApi.IJsonSchemaDescriptive.IObject,
schemas: document.components.schemas,
neighbors: getNeighbors(func).map((n) => n.plan),
relations: AutoBeRealizeTransformerProgrammer.getRelationMappingTable(
{
application: prismaApplication,
model,
},
),
model,
});
},
// Replace import statements using Transformer-specific programmer
replaceImportStatements: async (next) => {
return await AutoBeRealizeTransformerProgrammer.replaceImportStatements(
ctx,
{
dtoTypeName: next.function.plan.dtoTypeName,
schemas: document.components.schemas,
code: next.code,
},
);
},
// No additional files needed for transformers (unlike operations)
additional: (_functions) => ({}),
// Create preliminary controller with only databaseSchemas support
preliminary: (next) =>
new AutoBePreliminaryController<"databaseSchemas">({
source: next.source,
application:
typia.json.application<IAutoBeRealizeTransformerCorrectApplication>(),
kinds: ["databaseSchemas"],
dispatch: (e) => ctx.dispatch(e),
state: ctx.state(),
local: {
databaseSchemas: ctx
.state()
.database!.result.data.files.map((f) => f.models)
.flat()
.filter((m) => m.name === next.function.plan.databaseSchemaName),
},
}),
// Transform history using Transformer-specific transformer
histories: (next) =>
transformRealizeTransformerCorrectHistory(ctx, {
function: next.function,
neighbors: getNeighbors(next.function),
failures: next.failures,
preliminary: next.preliminary,
}),
// Create controller with Transformer-specific validation
controller: (next) => {
const validate: Validator = (input) => {
const result: IValidation<IAutoBeRealizeTransformerCorrectApplication.IProps> =
typia.validate<IAutoBeRealizeTransformerCorrectApplication.IProps>(
input,
);
if (result.success === false) return result;
else if (result.data.request.type !== "write")
return next.preliminary.validate({
thinking: result.data.thinking,
request: result.data.request,
});
// Validate transformer-specific constraints
const errors: IValidation.IError[] =
AutoBeRealizeTransformerProgrammer.validate({
application: prismaApplication,
document,
plan: next.function.plan,
neighbors: props.functions.map((f) => f.plan),
transformMappings: result.data.request.transformMappings,
selectMappings: result.data.request.selectMappings,
draft: result.data.request.draft,
revise: result.data.request.revise,
});
return errors.length
? {
success: false,
errors,
data: result.data,
}
: result;
};
const application: ILlmApplication = next.preliminary.fixApplication(
typia.llm.application<IAutoBeRealizeTransformerCorrectApplication>({
validate: {
process: validate,
},
}),
);
AutoBeRealizeTransformerProgrammer.fixApplication({
definition: application,
application: prismaApplication,
document,
plan: next.function.plan,
});
return {
protocol: "class",
name: next.source,
application,
execute: {
process: (v) => {
if (v.request.type === "write") next.build(v.request);
},
} satisfies IAutoBeRealizeTransformerCorrectApplication,
};
},
},
functions: props.functions,
progress: props.progress,
});
};
type Validator = (
input: unknown,
) => IValidation<IAutoBeRealizeTransformerCorrectApplication.IProps>;