agentlang
Version:
The easiest way to build the most reliable AI agents - enterprise-grade teams of AI agents that collaborate with each other and humans
493 lines • 18.6 kB
JavaScript
import { isPattern, isStatement, isWorkflowDefinition, } from '../language/generated/ast.js';
import { parseModule, parseStatement } from '../language/parser.js';
import { ExecGraph, ExecGraphNode, ExecGraphWalker, SubGraphType } from './defs.js';
import { DocEventName, Environment, evaluateExpression, evaluatePattern, evaluateStatement, handleAgentInvocation, handleOpenApiEvent, maybeBindStatementResultToAlias, maybeDeleteQueriedInstances, PatternHandler, setEvaluateFn, setParseAndEvaluateStatementFn, } from './interpreter.js';
import { fetchModule, getWorkflowForEvent, isAgentEvent, isAgentEventInstance, isEmptyWorkflow, isEventInstance, RecordType, } from './module.js';
import { flushMonitoringData } from './modules/core.js';
import { isOpenApiEventInstance, isOpenApiModule } from './openapi.js';
import { isMonitoringEnabled } from './state.js';
import { escapeQueryName, isCoreDefinition, isCoreModule, isFqName, makeFqName, nameToPath, } from './util.js';
const GraphCache = new Map();
export async function generateExecutionGraph(eventName) {
const cg = GraphCache.get(eventName);
if (cg)
return cg;
const wf = getWorkflowForEvent(eventName);
const parts = nameToPath(eventName);
const moduleName = parts.hasModule() ? parts.getModuleName() : undefined;
if (!isEmptyWorkflow(wf)) {
const g = (await graphFromStatements(wf.statements, moduleName)).setEventName(eventName);
if (g.canCache())
GraphCache.set(eventName, g);
return g;
}
return undefined;
}
class GraphGenerator extends PatternHandler {
constructor() {
super(...arguments);
this.graph = new ExecGraph();
}
genericHandler(env) {
this.graph.pushNode(new ExecGraphNode(env.getActiveUserData()));
}
async handleExpression(_, env) {
this.genericHandler(env);
}
async handleCrudMap(crudMap, env) {
const parts = nameToPath(crudMap.name);
const moduleName = parts.hasModule() ? parts.getModuleName() : env.getActiveModuleName();
const crudName = makeFqName(moduleName, parts.getEntryName());
if (crudName == DocEventName) {
return this.genericHandler(env);
}
if (isOpenApiModule(moduleName)) {
return this.genericHandler(env);
}
const module = fetchModule(moduleName);
const record = module.getRecord(escapeQueryName(parts.getEntryName()));
if (record.type == RecordType.EVENT) {
if (isAgentEvent(record)) {
this.graph.pushNode(new ExecGraphNode(env.getActiveUserData(), -2, SubGraphType.AGENT));
this.graph.setHasAgents(true);
return;
}
else {
const g = await generateExecutionGraph(crudName);
if (g) {
return this.addSubGraph(SubGraphType.EVENT, g, env);
}
}
}
this.genericHandler(env);
}
async handleForEach(forEach, env) {
const handler = new GraphGenerator();
const srcEnv = Environment.from(env).setActiveUserData(forEach.src);
await evaluatePattern(forEach.src, srcEnv, handler);
const srcg = handler.getGraph();
const g = await graphFromStatements(forEach.statements, env.getActiveModuleName());
srcg.pushSubGraph(g);
this.addSubGraph(SubGraphType.FOR_EACH, srcg, env);
}
async handleIf(ifStmt, env) {
const handler = new GraphGenerator();
await handler.handleExpression(ifStmt.cond, Environment.from(env).setActiveUserData(ifStmt.cond));
const cond = handler.getGraph();
const conseq = await graphFromStatements(ifStmt.statements, env.getActiveModuleName());
cond.pushSubGraph(conseq);
if (ifStmt.else !== undefined) {
const alter = await graphFromStatements(ifStmt.else.statements, env.getActiveModuleName());
cond.pushSubGraph(alter);
}
else {
cond.pushSubGraph(ExecGraph.Empty);
}
this.addSubGraph(SubGraphType.IF, cond, env);
}
async handleSubPattern(subGraphType, pat, env) {
const newEnv = Environment.from(env).setActiveUserData(pat);
const handler = new GraphGenerator();
await evaluatePattern(pat, newEnv, handler);
this.addSubGraph(subGraphType, handler.getGraph(), env);
}
async handleDelete(del, env) {
this.handleSubPattern(SubGraphType.DELETE, del.pattern, env);
}
async handlePurge(purge, env) {
this.handleSubPattern(SubGraphType.PURGE, purge.pattern, env);
}
async handleFullTextSearch(_, env) {
this.genericHandler(env);
}
async handleReturn(ret, env) {
this.handleSubPattern(SubGraphType.RETURN, ret.pattern, env);
}
getGraph() {
return this.graph;
}
addSubGraph(subGraphType, g, env) {
this.graph.pushSubGraph(g);
this.graph.pushNode(new ExecGraphNode(env.getActiveUserData(), this.graph.getLastSubGraphIndex(), subGraphType));
}
}
async function graphFromStatements(stmts, activeModuleName) {
const handler = new GraphGenerator();
const env = new Environment();
if (activeModuleName) {
env.switchActiveModuleName(activeModuleName);
}
for (let i = 0; i < stmts.length; ++i) {
const stmt = stmts[i];
env.setActiveUserData(stmt);
await evaluatePattern(stmt.pattern, env, handler);
}
return handler.getGraph().setActiveModuleName(activeModuleName);
}
function makeStatementsExecutor(execGraph, triggeringNode) {
return async (stmts, env) => {
const g = await graphFromStatements(stmts, env.getActiveModuleName());
if (execGraph && triggeringNode) {
execGraph.pushSubGraph(g);
triggeringNode.subGraphIndex = execGraph.getLastSubGraphIndex();
}
await executeGraph(g, env);
return env.getLastResult();
};
}
export async function executeGraph(execGraph, env) {
const activeModuleName = execGraph.getActiveModuleName();
env.setEventExecutor(executeEventHelper);
let oldModule = undefined;
if (activeModuleName) {
oldModule = env.switchActiveModuleName(activeModuleName);
}
const coreMod = activeModuleName ? isCoreModule(activeModuleName) : false;
const monitoringEnabled = !coreMod && isMonitoringEnabled();
try {
const walker = new ExecGraphWalker(execGraph);
while (walker.hasNext()) {
if (env.isMarkedForReturn()) {
break;
}
const node = walker.nextNode();
const monitorIncr = monitoringEnabled &&
node.subGraphIndex !== -1 &&
(node.subGraphType == SubGraphType.AGENT || node.subGraphType == SubGraphType.EVENT);
if (node.codeStr && monitoringEnabled) {
if (!isSystemCrudPattern(node.code, activeModuleName)) {
if (monitorIncr) {
env.incrementMonitor();
}
env.appendEntryToMonitor(node.codeStr);
}
}
try {
if (node.subGraphIndex == -1) {
await evaluateStatement(node.code, env);
}
else {
if (node.subGraphType == SubGraphType.AGENT) {
await executeAgent(node, execGraph, env);
}
else {
const subg = execGraph.fetchSubGraphAt(node.subGraphIndex);
switch (node.subGraphType) {
case SubGraphType.EVENT:
await evaluateStatement(node.code, env);
break;
case SubGraphType.IF: {
const newEnv = new Environment(`${env.name}-if`, env);
await executeIfSubGraph(subg, newEnv);
env.setLastResult(newEnv.getLastResult());
break;
}
case SubGraphType.FOR_EACH: {
const newEnv = new Environment(`${env.name}-forEach`, env);
await executeForEachSubGraph(subg, node, newEnv);
env.setLastResult(newEnv.getLastResult());
break;
}
case SubGraphType.DELETE:
await executeDeleteSubGraph(subg, node, env);
break;
case SubGraphType.PURGE:
await executePurgeSubGraph(subg, node, env);
break;
case SubGraphType.RETURN:
await executeReturnSubGraph(subg, env);
return;
default:
throw new Error(`Invalid sub-graph type: ${node.subGraphType}`);
}
}
maybeSetAlias(node, env);
}
}
catch (reason) {
if (monitoringEnabled)
env.setMonitorEntryError(reason);
throw reason;
}
finally {
if (monitoringEnabled) {
if (monitorIncr)
env.decrementMonitor();
env.setMonitorEntryResult(env.getLastResult());
}
}
}
}
finally {
if (oldModule) {
env.switchActiveModuleName(oldModule);
}
}
}
function isSystemCrudPattern(code, activeModuleName) {
if (isStatement(code)) {
return isSystemCrudPattern(code.pattern, activeModuleName);
}
else if (isPattern(code)) {
const crud = code.crudMap;
if (crud) {
if (isFqName(crud.name))
return isCoreDefinition(crud.name);
else if (activeModuleName)
return isCoreModule(activeModuleName);
}
}
return false;
}
async function evaluateFirstPattern(g, env) {
await evaluatePattern(g.getRootNodes()[0].code, env);
}
async function executeForEachSubGraph(subGraph, triggeringNode, env) {
var _a;
await evaluateFirstPattern(subGraph, env);
const rs = env.getLastResult();
if (rs.length > 0) {
const stmt = triggeringNode.code;
const loopVar = ((_a = stmt.pattern.forEach) === null || _a === void 0 ? void 0 : _a.var) || 'x';
const loopEnv = new Environment('for-each-body-env', env);
const loopg = subGraph.fetchForEachBodySubGraph();
const finalResult = new Array();
for (let i = 0; i < rs.length; ++i) {
loopEnv.bind(loopVar, rs[i]);
await executeGraph(loopg, loopEnv);
finalResult.push(loopEnv.getLastResult());
}
env.setLastResult(finalResult);
}
else {
env.setLastResult([]);
}
}
async function executeIfSubGraph(subGraph, env) {
await evaluateExpression(subGraph.getRootNodes()[0].code, env);
const newEnv = new Environment('cond-env', env);
if (env.getLastResult()) {
const conseq = subGraph.fetchIfConsequentSubGraph();
await executeGraph(conseq, newEnv);
}
else {
const alter = subGraph.fetchIfAlternativeSubGraph();
if (alter) {
if (ExecGraph.isEmpty(alter)) {
newEnv.setLastResult(false);
}
else {
await executeGraph(alter, newEnv);
}
}
}
env.setLastResult(newEnv.getLastResult());
}
async function executeAgent(triggeringNode, execGraph, env) {
await env.callWithStatementsExecutor(makeStatementsExecutor(execGraph, triggeringNode), async () => {
await evaluateStatement(triggeringNode.code, env);
return env.getLastResult();
});
}
async function executeReturnSubGraph(subGraph, env) {
await evaluateFirstPattern(subGraph, env);
env.markForReturn();
}
async function executeDeleteSubGraph(subGraph, node, env) {
const newEnv = new Environment(`delete-env`, env).setInDeleteMode(true);
await evaluateFirstPattern(subGraph, newEnv);
await maybeDeleteQueriedInstances(newEnv, env, false);
maybeSetAlias(node, env);
}
async function executePurgeSubGraph(subGraph, node, env) {
const newEnv = new Environment(`purge-env`, env).setInDeleteMode(true);
await evaluateFirstPattern(subGraph, newEnv);
await maybeDeleteQueriedInstances(newEnv, env, true);
maybeSetAlias(node, env);
}
export async function executeEvent(eventInstance, continuation, activeEnv, kernelCall) {
const env = new Environment(eventInstance.name + '.env', activeEnv);
env.setStatementsExecutor(executeStatementsHelper);
let txnRolledBack = false;
try {
if (isEventInstance(eventInstance)) {
if (kernelCall) {
env.setInKernelMode(true);
}
env.setActiveEvent(eventInstance);
await executeEventHelper(eventInstance, env);
}
else if (isAgentEventInstance(eventInstance)) {
await handleAgentInvocation(eventInstance, env);
}
const r = env.getLastResult();
if (continuation)
continuation(r);
return r;
}
catch (err) {
if (env && env.hasHandlers()) {
throw err;
}
else {
if (env !== undefined && activeEnv === undefined) {
await env.rollbackAllTransactions().then(() => {
txnRolledBack = true;
});
}
throw err;
}
}
finally {
if (!txnRolledBack && env !== undefined && activeEnv === undefined) {
await env.commitAllTransactions();
}
if (isMonitoringEnabled()) {
await flushMonitoringData(eventInstance.getId());
}
}
}
export async function executeEventHelper(eventInstance, env) {
if (isOpenApiEventInstance(eventInstance)) {
env = env || new Environment();
await handleOpenApiEvent(eventInstance, env);
return env.getLastResult();
}
const fqn = eventInstance.getFqName();
let isLocalEnv = false;
if (env === undefined) {
env = new Environment(`${fqn}-env`);
isLocalEnv = true;
}
let g;
if (!isAgentEventInstance(eventInstance)) {
g = await generateExecutionGraph(fqn);
if (!g) {
throw new Error(`Failed to generate graph for event ${fqn}`);
}
}
const oldModuleName = env.switchActiveModuleName(eventInstance.moduleName);
env.bind(eventInstance.name, eventInstance);
try {
if (g) {
await executeGraph(g, env);
}
else {
if (isMonitoringEnabled()) {
env.appendEntryToMonitor(`{${eventInstance.getFqName()} {message "${eventInstance.lookup('message')}"}}`);
}
await handleAgentInvocation(eventInstance, env);
}
if (isLocalEnv) {
await env.commitAllTransactions();
}
return env.getLastResult();
}
catch (err) {
if (isLocalEnv) {
await env.rollbackAllTransactions();
}
throw err;
}
finally {
if (!isLocalEnv)
env.switchActiveModuleName(oldModuleName);
}
}
export async function executeStatement(stmt, env, activeModule) {
return await executeStatements([stmt], env, activeModule);
}
export async function executeStatements(stmts, env, activeModule) {
const mod = await parseModule(`module Temp\nworkflow TempEvent { ${stmts.join(';')} }`);
if (isWorkflowDefinition(mod.defs[0])) {
return await executeStatementsHelper(mod.defs[0].statements, env, activeModule);
}
else {
throw new Error('Failed to extract workflow-statement');
}
}
async function executeStatementsHelper(stmts, env, activeModule) {
const g = await graphFromStatements(stmts);
let isLocalEnv = false;
if (env === undefined) {
env = new Environment(`stmt-exec-env`);
isLocalEnv = true;
}
let oldModuleName = undefined;
if (activeModule) {
oldModuleName = env.switchActiveModuleName(activeModule);
}
try {
await executeGraph(g, env);
if (isLocalEnv) {
await env.commitAllTransactions();
}
return env.getLastResult();
}
catch (err) {
if (isLocalEnv) {
await env.rollbackAllTransactions();
}
throw err;
}
finally {
if (oldModuleName) {
env.switchActiveModuleName(oldModuleName);
}
}
}
async function executeStatementHelper(stmt, env) {
return await executeStatementsHelper([stmt], env);
}
export async function parseAndExecuteStatement(stmtString, activeUserId, actievEnv) {
const env = actievEnv ? actievEnv : new Environment();
if (activeUserId) {
env.setActiveUser(activeUserId);
}
let commit = true;
try {
const stmt = await parseStatement(stmtString);
if (stmt) {
await executeStatementHelper(stmt, env);
return env.getLastResult();
}
else {
commit = false;
}
}
catch (err) {
commit = false;
throw err;
}
finally {
if (!actievEnv) {
if (commit) {
await env.commitAllTransactions();
}
else {
await env.rollbackAllTransactions();
}
}
}
}
function maybeSetAlias(node, env) {
const stmt = node.code;
const hints = stmt.hints;
if (hints && hints.length > 0) {
maybeBindStatementResultToAlias(hints, env);
}
}
export function enableExecutionGraph() {
const e = setEvaluateFn(executeEvent);
const es = setParseAndEvaluateStatementFn(parseAndExecuteStatement);
return { evaluate: e, parseAndEvaluateStatement: es };
}
export function disableExecutionGraph(oldFns) {
if (oldFns.evaluate && oldFns.parseAndEvaluateStatement) {
setEvaluateFn(oldFns.evaluate);
setParseAndEvaluateStatementFn(oldFns.parseAndEvaluateStatement);
return true;
}
return false;
}
//# sourceMappingURL=exec-graph.js.map