UNPKG

@autobe/agent

Version:

AI backend server code generator

341 lines 15.5 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.AutoBePreliminaryController = void 0; const utils_1 = require("@autobe/utils"); const utils_2 = require("@typia/utils"); const uuid_1 = require("uuid"); const AutoBePreliminaryExhaustedError_1 = require("../../utils/AutoBePreliminaryExhaustedError"); const transformPreliminaryHistory_1 = require("./histories/transformPreliminaryHistory"); const complementPreliminaryCollection_1 = require("./internal/complementPreliminaryCollection"); const createPreliminaryCollection_1 = require("./internal/createPreliminaryCollection"); const fixPrelminaryApplication_1 = require("./internal/fixPrelminaryApplication"); const validatePreliminary_1 = require("./internal/validatePreliminary"); const orchestratePreliminary_1 = require("./orchestratePreliminary"); /** * RAG controller for incremental context loading. * * Manages LLM's incremental data requests via function calling, preventing * duplicates and auto-resolving dependencies. * * - `all`: globally available data (from state) * - `local`: currently loaded data (agent context) * - Auto-complements prerequisites, $ref dependencies, and neighbors * * @author Samchon */ class AutoBePreliminaryController { /** * Initializes controller with data collections and auto-complements * dependencies. * * @param props Constructor configuration including kinds, state, and initial * data. */ constructor(props) { var _a, _b, _c, _d; // PAGINATION this.analysisPageOffset = 0; // COMPLETION TRACKING this.previousWrites = []; this.completed = { value: false, }; this.source = props.source; this.source_id = (0, uuid_1.v7)(); this.kinds = props.kinds; this.dispatch = props.dispatch; // biome-ignore-start lint: intended this.config = { database: (_b = (_a = props.config) === null || _a === void 0 ? void 0 : _a.database) !== null && _b !== void 0 ? _b : "text", databaseProperty: (_d = (_c = props.config) === null || _c === void 0 ? void 0 : _c.databaseProperty) !== null && _d !== void 0 ? _d : false, }; // biome-ignore-end lint: intended this.argumentTypeNames = (() => { var _a, _b, _c; const func = props.application.functions.find((f) => f.name === "process"); if (func === undefined) throw new Error("Unable to find 'process' function in application."); const param = (_a = func.parameters[0]) === null || _a === void 0 ? void 0 : _a.schema; if (param === undefined || utils_2.OpenApiTypeChecker.isReference(param) === false) throw new Error("'process' function parameter is not a reference type."); const schema = (_b = props.application.components.schemas) === null || _b === void 0 ? void 0 : _b[param.$ref.split("/").pop()]; if (schema === undefined || utils_2.OpenApiTypeChecker.isObject(schema) === false) throw new Error("'process' function parameter reference is not an object type."); const request = (_c = schema.properties) === null || _c === void 0 ? void 0 : _c.request; if (request === undefined || utils_2.OpenApiTypeChecker.isOneOf(request) === false) throw new Error("'process' function parameter.request is not a oneOf type."); else if (request.oneOf.length === 0 || request.oneOf.every((sch) => utils_2.OpenApiTypeChecker.isReference(sch) === false)) throw new Error("'process' function parameter.request oneOf does not contain any reference type."); return request.oneOf.map((sch) => { // biome-ignore lint: intended const ref = sch.$ref; return ref.split("/").pop(); }); })(); this.state = props.state; this.all = (0, createPreliminaryCollection_1.createPreliminaryCollection)(props.state, props.all); this.local = (0, createPreliminaryCollection_1.createPreliminaryCollection)(null, props.local); (0, complementPreliminaryCollection_1.complementPreliminaryCollection)({ kinds: props.kinds, all: this.all, local: this.local, prerequisite: false, }); } /** * Validates request for duplicates and non-existent items. * * @param input LLM's function calling request to validate. * @returns Validation result with errors if duplicates or non-existent items * found. */ validate(input) { return (0, validatePreliminary_1.validatePreliminary)(this, input); } /** * Generates dynamic system prompts with `LOADED`/`AVAILABLE` lists. * * @returns Assistant and system messages with loaded/available item lists. */ getHistories() { return (0, transformPreliminaryHistory_1.transformPreliminaryHistory)(this); } /** * Returns the orchestration source that created this controller. * * @returns Source event type (e.g., `"realizeWrite"`, `"interfaceSchema"`). */ getSource() { return this.source; } /** * Returns data types enabled for this controller. * * @returns Array of enabled kinds (e.g., `["databaseSchemas", * "interfaceSchemas"]`). */ getKinds() { return this.kinds; } /** * Returns configuration (e.g., database schema format: `"ast"` | `"text"`). * * @returns Controller configuration object. */ getConfig() { return this.config; } /** * Returns function calling type names available in LLM application. * * @returns Array of request type names from `oneOf` union. */ getArgumentTypeNames() { return this.argumentTypeNames; } /** * Returns all globally available data from state. * * @returns Complete dataset that can be requested. */ getAll() { return this.all; } /** * Returns currently loaded data in agent context. * * @returns Subset of data already provided to LLM. */ getLocal() { return this.local; } /** * Extracts acquisition metadata from the currently loaded preliminary data. * * Transforms the local preliminary collection into a normalized acquisition * structure that is suitable for event tracking, including only metadata such * as filenames, schema names, and operation identifiers rather than full * objects. * * @returns Acquisition metadata derived from currently loaded data, * normalized for event tracking. */ getAcquisition() { const acquisition = {}; const local = this .local; for (const kind of this.kinds) if (kind === "analysisSections") acquisition.analysisSections = local.analysisSections.map((s) => s.id); else if (kind === "databaseSchemas") acquisition.databaseSchemas = local.databaseSchemas.map((s) => s.name); else if (kind === "interfaceOperations") acquisition.interfaceOperations = local.interfaceOperations.map((o) => ({ path: o.path, method: o.method, })); else if (kind === "interfaceSchemas") acquisition.interfaceSchemas = Object.keys(local.interfaceSchemas); else if (kind === "realizeCollectors") acquisition.realizeCollectors = local.realizeCollectors.map((f) => f.plan.dtoTypeName); else if (kind === "realizeTransformers") acquisition.realizeTransformers = local.realizeTransformers.map((f) => f.plan.dtoTypeName); else if (kind === "previousAnalysisSections") acquisition.previousAnalysisSections = local.previousAnalysisSections.map((s) => s.id); else if (kind === "previousDatabaseSchemas") acquisition.previousDatabaseSchemas = local.previousDatabaseSchemas.map((s) => s.name); else if (kind === "previousInterfaceOperations") acquisition.previousInterfaceOperations = local.previousInterfaceOperations.map((o) => ({ path: o.path, method: o.method, })); else if (kind === "previousInterfaceSchemas") acquisition.previousInterfaceSchemas = Object.keys(local.previousInterfaceSchemas); else if (kind === "complete") acquisition.complete = false; else kind; return acquisition; } /** * Returns the current AutoBe state. * * @returns Current pipeline state containing all phase histories. */ getState() { return this.state; } /** Returns current page offset for analysis section metadata pagination. */ getAnalysisPageOffset() { return this.analysisPageOffset; } getPreviousWrite() { var _a, _b; return (_b = (_a = this.previousWrites.at(-1)) === null || _a === void 0 ? void 0 : _a.raw) !== null && _b !== void 0 ? _b : null; } /** Advances analysis section metadata page by PAGE_SIZE. */ advanceAnalysisPage() { this.analysisPageOffset += 75 /* AutoBeConfigConstant.ANALYSIS_PAGE_SIZE */; } /** * Dynamically adjusts LLM application schema at runtime. * * Removes `getPreviousXXX` types from union/oneOf when no previous iteration * exists. Mutates application's `anyOf`/`oneOf` array, `$defs`, and * `discriminator` mapping. Also erases corresponding `kinds` from * controller's `all`/`local` collections. * * @param application LLM application to modify (mutated in-place) */ fixApplication(application, enumerable = false) { (0, fixPrelminaryApplication_1.fixPreliminaryApplication)({ state: this.state, preliminary: this, application, enumerable, }); return application; } /** * Runs RAG loop for incremental context loading. * * Repeats until process returns non-null value or exceeds the maximum number * of iterations (`AutoBeConfigConstant.RAG_LIMIT`). Each iteration: LLM * requests data → `orchestratePreliminary` adds to `local` → next iteration * with updated context. * * When RAG_LIMIT is exhausted, throws `AutoBePreliminaryExhaustedError` which * can be caught alongside `AutoBeTimeoutError` for force-pass. * * @param ctx AutoBe context for `conversate` and state access. * @param process Callback that runs LLM `conversate` and returns result. * @returns Final value when process returns non-null or throws after * exceeding `AutoBeConfigConstant.RAG_LIMIT` retries. */ orchestrate(ctx, process) { return __awaiter(this, void 0, void 0, function* () { // initialize this.previousWrites = []; this.completed.value = false; const aggregate = utils_1.AutoBeProcessAggregateFactory.createAggregate(); try { for (let i = 0; i < 7 /* AutoBeConfigConstant.RAG_LIMIT */; ++i) { // take a process const result = yield process((x) => (value) => (Object.assign(Object.assign({}, x), { value }))); // swap consumption to aggregate utils_1.AutoBeFunctionCallingMetricFactory.increment(aggregate.metric, result.metric); utils_1.TokenUsageComputer.increment(aggregate.tokenUsage, result.tokenUsage); result.tokenUsage = aggregate.tokenUsage; result.metric = aggregate.metric; if (result.value !== null) { const executes = result.histories.filter((h) => h.type === "execute"); const history = executes.find((h) => h.arguments.request.type === "write"); if (history === undefined) continue; // store write result and raw arguments this.previousWrites.push({ value: result.value, metric: result.metric, tokenUsage: result.tokenUsage, raw: history.arguments, }); if (this.previousWrites.length > 1) { this.dispatch({ id: (0, uuid_1.v7)(), type: "preliminaryRewrite", source: this.source, thinking: history.arguments.thinking, oldbie: this.previousWrites.at(-2).raw, newbie: history.arguments, created_at: new Date().toISOString(), }); } if (this.previousWrites.length >= (this.kinds.includes("complete") ? 3 /* AutoBeConfigConstant.PRELIMINARY_WRITE_LIMIT */ : 1)) break; } else { // orchestrate next iteration yield (0, orchestratePreliminary_1.orchestratePreliminary)(ctx, { source_id: this.source_id, source: this.source, preliminary: this, trial: i + 1, histories: result.histories, completed: this.completed, }); if (this.completed.value === true && this.previousWrites.length !== 0) break; } } } catch (error) { if (this.previousWrites.length === 0) throw error; } // check success const last = this.previousWrites.at(-1); if (last !== undefined) return last.value; throw new AutoBePreliminaryExhaustedError_1.AutoBePreliminaryExhaustedError(); }); } } exports.AutoBePreliminaryController = AutoBePreliminaryController; //# sourceMappingURL=AutoBePreliminaryController.js.map