@autobe/agent
Version:
AI backend server code generator
221 lines • 11.6 kB
JavaScript
;
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