UNPKG

@autobe/agent

Version:

AI backend server code generator

215 lines (196 loc) 6.49 kB
import { IAgenticaController, MicroAgentica } from "@agentica/core"; import { ILlmApplication, ILlmSchema } from "@samchon/openapi"; import typia from "typia"; import { v4 } from "uuid"; import { AutoBeSystemPromptConstant } from "../../constants/AutoBeSystemPromptConstant"; import { AutoBeContext } from "../../context/AutoBeContext"; import { assertSchemaModel } from "../../context/assertSchemaModel"; import { enforceToolCall } from "../../utils/enforceToolCall"; import { AutoBeAnalyzeFileSystem, IAutoBeAnalyzeFileSystem, } from "./AutoBeAnalyzeFileSystem"; import { AutoBEAnalyzeFileMap, AutoBeAnalyzePointer, } from "./AutoBeAnalyzePointer"; import { AutoBeAnalyzeReviewer } from "./AutoBeAnalyzeReviewer"; export class AutoBeAnalyzeAgent<Model extends ILlmSchema.Model> { private readonly createAnalyzeAgent: () => MicroAgentica<Model>; private readonly fileMap: AutoBEAnalyzeFileMap = {}; constructor( private readonly createReviewerAgentFn: typeof AutoBeAnalyzeReviewer, private readonly ctx: AutoBeContext<Model>, private readonly pointer: AutoBeAnalyzePointer, private readonly filenames: string[], ) { assertSchemaModel(ctx.model); const controller = createController<Model>({ model: ctx.model, execute: new AutoBeAnalyzeFileSystem(this.fileMap), build: async (files: AutoBEAnalyzeFileMap) => { this.pointer.value ??= { files: {} }; Object.assign(this.pointer.value.files, files); }, }); this.createAnalyzeAgent = (): MicroAgentica<Model> => { const agent = new MicroAgentica({ controllers: [controller], model: ctx.model, vendor: ctx.vendor, config: { locale: ctx.config?.locale, executor: { describe: null, }, }, tokenUsage: ctx.usage(), histories: [ { id: v4(), created_at: new Date().toISOString(), type: "systemMessage", text: AutoBeSystemPromptConstant.ANALYZE.replace( "{% User Locale %}", ctx.config?.locale ?? "en-US", ), }, { id: v4(), created_at: new Date().toISOString(), type: "systemMessage", text: [ "# Guidelines", "If the user specifies the exact number of pages, please follow it precisely.", AutoBeSystemPromptConstant.ANALYZE_GUIDELINE, ].join("\n"), }, { id: v4(), created_at: new Date().toISOString(), type: "systemMessage", text: [ "The following is the name of the entire file.", "Use it to build a table of contents.", this.filenames.map((filename) => `- ${filename}`), "", "However, do not touch other than the file you have to create.", ].join("\n"), }, ], }); return enforceToolCall(agent); }; } /** * Conversate with planner agent * * @param content Conversation from user in this time. * @returns */ async conversate(content: string, retry = 3): Promise<string> { if (retry === 0) { return "Abort due to excess retry count"; } const response = await this.createAnalyzeAgent().conversate(content); const lastMessage = response[response.length - 1]!; if ("text" in lastMessage) { this.ctx.dispatch({ type: "analyzeWriteDocument", files: this.fileMap, created_at: new Date().toISOString(), step: this.ctx.state().analyze?.step ?? 0, }); const aborted = lastMessage.type === "describe" && lastMessage.executes.some((el) => { if ( el.protocol === "class" && el.operation.function.name === "abort" ) { el.arguments; return true; } }); if (aborted === true) { return lastMessage.text; } const reviewer = this.createReviewerAgentFn(this.ctx, { query: content, files: JSON.stringify(this.fileMap), }); const filenames = Object.keys(this.fileMap).join(","); const command = `Please proceed with the review of these files only.: ${filenames}`; const response = await reviewer.conversate(command); const review = response.find((el) => el.type === "assistantMessage"); if (review) { this.ctx.dispatch({ type: "analyzeReview", review: review.text, created_at: new Date().toISOString(), step: this.ctx.state().analyze?.step ?? 0, }); return this.conversate( JSON.stringify({ user_query: content, message: `THIS IS ANSWER OF REVIEW AGENT. FOLLOW THIS INSTRUCTIONS. AND DON\'T REQUEST ANYTHING.`, review: review.text, }), retry - 1, ); } return `COMPLETE WITHOUT REVIEW`; } return "COMPLETE"; } } function createController<Model extends ILlmSchema.Model>(props: { model: Model; execute: AutoBeAnalyzeFileSystem; build: (input: AutoBEAnalyzeFileMap) => void; }): IAgenticaController.IClass<Model> { assertSchemaModel(props.model); const application: ILlmApplication<Model> = collection[ props.model ] as unknown as ILlmApplication<Model>; return { protocol: "class", name: "Planning", application, // execute: props.execute, execute: { removeFile: (input) => { const response = props.execute.removeFile(input); props.build(props.execute.allFiles()); return response; }, abort: (input) => { const response = props.execute.abort(input); props.build(props.execute.allFiles()); return response; }, createOrUpdateFiles: (input) => { const response = props.execute.createOrUpdateFiles(input); props.build(props.execute.allFiles()); return response; }, } satisfies IAutoBeAnalyzeFileSystem, }; } const claude = typia.llm.application< AutoBeAnalyzeFileSystem, "claude", { reference: true } >(); const collection = { chatgpt: typia.llm.application< AutoBeAnalyzeFileSystem, "chatgpt", { reference: true } >(), claude, llama: claude, deepseek: claude, "3.1": claude, "3.0": typia.llm.application<AutoBeAnalyzeFileSystem, "3.0">(), };