@autobe/agent
Version:
AI backend server code generator
173 lines (161 loc) • 6.42 kB
text/typescript
import {
AutoBeOpenApi,
AutoBeProgressEventBase,
AutoBeRealizeCollectorFunction,
} 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 { transformRealizeCollectorCorrectHistory } from "./histories/transformRealizeCollectorCorrectHistory";
import { AutoBeRealizeCollectorProgrammer } from "./programmers/AutoBeRealizeCollectorProgrammer";
import { IAutoBeRealizeCollectorCorrectApplication } from "./structures/IAutoBeRealizeCollectorCorrectApplication";
import { IAutoBeRealizeFunctionResult } from "./structures/IAutoBeRealizeFunctionResult";
export const orchestrateRealizeCollectorCorrectOverall = async (
ctx: AutoBeContext,
props: {
functions: AutoBeRealizeCollectorFunction[];
progress: AutoBeProgressEventBase;
},
): Promise<IAutoBeRealizeFunctionResult<AutoBeRealizeCollectorFunction>[]> => {
const document: AutoBeOpenApi.IDocument = ctx.state().interface!.document;
const getNeighbors = (
func: AutoBeRealizeCollectorFunction,
): AutoBeRealizeCollectorFunction[] => {
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/collectors",
// Recalculate template for corrected collector function
template: (func) =>
AutoBeRealizeCollectorProgrammer.writeTemplate({
plan: func.plan,
body: document.components.schemas[func.plan.dtoTypeName],
model: ctx
.state()
.database!.result.data.files.map((f) => f.models)
.flat()
.find((m) => m.name === func.plan.databaseSchemaName)!,
application: ctx.state().database!.result.data,
}),
// Replace import statements using Collector-specific programmer
replaceImportStatements: async (next) => {
return await AutoBeRealizeCollectorProgrammer.replaceImportStatements(
ctx,
{
dtoTypeName: next.function.plan.dtoTypeName,
schemas: document.components.schemas,
code: next.code,
},
);
},
// No additional files needed for collectors (unlike operations)
additional: (_functions) => ({}),
// Create preliminary controller with only databaseSchemas support
preliminary: (next) =>
new AutoBePreliminaryController<"databaseSchemas">({
source: next.source,
application:
typia.json.application<IAutoBeRealizeCollectorCorrectApplication>(),
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 Collector-specific transformer
histories: (next) =>
transformRealizeCollectorCorrectHistory(ctx, {
function: next.function,
neighbors: getNeighbors(next.function),
failures: next.failures,
preliminary: next.preliminary,
}),
// Create controller with Collector-specific validation
controller: (next) => {
const validate: Validator = (input) => {
const result: IValidation<IAutoBeRealizeCollectorCorrectApplication.IProps> =
typia.validate<IAutoBeRealizeCollectorCorrectApplication.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 collector-specific constraints
const errors: IValidation.IError[] =
AutoBeRealizeCollectorProgrammer.validate({
plan: next.function.plan,
mappings: result.data.request.mappings,
neighbors: props.functions.map((f) => f.plan),
draft: result.data.request.draft,
revise: result.data.request.revise,
application: ctx.state().database!.result.data,
});
return errors.length
? {
success: false,
errors,
data: result.data,
}
: result;
};
const application: ILlmApplication = next.preliminary.fixApplication(
typia.llm.application<IAutoBeRealizeCollectorCorrectApplication>({
validate: {
process: validate,
},
}),
);
AutoBeRealizeCollectorProgrammer.fixApplication({
definition: application,
application: ctx.state().database!.result.data,
model: ctx
.state()
.database!.result.data.files.map((f) => f.models)
.flat()
.find((m) => m.name === next.function.plan.databaseSchemaName)!,
});
return {
protocol: "class",
name: next.source,
application,
execute: {
process: (v) => {
if (v.request.type === "write") next.build(v.request);
},
} satisfies IAutoBeRealizeCollectorCorrectApplication,
};
},
},
functions: props.functions,
progress: props.progress,
});
};
type Validator = (
input: unknown,
) => IValidation<IAutoBeRealizeCollectorCorrectApplication.IProps>;