UNPKG

@autobe/agent

Version:

AI backend server code generator

220 lines (209 loc) 6.62 kB
import { AutoBeProgressEventBase, AutoBeTestValidateEvent, } from "@autobe/interface"; import { IPointer } from "tstl"; import { ILlmController } from "typia"; import { v7 } from "uuid"; import { AutoBeConfigConstant } from "../../../constants/AutoBeConfigConstant"; import { AutoBeContext } from "../../../context/AutoBeContext"; import { executeCachedBatch } from "../../../utils/executeCachedBatch"; import { transformTestCorrectOverallHistory } from "../histories/transformTestCorrectOverallHistory"; import { IAutoBeTestCorrectOverallApplication } from "../structures/IAutoBeTestCorrectOverallApplication"; import { IAutoBeTestFunctionFailure } from "../structures/IAutoBeTestFunctionFailure"; import { IAutoBeTestProcedure } from "../structures/IAutoBeTestProcedure"; interface IProgrammer< Procedure extends IAutoBeTestProcedure, Complete extends IAutoBeTestCorrectOverallApplication.IProps, > { controller(next: { procedure: Procedure; build: (next: Complete) => void; }): ILlmController; replaceImportStatements(procedure: Procedure): Promise<string>; compile( procedure: Procedure, ): Promise<AutoBeTestValidateEvent<Procedure["function"]>>; } export async function orchestrateTestCorrectOverall< Procedure extends IAutoBeTestProcedure, Complete extends IAutoBeTestCorrectOverallApplication.IProps, >( ctx: AutoBeContext, props: { programmer: IProgrammer<Procedure, Complete>; procedures: Procedure[]; instruction: string; progress: AutoBeProgressEventBase; discard: boolean; }, ): Promise<Procedure[]> { const results: Array<Procedure | null> = await executeCachedBatch( ctx, props.procedures.map((procedure) => async (promptCacheKey) => { try { const event: AutoBeTestValidateEvent<Procedure["function"]> = await predicate( ctx, { programmer: props.programmer, procedure, failures: [], validate: await compileWithFiltering({ compile: props.programmer.compile, procedure, }), promptCacheKey, instruction: props.instruction, }, AutoBeConfigConstant.COMPILER_RETRY, ); if (event.result.type === "failure" && props.discard) return null; return { ...procedure, function: event.function, }; } catch { if (props.discard) return null; else return procedure; } }), ); return results.filter((r) => r !== null); } async function predicate< Procedure extends IAutoBeTestProcedure, Complete extends IAutoBeTestCorrectOverallApplication.IProps, >( ctx: AutoBeContext, props: { programmer: IProgrammer<Procedure, Complete>; procedure: Procedure; failures: IAutoBeTestFunctionFailure[]; validate: AutoBeTestValidateEvent<Procedure["function"]>; promptCacheKey: string; instruction: string; }, life: number, ): Promise<AutoBeTestValidateEvent<Procedure["function"]>> { if (props.validate.result.type === "failure") { ctx.dispatch(props.validate); try { return await correct(ctx, props, life - 1); } catch (error) { console.log("testCorrectOverall", error); return await correct(ctx, props, life - 2); } } return props.validate; } async function correct< Procedure extends IAutoBeTestProcedure, Complete extends IAutoBeTestCorrectOverallApplication.IProps, >( ctx: AutoBeContext, props: { programmer: IProgrammer<Procedure, Complete>; procedure: Procedure; failures: IAutoBeTestFunctionFailure<Procedure>[]; validate: AutoBeTestValidateEvent<Procedure["function"]>; promptCacheKey: string; instruction: string; }, life: number, ): Promise<AutoBeTestValidateEvent<Procedure["function"]>> { if (props.validate.result.type !== "failure") return props.validate; else if (life < 0) return props.validate; const pointer: IPointer<Complete | null> = { value: null, }; const { metric, tokenUsage } = await ctx.conversate({ source: "testCorrect", controller: props.programmer.controller({ procedure: props.procedure, build: (next) => { pointer.value = next; }, }), enforceFunctionCall: true, promptCacheKey: props.promptCacheKey, ...(await transformTestCorrectOverallHistory(ctx, { instruction: props.instruction, procedure: props.procedure, failures: [ ...props.failures, { procedure: props.procedure, failure: props.validate.result, }, ], })), }); if (pointer.value === null) throw new Error("Failed to correct test code."); const newProcedure: Procedure = { ...props.procedure, function: { ...props.procedure.function, content: await props.programmer.replaceImportStatements({ ...props.procedure, function: { ...props.procedure.function, content: pointer.value.revise.final ?? pointer.value.draft, }, }), }, }; const newValidate: AutoBeTestValidateEvent<Procedure["function"]> = await compileWithFiltering({ compile: props.programmer.compile, procedure: newProcedure, }); ctx.dispatch({ type: "testCorrect", kind: "overall", id: v7(), created_at: new Date().toISOString(), function: newProcedure.function, result: props.validate.result, metric, tokenUsage, step: ctx.state().analyze?.step ?? 0, }); return await predicate( ctx, { programmer: props.programmer, procedure: newProcedure, failures: [ ...props.failures, { procedure: props.procedure, failure: props.validate.result, }, ], validate: newValidate, promptCacheKey: props.promptCacheKey, instruction: props.instruction, }, life, ); } const compileWithFiltering = async < Procedure extends IAutoBeTestProcedure, >(props: { compile( procedure: Procedure, ): Promise<AutoBeTestValidateEvent<Procedure["function"]>>; procedure: Procedure; }): Promise<AutoBeTestValidateEvent<Procedure["function"]>> => { const event: AutoBeTestValidateEvent<Procedure["function"]> = await props.compile(props.procedure); if (event.result.type === "failure") { event.result.diagnostics = event.result.diagnostics.filter( (d) => d.file === props.procedure.function.location, ); if (event.result.diagnostics.length === 0) event.result = { type: "success" }; } return event; };