UNPKG

@autobe/agent

Version:

AI backend server code generator

444 lines (440 loc) 23.1 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()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createAutoBeContext = void 0; const core_1 = require("@agentica/core"); const utils_1 = require("@autobe/utils"); const openai_1 = require("openai"); const tstl_1 = require("tstl"); const typia_1 = __importDefault(require("typia")); const uuid_1 = require("uuid"); const AutoBeTokenUsageComponent_1 = require("../context/AutoBeTokenUsageComponent"); const TimedConversation_1 = require("../utils/TimedConversation"); const forceRetry_1 = require("../utils/forceRetry"); const consentFunctionCall_1 = require("./consentFunctionCall"); const getCriticalCompiler_1 = require("./getCriticalCompiler"); const mergeSystemMessages_1 = require("./mergeSystemMessages"); // import { supportFunctionCallFallback } from "./supportFunctionCallFallback"; const supportMistral_1 = require("./supportMistral"); const createAutoBeContext = (props) => { var _a, _b, _c; const config = { retry: (_a = props.config.retry) !== null && _a !== void 0 ? _a : 3 /* AutoBeConfigConstant.VALIDATION_RETRY */, locale: (_b = props.config.locale) !== null && _b !== void 0 ? _b : "en-US", timeout: (_c = props.config.timeout) !== null && _c !== void 0 ? _c : 1200000 /* AutoBeConfigConstant.TIMEOUT */, }; const critical = new tstl_1.Semaphore(2); return { vendor: props.vendor, retry: config.retry, locale: config.locale, aggregates: props.aggregates, compilerListener: props.compilerListener, compiler: () => __awaiter(void 0, void 0, void 0, function* () { const compiler = yield props.compiler(); return (0, getCriticalCompiler_1.getCriticalCompiler)(critical, compiler); }), files: props.files, histories: props.histories, state: props.state, usage: props.usage, dispatch: createDispatch(props), assistantMessage: (message) => { props.histories().push(message); setTimeout(() => { void props.dispatch(message).catch(() => { }); }); return message; }, conversate: (next, closure) => __awaiter(void 0, void 0, void 0, function* () { const aggregate = utils_1.AutoBeProcessAggregateFactory.createAggregate(); const progress = { request: 0, response: 0, timeout: 0, }; const metric = (key) => { const accumulate = (collection) => { var _a; var _b; ++collection.total.metric[key]; (_a = collection[_b = next.source]) !== null && _a !== void 0 ? _a : (collection[_b] = utils_1.AutoBeProcessAggregateFactory.createAggregate()); ++collection[next.source].metric[key]; }; ++aggregate.metric[key]; accumulate(props.aggregates); }; const consume = (tokenUsage) => { var _a; const accumulate = (collection) => { var _a; var _b; utils_1.TokenUsageComputer.increment(collection.total.tokenUsage, tokenUsage); (_a = collection[_b = next.source]) !== null && _a !== void 0 ? _a : (collection[_b] = utils_1.AutoBeProcessAggregateFactory.createAggregate()); utils_1.TokenUsageComputer.increment(collection[next.source].tokenUsage, tokenUsage); }; utils_1.TokenUsageComputer.increment(aggregate.tokenUsage, tokenUsage); accumulate(props.aggregates); props .usage() .record(tokenUsage, [ (_a = STAGES.find((stage) => next.source.startsWith(stage))) !== null && _a !== void 0 ? _a : "analyze", ]); }; const execute = () => __awaiter(void 0, void 0, void 0, function* () { var _a, _b, _c, _d, _e; // CREATE AGENT const agent = new core_1.MicroAgentica({ vendor: props.vendor, config: Object.assign(Object.assign({}, ((_a = props.config) !== null && _a !== void 0 ? _a : {})), { executor: { describe: false, }, retry: (_d = (_b = next.retry) !== null && _b !== void 0 ? _b : (_c = props.config) === null || _c === void 0 ? void 0 : _c.retry) !== null && _d !== void 0 ? _d : 3 /* AutoBeConfigConstant.VALIDATION_RETRY */, // stream: false, stream: next.enforceFunctionCall === false }), histories: next.histories, controllers: [next.controller], }); (0, supportMistral_1.supportMistral)(agent, props.vendor); // supportFunctionCallFallback(agent, props.vendor); (0, mergeSystemMessages_1.mergeSystemMessages)(agent, props.vendor); // ADD EVENT LISTENERS agent.on("request", (event) => __awaiter(void 0, void 0, void 0, function* () { var _a, _b; if (next.enforceFunctionCall === true && !!((_a = event.body.tools) === null || _a === void 0 ? void 0 : _a.length) && ((_b = props.vendor.useToolChoice) !== null && _b !== void 0 ? _b : true) === true) event.body.tool_choice = "required"; else if (event.body.tool_choice !== undefined) delete event.body.tool_choice; if (event.body.parallel_tool_calls !== undefined) delete event.body.parallel_tool_calls; if (next.promptCacheKey) event.body.prompt_cache_key = next.promptCacheKey; // event.body.max_tokens = 32768; // for deepseek v3.1 yield props.dispatch(Object.assign(Object.assign({}, event), { type: "vendorRequest", source: next.source, retry: progress.request++ })); })); agent.on("response", (event) => { void props .dispatch(Object.assign(Object.assign({}, event), { type: "vendorResponse", source: next.source, retry: progress.response++ })) .catch(() => { }); }); agent.on("call", () => { metric("attempt"); }); agent.on("jsonParseError", (event) => { metric("invalidJson"); void props .dispatch(Object.assign(Object.assign({}, event), { function: event.operation.function.name, source: next.source })) .catch(() => { }); }); agent.on("validate", (event) => { metric("validationFailure"); void props .dispatch({ type: "jsonValidateError", id: (0, uuid_1.v7)(), source: next.source, function: event.operation.function.name, result: event.result, life: event.life, created_at: event.created_at, }) .catch(() => { }); }); if (closure) closure(agent); // DO CONVERSATE const message = next.enforceFunctionCall === true ? utils_1.StringUtil.trim ` ${next.userMessage} > You have to call function(s) of below to accomplish my request. > > Never hesitate the function calling. Never ask for me permission > to execute the function. Never explain me your plan with waiting > for my approval. > > I gave you every information for the function calling, so just > call it. I repeat that, never hesitate the function calling. > Just do it without any explanation. > ${next.controller.application.functions .map((f) => `> - ${f.name}`) .join("\n")} ` : next.userMessage; const result = yield TimedConversation_1.TimedConversation.process({ timeout: config.timeout, agent, message, }); const tokenUsage = agent .getTokenUsage() .toJSON().aggregate; props .usage() .record(tokenUsage, [ (_e = STAGES.find((stage) => next.source.startsWith(stage))) !== null && _e !== void 0 ? _e : "analyze", ]); consume(tokenUsage); const success = (histories) => { metric("success"); return { histories, tokenUsage: aggregate.tokenUsage, metric: aggregate.metric, __agent: agent, }; }; if (result.type === "error") throw result.error; else if (result.type === "timeout") { void props .dispatch({ type: "vendorTimeout", id: (0, uuid_1.v7)(), source: next.source, timeout: config.timeout, retry: progress.timeout++, created_at: new Date().toISOString(), }) .catch(() => { }); throw result.error; } else if (true === next.enforceFunctionCall && false === result.histories.some((h) => h.type === "execute")) { const failure = () => { throw new Error(utils_1.StringUtil.trim ` Failed to function calling in the ${next.source} step. Here is the list of history types that occurred during the conversation: ${result.histories.map((h) => `- ${h.type}`).join("\n")} \`\`\`json ${JSON.stringify(result.histories, null, 2)} \`\`\` `); }; const last = result.histories.at(-1); if ((last === null || last === void 0 ? void 0 : last.type) === "assistantMessage" || (result.histories.length === 1 && (last === null || last === void 0 ? void 0 : last.type) === "userMessage")) { metric("consent"); const consent = yield (0, consentFunctionCall_1.consentFunctionCall)({ source: next.source, dispatch: (e) => { props.dispatch(e).catch(() => { }); }, config: props.config, vendor: props.vendor, assistantMessage: (last === null || last === void 0 ? void 0 : last.type) === "assistantMessage" ? last.text.trim() : "", }); if (consent !== null) { const newHistories = yield agent.conversate(consent); const newTokenUsage = AutoBeTokenUsageComponent_1.AutoBeTokenUsageComponent.minus(new AutoBeTokenUsageComponent_1.AutoBeTokenUsageComponent(agent.getTokenUsage().toJSON().aggregate), new AutoBeTokenUsageComponent_1.AutoBeTokenUsageComponent(tokenUsage)); consume(newTokenUsage); if (newHistories.some((h) => h.type === "execute")) return success(newHistories); } } // Retry with explicit failure feedback const functionNames = next.controller.application.functions .map((f) => f.name) .join(", "); for (let retry = 0; retry < 3 /* AutoBeConfigConstant.FUNCTION_CALLING_RETRY */ - 1; retry++) { metric("consent"); const retryMessage = `You failed to call any function. ` + `You MUST call one of these functions immediately: ${functionNames}. ` + `Do not explain anything. Just call the function right now.`; const retryHistories = yield agent.conversate(retryMessage); const retryTokenUsage = AutoBeTokenUsageComponent_1.AutoBeTokenUsageComponent.minus(new AutoBeTokenUsageComponent_1.AutoBeTokenUsageComponent(agent.getTokenUsage().toJSON().aggregate), new AutoBeTokenUsageComponent_1.AutoBeTokenUsageComponent(tokenUsage)); consume(retryTokenUsage); if (retryHistories.some((h) => h.type === "execute")) return success(retryHistories); } failure(); } return success(result.histories); }); return yield (0, forceRetry_1.forceRetry)(execute, 3 /* AutoBeConfigConstant.API_ERROR_RETRY */, (error) => { var _a, _b, _c, _d, _e, _f; // Context overflow and other permanent 400 errors should not be // retried — the same payload will always produce the same failure. if (error instanceof openai_1.BadRequestError) { const errBody = error; const msg = String((_f = (_e = (_c = (_b = (_a = errBody.error) === null || _a === void 0 ? void 0 : _a.metadata) === null || _b === void 0 ? void 0 : _b.raw) !== null && _c !== void 0 ? _c : (_d = errBody.error) === null || _d === void 0 ? void 0 : _d.message) !== null && _e !== void 0 ? _e : error.message) !== null && _f !== void 0 ? _f : ""); const permanent = [ "context_length_exceeded", "maximum context length", "request too large", ]; if (permanent.some((p) => msg.includes(p))) return false; } return (error instanceof openai_1.APIError || error instanceof openai_1.BadRequestError || error instanceof core_1.AgenticaJsonParseError || error instanceof core_1.AgenticaValidationError || error instanceof TypeError || (error instanceof Error && error.message.startsWith("OpenRouter upstream error")) || (error instanceof Error && OPENAI_API_ERROR_KEYS.get().every((key) => error.hasOwnProperty(key)))); }); }), getCurrentAggregates: (phase) => { const previous = utils_1.AutoBeProcessAggregateFactory.reduce(props .histories() .filter((h) => h.type === "analyze" || h.type === "database" || h.type === "interface" || h.type === "test" || h.type === "realize") .map((h) => h.aggregates)); return utils_1.AutoBeProcessAggregateFactory.filterPhase(utils_1.AutoBeProcessAggregateFactory.minus(props.aggregates, previous), phase); }, }; }; exports.createAutoBeContext = createAutoBeContext; const createDispatch = (props) => { let analyzeStart = null; let databaseStart = null; let interfaceStart = null; let testStart = null; let realizeStart = null; return (event) => { var _a, _b, _c, _d, _e, _f, _g, _h, _j; // starts if (event.type === "analyzeStart") analyzeStart = event; else if (event.type === "databaseStart") databaseStart = event; else if (event.type === "interfaceStart") interfaceStart = event; else if (event.type === "testStart") testStart = event; else if (event.type === "realizeStart") realizeStart = event; // completes else if (event.type === "analyzeComplete") return transformAndDispatch({ dispatch: props.dispatch, histories: props.histories, state: props.state, event, history: { type: "analyze", id: (0, uuid_1.v7)(), prefix: event.prefix, actors: event.actors, files: event.files, aggregates: event.aggregates, step: event.step, created_at: (_a = analyzeStart === null || analyzeStart === void 0 ? void 0 : analyzeStart.created_at) !== null && _a !== void 0 ? _a : new Date().toISOString(), completed_at: event.created_at, }, }); else if (event.type === "databaseComplete") return transformAndDispatch({ dispatch: props.dispatch, histories: props.histories, state: props.state, event, history: { type: "database", id: (0, uuid_1.v7)(), instruction: (_b = databaseStart === null || databaseStart === void 0 ? void 0 : databaseStart.reason) !== null && _b !== void 0 ? _b : "", schemas: event.schemas, result: event.result, compiled: event.compiled, aggregates: event.aggregates, step: event.step, created_at: (_c = databaseStart === null || databaseStart === void 0 ? void 0 : databaseStart.created_at) !== null && _c !== void 0 ? _c : new Date().toISOString(), completed_at: event.created_at, }, }); else if (event.type === "interfaceComplete") return transformAndDispatch({ dispatch: props.dispatch, histories: props.histories, state: props.state, event, history: { type: "interface", id: (0, uuid_1.v7)(), instruction: (_d = interfaceStart === null || interfaceStart === void 0 ? void 0 : interfaceStart.reason) !== null && _d !== void 0 ? _d : "", authorizations: event.authorizations, document: event.document, missed: event.missed, aggregates: event.aggregates, step: event.step, created_at: (_e = interfaceStart === null || interfaceStart === void 0 ? void 0 : interfaceStart.created_at) !== null && _e !== void 0 ? _e : new Date().toISOString(), completed_at: new Date().toISOString(), }, }); else if (event.type === "testComplete") return transformAndDispatch({ dispatch: props.dispatch, histories: props.histories, state: props.state, event, history: { type: "test", id: (0, uuid_1.v7)(), instruction: (_f = testStart === null || testStart === void 0 ? void 0 : testStart.reason) !== null && _f !== void 0 ? _f : "", functions: event.functions, compiled: event.compiled, aggregates: event.aggregates, step: event.step, created_at: (_g = testStart === null || testStart === void 0 ? void 0 : testStart.created_at) !== null && _g !== void 0 ? _g : new Date().toISOString(), completed_at: new Date().toISOString(), }, }); else if (event.type === "realizeComplete") return transformAndDispatch({ dispatch: props.dispatch, histories: props.histories, state: props.state, event, history: { type: "realize", id: (0, uuid_1.v7)(), instruction: (_h = realizeStart === null || realizeStart === void 0 ? void 0 : realizeStart.reason) !== null && _h !== void 0 ? _h : "", authorizations: event.authorizations, functions: event.functions, controllers: event.controllers, compiled: event.compiled, aggregates: event.aggregates, step: event.step, created_at: (_j = realizeStart === null || realizeStart === void 0 ? void 0 : realizeStart.created_at) !== null && _j !== void 0 ? _j : new Date().toISOString(), completed_at: new Date().toISOString(), }, }); void props.dispatch(event).catch(() => { }); return null; }; }; const transformAndDispatch = (props) => { props.histories().push(props.history); // biome-ignore lint: intended props.state()[props.history.type] = props.history; void props.dispatch(props.event).catch(() => { }); return props.history; }; const STAGES = [ "analyze", "database", "interface", "test", "realize", "facade" ]; const OPENAI_API_ERROR_KEYS = new tstl_1.Singleton(() => Object.keys(new openai_1.APIError(undefined, undefined, undefined, undefined))); //# sourceMappingURL=createAutoBeContext.js.map