UNPKG

@autobe/agent

Version:

AI backend server code generator

221 lines 11.6 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.writeCodeUntilCompilePassed = writeCodeUntilCompilePassed; const tstl_1 = require("tstl"); const ProviderCodeComparator_1 = require("./ProviderCodeComparator"); const RealizePipe_1 = require("./RealizePipe"); const orchestrateRealizeCoder_1 = require("./orchestrateRealizeCoder"); const orchestrateRealizePlanner_1 = require("./orchestrateRealizePlanner"); const IAutoBeRealizeFailedSymbol_1 = require("./structures/IAutoBeRealizeFailedSymbol"); const ProviderFileSystem_1 = require("./utils/ProviderFileSystem"); function writeCodeUntilCompilePassed(ctx) { return function (props) { return __awaiter(this, void 0, void 0, function* () { var _a, _b, _c; const payloads = Object.fromEntries(props.authorizations.map((el) => [ el.payload.location, el.payload.content, ])); const files = Object.fromEntries(Object.entries(yield ctx.files({ dbms: "postgres" })).filter(([key]) => key.startsWith("src"))); const templateFiles = yield getTemplates(ctx); let diagnostics = { current: [], total: [], }; const histories = new tstl_1.HashMap(ProviderCodeComparator_1.ProviderCodeComparator.hashCode, ProviderCodeComparator_1.ProviderCodeComparator.equals); for (const operation of props.operations) { histories.set(operation, []); } let compiled = null; const entireCodes = {}; for (let i = 0; i < props.retry; i++) { const targets = props.operations.filter((op) => shouldProcessOperation(op, diagnostics.current)); const metadata = { total: targets.length, count: 0 }; const generatedCodes = yield Promise.all(targets.map((operation) => { const role = operation.authorizationRole; const authorization = props.authorizations.find((el) => el.role === role); return process(ctx)({ metadata, operation, previousCodes: histories.get(operation), diagnostics, entireCodes, authorization, }); })); for (const code of generatedCodes) { if (code.type === "success") { const response = histories.get(code.operation); response.push(code); histories.set(code.operation, response); entireCodes[code.result.filename] = { content: code.result.implementationCode, result: "success", endpoint: { method: code.operation.method, path: code.operation.path, }, location: code.result.filename, name: code.result.name, }; } } const prisma = (_a = ctx.state().prisma) === null || _a === void 0 ? void 0 : _a.compiled; const nodeModules = (prisma === null || prisma === void 0 ? void 0 : prisma.type) === "success" ? prisma.nodeModules : {}; const compiler = yield ctx.compiler(); compiled = yield compiler.typescript.compile({ files: Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, payloads), files), nodeModules), Object.fromEntries(templateFiles.map((file) => [file.location, file.content]))), Object.fromEntries(Object.entries(entireCodes).map(([filename, { content }]) => [ filename, content, ]))), }); if (compiled && compiled.type !== "success") { ctx.dispatch({ type: "realizeValidate", created_at: new Date().toISOString(), files: compiled.type === "failure" ? Object.fromEntries(compiled.diagnostics.map((diagnostic) => [ diagnostic.file, diagnostic.code, ])) : {}, result: compiled, step: (_c = (_b = ctx.state().analyze) === null || _b === void 0 ? void 0 : _b.step) !== null && _c !== void 0 ? _c : 0, }); } if (compiled.type === "success" && generatedCodes.every((c) => c.type === "success")) { break; } else if (compiled.type === "failure") { diagnostics.current = compiled.diagnostics; diagnostics.total = [...diagnostics.total, ...compiled.diagnostics]; } } const functions = Object.entries(entireCodes) .filter(([filename]) => filename.startsWith("src/providers")) // filter only provider files .map(([filename, value]) => { var _a; return { filename, content: value.content, endpoint: value.endpoint, location: value.location, name: value.name, role: (_a = value.role) !== null && _a !== void 0 ? _a : null, }; }); return { functions, compiled: compiled ? compiled : { type: "success" } }; }); }; } /** * Loads template files for the realize agent These files are essential for the * realize coder to pass compilation * * @param ctx Context of agent * @returns Template file infomations */ function getTemplates(ctx) { return __awaiter(this, void 0, void 0, function* () { const compiler = yield ctx.compiler(); const templateFiles = yield compiler.realize.getTemplate(); const pathnames = ["src/MyGlobal.ts", "src/util/toISOStringSafe.ts"]; return pathnames.map((pathname) => { return { content: templateFiles[pathname], result: "success", location: pathname, role: null, // template files doesn't have role. }; }); }); } function process(ctx) { return function (props) { return __awaiter(this, void 0, void 0, function* () { const result = yield (0, RealizePipe_1.pipe)(props.operation, (operation) => (0, orchestrateRealizePlanner_1.orchestrateRealizePlanner)(ctx, operation, props.authorization), (plan) => __awaiter(this, void 0, void 0, function* () { var _a, _b; const filename = ProviderFileSystem_1.RealizeFileSystem.providerPath(plan.functionName); const totalDiagnostics = props.diagnostics.total.filter((el) => el.file === filename); const currentDiagnostics = props.diagnostics.current.filter((el) => el.file === filename); const code = (_b = (_a = props.entireCodes[filename]) === null || _a === void 0 ? void 0 : _a.content) !== null && _b !== void 0 ? _b : null; return (0, orchestrateRealizeCoder_1.orchestrateRealizeCoder)(ctx, props.operation, props.previousCodes, plan, code, totalDiagnostics, currentDiagnostics, props.authorization).then((res) => { var _a, _b, _c, _d; if (props.previousCodes.length === 0) { ctx.dispatch({ type: "realizeWrite", filename: filename, content: res === IAutoBeRealizeFailedSymbol_1.FAILED ? "FAILED" : res.implementationCode, completed: ++props.metadata.count, created_at: new Date().toISOString(), step: (_b = (_a = ctx.state().analyze) === null || _a === void 0 ? void 0 : _a.step) !== null && _b !== void 0 ? _b : 0, total: props.metadata.total, }); } else { ctx.dispatch({ type: "realizeCorrect", filename: filename, content: res === IAutoBeRealizeFailedSymbol_1.FAILED ? "FAILED" : res.implementationCode, completed: ++props.metadata.count, created_at: new Date().toISOString(), step: (_d = (_c = ctx.state().analyze) === null || _c === void 0 ? void 0 : _c.step) !== null && _d !== void 0 ? _d : 0, total: props.metadata.total, }); } if (res === IAutoBeRealizeFailedSymbol_1.FAILED) { return res; } return Object.assign(Object.assign({}, res), { name: plan.functionName }); }); })); if (result === IAutoBeRealizeFailedSymbol_1.FAILED) { return { type: "failed", operation: props.operation, result }; } return { type: "success", operation: props.operation, result }; }); }; } /** * Determines whether an operation should be processed in the current iteration. * In the initial case (no errors), all operations are processed. When errors * exist, only operations with compilation errors are targeted for reprocessing * in the next iteration. * * @param op - The operation to check * @param currentDiagnostics - Current compilation errors * @returns True if the operation should be processed */ function shouldProcessOperation(op, currentDiagnostics) { if (currentDiagnostics.length === 0) { return true; } const operationFilename = generateProviderFilename(op); return currentDiagnostics.some((diagnostic) => diagnostic.file === operationFilename); } /** * Generates a provider filename for an operation. Converts the operation's HTTP * method and path into a valid TypeScript filename. The filename serves as both * the function name and the file identifier. * * @param op - The operation to generate a filename for * @returns The generated provider filename with path */ function generateProviderFilename(op) { return `src/providers/${op.method}_${op.path .replaceAll("/", "_") .replaceAll("-", "_") .replaceAll("{", "$") .replaceAll("}", "")}.ts`; } //# sourceMappingURL=writeCodeUntilCompilePassed.js.map