UNPKG

@autobe/agent

Version:

AI backend server code generator

305 lines (291 loc) 10.1 kB
import { AutoBeEventSource, AutoBeOpenApi, AutoBeProgressEventBase, AutoBeRealizeAuthorization, AutoBeRealizeCollectorFunction, AutoBeRealizeOperationFunction, AutoBeRealizeTransformerFunction, AutoBeRealizeWriteEvent, } from "@autobe/interface"; import { IPointer, Singleton } from "tstl"; import typia, { ILlmApplication, ILlmController, IValidation } from "typia"; import { v7 } from "uuid"; import { AutoBeContext } from "../../context/AutoBeContext"; import { buildAnalysisContextSections } from "../../utils/RAGRetrieval"; import { executeCachedBatch } from "../../utils/executeCachedBatch"; import { forceRetry } from "../../utils/forceRetry"; import { getEmbedder } from "../../utils/getEmbedder"; import { validateEmptyCode } from "../../utils/validateEmptyCode"; import { AutoBePreliminaryController } from "../common/AutoBePreliminaryController"; import { convertToSectionEntries } from "../common/internal/convertToSectionEntries"; import { IAnalysisSectionEntry } from "../common/structures/IAnalysisSectionEntry"; import { transformRealizeOperationWriteHistory } from "./histories/transformRealizeOperationWriteHistory"; import { AutoBeRealizeOperationProgrammer } from "./programmers/AutoBeRealizeOperationProgrammer"; import { IAutoBeRealizeOperationWriteApplication } from "./structures/IAutoBeRealizeOperationWriteApplication"; import { IAutoBeRealizeScenarioResult } from "./structures/IAutoBeRealizeScenarioResult"; export async function orchestrateRealizeOperationWrite( ctx: AutoBeContext, props: { authorizations: AutoBeRealizeAuthorization[]; collectors: AutoBeRealizeCollectorFunction[]; transformers: AutoBeRealizeTransformerFunction[]; progress: AutoBeProgressEventBase; targetEndpoints?: AutoBeOpenApi.IEndpoint[]; }, ): Promise<AutoBeRealizeOperationFunction[]> { const document: AutoBeOpenApi.IDocument = ctx.state().interface!.document; const allScenarios: IAutoBeRealizeScenarioResult[] = document.operations.map( (operation) => AutoBeRealizeOperationProgrammer.getScenario({ authorizations: props.authorizations, operation, }), ); const scenarios: IAutoBeRealizeScenarioResult[] = props.targetEndpoints ? allScenarios.filter((s) => props.targetEndpoints!.some( (e) => e.method === s.operation.method && e.path === s.operation.path, ), ) : allScenarios; return await executeCachedBatch( ctx, scenarios.map((s) => { const counter = new Singleton(() => ++props.progress.completed); return async (promptCacheKey: string) => { try { return await forceRetry(() => process(ctx, { document, totalAuthorizations: props.authorizations, collectors: props.collectors, transformers: props.transformers, authorization: s.decoratorEvent ?? null, scenario: s, progress: props.progress, counter, promptCacheKey, }), ); } catch (error) { counter.get(); throw error; } }; }), ); } async function process( ctx: AutoBeContext, props: { document: AutoBeOpenApi.IDocument; authorization: AutoBeRealizeAuthorization | null; collectors: AutoBeRealizeCollectorFunction[]; totalAuthorizations: AutoBeRealizeAuthorization[]; scenario: IAutoBeRealizeScenarioResult; transformers: AutoBeRealizeTransformerFunction[]; progress: AutoBeProgressEventBase; counter: Singleton<number>; promptCacheKey: string; }, ): Promise<AutoBeRealizeOperationFunction> { const allSections: IAnalysisSectionEntry[] = convertToSectionEntries( ctx.state().analyze?.files ?? [], ); const pathSegments = props.scenario.operation.path .split("/") .filter((p) => p && !p.startsWith(":") && !p.startsWith("{")); const queryText: string = [ "operation", "write", props.scenario.operation.method, ...pathSegments, props.scenario.functionName, ].join(" "); const ragSections: IAnalysisSectionEntry[] = await buildAnalysisContextSections( getEmbedder(), allSections, queryText, "TOPK", { log: false, logPrefix: "realizeOperationWrite" }, ); const preliminary: AutoBePreliminaryController< | "analysisSections" | "databaseSchemas" | "realizeCollectors" | "realizeTransformers" | "complete" > = new AutoBePreliminaryController({ source: SOURCE, application: typia.json.application<IAutoBeRealizeOperationWriteApplication>(), kinds: [ "analysisSections", "databaseSchemas", "realizeCollectors", "realizeTransformers", "complete", ], dispatch: (e) => ctx.dispatch(e), state: ctx.state(), all: { realizeCollectors: props.collectors, realizeTransformers: props.transformers, }, local: { realizeCollectors: props.collectors.filter( (c) => c.plan.dtoTypeName === props.scenario.operation.requestBody?.typeName, ), realizeTransformers: AutoBeRealizeOperationProgrammer.getLocalTransformers({ operation: props.scenario.operation, schemas: props.document.components.schemas, transformers: props.transformers, }), analysisSections: ragSections, }, }); const event: AutoBeRealizeWriteEvent = await preliminary.orchestrate( ctx, async (out) => { const pointer: IPointer<IAutoBeRealizeOperationWriteApplication.IWrite | null> = { value: null, }; const dto: Record<string, string> = await AutoBeRealizeOperationProgrammer.writeStructures( ctx, props.scenario.operation, ); const result: AutoBeContext.IResult = await ctx.conversate({ source: "realizeWrite", controller: createController({ functionName: props.scenario.functionName, build: (next) => { pointer.value = next; }, preliminary, }), enforceFunctionCall: true, promptCacheKey: props.promptCacheKey, ...transformRealizeOperationWriteHistory({ state: ctx.state(), scenario: props.scenario, authorization: props.authorization, totalAuthorizations: props.totalAuthorizations, collectors: props.collectors, transformers: props.transformers, dto, preliminary, }), }); if (pointer.value === null) return out(result)(null); const template: string = AutoBeRealizeOperationProgrammer.writeTemplate({ authorizations: props.totalAuthorizations, schemas: props.document.components.schemas, operation: props.scenario.operation, collectors: props.collectors, transformers: props.transformers, }); const functor: AutoBeRealizeOperationFunction = { type: "operation", endpoint: { method: props.scenario.operation.method, path: props.scenario.operation.path, }, location: props.scenario.location, name: props.scenario.functionName, content: await AutoBeRealizeOperationProgrammer.replaceImportStatements( ctx, { operation: props.scenario.operation, schemas: props.document.components.schemas, code: pointer.value.revise.final ?? pointer.value.draft, payload: props.authorization?.payload.name, }, ), template, }; return out(result)({ id: v7(), type: "realizeWrite", function: functor, acquisition: preliminary.getAcquisition(), metric: result.metric, tokenUsage: result.tokenUsage, completed: props.counter.get(), total: props.progress.total, step: ctx.state().analyze?.step ?? 0, created_at: new Date().toISOString(), } satisfies AutoBeRealizeWriteEvent); }, ); ctx.dispatch(event); return event.function as AutoBeRealizeOperationFunction; } function createController(props: { functionName: string; build: (next: IAutoBeRealizeOperationWriteApplication.IWrite) => void; preliminary: AutoBePreliminaryController< | "analysisSections" | "databaseSchemas" | "realizeCollectors" | "realizeTransformers" | "complete" >; }): ILlmController { const validate: Validator = (input) => { const result: IValidation<IAutoBeRealizeOperationWriteApplication.IProps> = typia.validate<IAutoBeRealizeOperationWriteApplication.IProps>(input); if (result.success === false) return result; else if (result.data.request.type !== "write") return props.preliminary.validate({ thinking: result.data.thinking, request: result.data.request, }); const errors: IValidation.IError[] = [ ...validateEmptyCode({ name: props.functionName, draft: result.data.request.draft, revise: result.data.request.revise, path: "$input.request", asynchronous: true, }), ...AutoBeRealizeOperationProgrammer.validateSelectTransformContract({ draft: result.data.request.draft, revise: result.data.request.revise, }), ]; return errors.length ? { success: false, errors, data: result.data, } : result; }; const application: ILlmApplication = props.preliminary.fixApplication( typia.llm.application<IAutoBeRealizeOperationWriteApplication>({ validate: { process: validate, }, }), ); return { protocol: "class", name: SOURCE, application, execute: { process: (next) => { if (next.request.type === "write") props.build(next.request); }, } satisfies IAutoBeRealizeOperationWriteApplication, }; } type Validator = ( input: unknown, ) => IValidation<IAutoBeRealizeOperationWriteApplication.IProps>; const SOURCE = "realizeWrite" satisfies AutoBeEventSource;