@autobe/agent
Version:
AI backend server code generator
409 lines (405 loc) • 19.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());
});
};
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 tstl_1 = require("tstl");
const typia_1 = __importDefault(require("typia"));
const uuid_1 = require("uuid");
const AutoBeTokenUsageComponent_1 = require("../context/AutoBeTokenUsageComponent");
const AutoBeTimeoutError_1 = require("../utils/AutoBeTimeoutError");
const TimedConversation_1 = require("../utils/TimedConversation");
const consentFunctionCall_1 = require("./consentFunctionCall");
const getCommonPrompt_1 = require("./getCommonPrompt");
const getCriticalCompiler_1 = require("./getCriticalCompiler");
const supportMistral_1 = require("./supportMistral");
const createAutoBeContext = (props) => {
var _a, _b, _c;
const config = {
retry: (_a = props.config.retry) !== null && _a !== void 0 ? _a : 4 /* AutoBeConfigConstant.RETRY */,
locale: (_b = props.config.locale) !== null && _b !== void 0 ? _b : "en-US",
timeout: (_c = props.config.timeout) !== null && _c !== void 0 ? _c : null,
};
const critical = new tstl_1.Semaphore(2);
return {
model: props.model,
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 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 progress = {
request: 0,
response: 0,
timeout: 0,
};
const execute = () => __awaiter(void 0, void 0, void 0, function* () {
var _a, _b, _c, _d;
// CREATE AGENT
const agent = new core_1.MicroAgentica({
model: props.model,
vendor: props.vendor,
config: Object.assign(Object.assign({}, ((_a = props.config) !== null && _a !== void 0 ? _a : {})), { retry: (_c = (_b = props.config) === null || _b === void 0 ? void 0 : _b.retry) !== null && _c !== void 0 ? _c : 4 /* AutoBeConfigConstant.RETRY */, executor: {
describe: null,
}, systemPrompt: {
common: () => (0, getCommonPrompt_1.getCommonPrompt)(props.config),
} }),
histories: next.histories,
controllers: [next.controller],
});
(0, supportMistral_1.supportMistral)(agent, props.vendor);
// ADD EVENT LISTENERS
agent.on("request", (event) => __awaiter(void 0, void 0, void 0, function* () {
if (next.enforceFunctionCall === true && event.body.tools)
event.body.tool_choice = "required";
if (event.body.parallel_tool_calls !== undefined)
delete event.body.parallel_tool_calls;
if (next.promptCacheKey)
event.body.prompt_cache_key = next.promptCacheKey;
yield props.dispatch(Object.assign(Object.assign({}, event), { type: "vendorRequest", source: next.source, retry: progress.request++ }));
}));
agent.on("response", (event) => __awaiter(void 0, void 0, void 0, function* () {
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, [
(_d = STAGES.find((stage) => next.source.startsWith(stage))) !== null && _d !== void 0 ? _d : "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" && h.success === true)) {
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.stringify(result.histories)}
`);
};
const last = result.histories.at(-1);
if ((last === null || last === void 0 ? void 0 : last.type) === "assistantMessage" &&
last.text.trim().length !== 0) {
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.text,
});
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" && h.success))
return success(newHistories);
}
}
failure();
}
return success(result.histories);
});
if (next.enforceFunctionCall === true)
return yield forceRetry(execute, config.retry);
else
return yield execute();
}),
getCurrentAggregates: (phase) => {
const previous = utils_1.AutoBeProcessAggregateFactory.reduce(props
.histories()
.filter((h) => h.type === "analyze" ||
h.type === "prisma" ||
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 prismaStart = 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 === "prismaStart")
prismaStart = 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 === "prismaComplete")
return transformAndDispatch({
dispatch: props.dispatch,
histories: props.histories,
state: props.state,
event,
history: {
type: "prisma",
id: (0, uuid_1.v7)(),
instruction: (_b = prismaStart === null || prismaStart === void 0 ? void 0 : prismaStart.reason) !== null && _b !== void 0 ? _b : "",
schemas: event.schemas,
result: event.result,
compiled: event.compiled,
aggregates: event.aggregates,
step: event.step,
created_at: (_c = prismaStart === null || prismaStart === void 0 ? void 0 : prismaStart.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 : "",
files: event.files,
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);
props.state()[props.history.type] = props.history;
void props.dispatch(props.event).catch(() => { });
return props.history;
};
const forceRetry = (task, count) => __awaiter(void 0, void 0, void 0, function* () {
let error = undefined;
for (let i = 0; i < count; ++i)
try {
return yield task();
}
catch (e) {
if (e instanceof AutoBeTimeoutError_1.AutoBeTimeoutError)
throw e;
error = e;
}
throw error;
});
const STAGES = [
"analyze",
"prisma",
"interface",
"test",
"realize"
];
//# sourceMappingURL=createAutoBeContext.js.map