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
1,553 lines (1,552 loc) • 106 kB
JavaScript
import chalk from 'chalk';
import { isRelNodes, isLiteral, } from '../language/generated/ast.js';
import { Path, nameToPath, isString, isNumber, isBoolean, isFqName, makeFqName, DefaultModuleName, DefaultModules, joinStatements, isMinusZero, now, findMetaSchema, findAllPrePostTriggerSchema, asCrudType, isPath, findUqCompositeAttributes, escapeFqName, encryptPassword, splitFqName, splitRefs, forceAsFqName, validateIdFormat, nameContainsSepEscape, registerInitFunction, } from './util.js';
import { parseStatement } from '../language/parser.js';
import { AdminSession } from './auth/defs.js';
import { FetchModuleFn, PathAttributeName } from './defs.js';
import { logger } from './logger.js';
import { CasePattern, FlowStepPattern } from '../language/syntax.js';
import { getAgentDirectives, getAgentDirectivesJson, getAgentGlossary, getAgentGlossaryJson, getAgentResponseSchema, getAgentScenarios, getAgentScenariosJson, registerAgentDirectives, registerAgentGlossary, registerAgentResponseSchema, registerAgentScenarios, removeAgentDirectives, removeAgentGlossary, removeAgentResponseSchema, removeAgentScenarios, } from './agents/common.js';
import { isNode } from '../utils/fs-utils.js';
export class ModuleEntry {
constructor(name, moduleName) {
this.taggedAsPublic = false;
if (nameContainsSepEscape(name)) {
throw new Error(`Name cannot contain reserved escape characters - ${name}`);
}
this.name = name;
this.moduleName = moduleName;
}
getFqName() {
return makeFqName(this.moduleName, this.name);
}
setPublic(flag) {
this.taggedAsPublic = flag;
return this;
}
isPublic() {
return this.taggedAsPublic;
}
}
function normalizePropertyNames(props) {
// Convert iterator to array for compatibility with different Node.js versions
const normKs = Array.from(props.keys()).filter((k) => {
return k.charAt(0) === '@';
});
normKs.forEach((k) => {
const v = props.get(k);
props.delete(k);
props.set(k.substring(1), v);
});
}
const SystemAttributeProperty = 'system-attribute';
const SystemDefinedEvent = 'system-event';
function asSystemAttribute(attrSpec) {
const props = attrSpec.properties ? attrSpec.properties : new Map();
props.set(SystemAttributeProperty, true);
attrSpec.properties = props;
return attrSpec;
}
function isSystemAttribute(attrSpec) {
if (attrSpec.properties) {
return attrSpec.properties.get(SystemAttributeProperty) == true;
}
return false;
}
function recordSchemaToString(scm) {
const ss = [];
scm.forEach((attrSpec, n) => {
if (!isSystemAttribute(attrSpec)) {
ss.push(` ${n} ${attributeSpecToString(attrSpec)}`);
}
});
return `\n${ss.join(',\n')}`;
}
function attributeSpecToString(attrSpec) {
let s = getEnumValues(attrSpec) || getOneOfRef(attrSpec) ? '' : `${attrSpec.type}`;
if (isArrayAttribute(attrSpec)) {
s = `${s}[]`;
}
if (attrSpec.properties) {
const ps = [];
const hasEnum = attrSpec.properties.has('enum');
const hasOneOf = attrSpec.properties.has('oneof');
const needsReordering = hasEnum || hasOneOf;
if (needsReordering) {
const priorityKeys = ['enum', 'oneof'];
const processedKeys = new Set();
priorityKeys.forEach(k => {
if (attrSpec.properties.has(k)) {
const v = attrSpec.properties.get(k);
if (v == true)
ps.push(` @${k}`);
else
ps.push(` @${k}(${attributePropertyValueToString(k, v, attrSpec.type)})`);
processedKeys.add(k);
}
});
attrSpec.properties.forEach((v, k) => {
if (k !== 'array' && !processedKeys.has(k)) {
if (v == true)
ps.push(` @${k}`);
else
ps.push(` @${k}(${attributePropertyValueToString(k, v, attrSpec.type)})`);
}
});
}
else {
attrSpec.properties.forEach((v, k) => {
if (k != 'array') {
if (v == true)
ps.push(` @${k}`);
else
ps.push(` @${k}(${attributePropertyValueToString(k, v, attrSpec.type)})`);
}
});
}
s = s.concat(ps.join(' '));
}
return s;
}
function attributePropertyValueToString(propName, propValue, attrType) {
if (propName == EnumPropertyName) {
const v = propValue;
const ss = new Array();
v.forEach((s) => {
ss.push(`"${s}"`);
});
return ss.join(',');
}
else if (propName == 'default') {
if (isTextualType(attrType) && propValue != 'now()' && propValue != 'uuid()') {
return `"${propValue}"`;
}
}
else if (propName == 'comment') {
return `"${propValue}"`;
}
return `${propValue}`;
}
export function newRecordSchema() {
return new Map();
}
export function newMeta() {
return new Map();
}
export var RecordType;
(function (RecordType) {
RecordType[RecordType["RECORD"] = 0] = "RECORD";
RecordType[RecordType["ENTITY"] = 1] = "ENTITY";
RecordType[RecordType["EVENT"] = 2] = "EVENT";
RecordType[RecordType["RELATIONSHIP"] = 3] = "RELATIONSHIP";
RecordType[RecordType["AGENT"] = 4] = "AGENT";
})(RecordType || (RecordType = {}));
function normalizeMetaValue(metaValue) {
if (!isLiteral(metaValue)) {
throw new Error(`Invalid entry ${metaValue} in meta specification - expected a literal`);
}
const v = metaValue;
if (v.array) {
return v.array.vals.map((value) => {
return normalizeMetaValue(value.pattern.expr);
});
}
else if (v.bool !== undefined) {
return v.bool == 'true' ? true : false;
}
else if (v.id) {
return v.id;
}
else if (v.map) {
const result = new Map();
v.map.entries.forEach((value) => {
result.set(value.key, normalizeMetaValue(value.value));
});
return result;
}
else if (v.ref) {
return v.ref;
}
else if (v.num) {
return v.num;
}
else if (v.str) {
return v.str;
}
else {
throw new Error(`Invalid value ${metaValue} passed to meta specification`);
}
}
function asTriggerInfo(te) {
return {
eventName: te.event,
async: te.async ? true : false,
};
}
const EnumPropertyName = 'enum';
const OneOfPropertyName = 'oneof';
export function enumAttributeSpec(values) {
return {
type: 'String',
properties: new Map().set(EnumPropertyName, values),
};
}
export function oneOfAttributeSpec(ref) {
return {
type: 'String',
properties: new Map().set(OneOfPropertyName, ref),
};
}
export class Record extends ModuleEntry {
constructor(name, moduleName, scm, parentEntryName) {
super(name, moduleName);
this.type = RecordType.RECORD;
this.parentEntryName = parentEntryName;
this.schema = parentEntryName
? cloneParentSchema(parentEntryName, moduleName)
: newRecordSchema();
const attributes = scm ? scm.attributes : undefined;
if (attributes !== undefined) {
attributes.forEach((a) => {
var _a, _b;
verifyAttribute(a);
let props = asPropertiesMap(a.properties);
const isArrayType = a.arrayType ? true : false;
let t = isArrayType ? a.arrayType : a.type;
if (a.refSpec) {
let fp = a.refSpec.ref;
const rp = nameToPath(fp);
if (!rp.hasModule()) {
rp.setModuleName(this.moduleName);
fp = rp.asFqName();
}
if (props === undefined) {
props = new Map();
}
props.set('ref', escapeFqName(fp));
t = a.refSpec.type === undefined ? 'Any' : a.refSpec.type;
}
const enumValues = (_a = a.enumSpec) === null || _a === void 0 ? void 0 : _a.values;
const oneOfRef = (_b = a.oneOfSpec) === null || _b === void 0 ? void 0 : _b.ref;
if (!t) {
if (enumValues || oneOfRef) {
t = 'String';
}
else {
throw new Error(`Attribute ${a.name} requires a type`);
}
}
if (a.expr) {
if (props === undefined) {
props = new Map();
}
props.set('expr', a.expr).set('optional', true);
}
const isObjectType = t == 'Map' || !isBuiltInType(t);
if (isArrayType || isObjectType || enumValues || oneOfRef) {
if (props === undefined) {
props = new Map();
}
if (isArrayType)
props.set('array', true);
if (isObjectType)
props.set('object', true);
if (enumValues)
props.set(EnumPropertyName, new Set(enumValues));
if (oneOfRef) {
props.set(OneOfPropertyName, oneOfRef);
this.addOneOfRefAttribute(a.name);
}
}
this.schema.set(a.name, { type: t, properties: props });
});
}
const meta = findMetaSchema(scm);
if (meta) {
meta.spec.entries.forEach((entry) => {
if (entry.key.str)
this.addMeta(entry.key.str, normalizeMetaValue(entry.value));
else
throw new Error(`Key must be a string for meta-definition in ${this.moduleName}/${this.name}`);
});
}
const prepostTrigs = findAllPrePostTriggerSchema(scm);
if (prepostTrigs) {
prepostTrigs.forEach((ppt) => {
if (ppt.after) {
if (this.afterTriggers === undefined) {
this.afterTriggers = new Map();
}
ppt.after.triggers.entries.forEach((te) => {
if (this.afterTriggers)
this.afterTriggers.set(asCrudType(te.on), asTriggerInfo(te));
});
}
else if (ppt.before) {
if (this.beforeTriggers === undefined) {
this.beforeTriggers = new Map();
}
ppt.before.triggers.entries.forEach((te) => {
if (this.beforeTriggers)
this.beforeTriggers.set(asCrudType(te.on), asTriggerInfo(te));
});
}
});
}
this.compositeUqAttributes = findUqCompositeAttributes(scm);
}
addMetaAttributes() {
this.schema
.set(SysAttr_Created, SysAttr_CreatedSpec)
.set(SysAttr_CreatedBy, SysAttr_CreatedBySpec)
.set(SysAttr_LastModified, SysAttr_LastModifiedSpec)
.set(SysAttr_LastModifiedBy, SysAttr_LastModifiedBySpec);
return this;
}
addOneOfRefAttribute(s) {
if (this.oneOfRefAttributes === undefined) {
this.oneOfRefAttributes = [];
}
this.oneOfRefAttributes.push(s);
return this;
}
addAfterTrigger(te) {
var _a;
if (this.afterTriggers === undefined) {
this.afterTriggers = new Map();
}
(_a = this.afterTriggers) === null || _a === void 0 ? void 0 : _a.set(asCrudType(te.on), asTriggerInfo(te));
return this;
}
addBeforeTrigger(te) {
var _a;
if (this.beforeTriggers === undefined) {
this.beforeTriggers = new Map();
}
(_a = this.beforeTriggers) === null || _a === void 0 ? void 0 : _a.set(asCrudType(te.on), asTriggerInfo(te));
return this;
}
getCompositeUniqueAttributes() {
return this.compositeUqAttributes;
}
getPreTriggerInfo(crudType) {
if (this.beforeTriggers) {
return this.beforeTriggers.get(crudType);
}
return undefined;
}
getPostTriggerInfo(crudType) {
if (this.afterTriggers) {
return this.afterTriggers.get(crudType);
}
return undefined;
}
addMeta(k, v) {
if (!this.meta) {
this.meta = newMeta();
}
this.meta.set(k, v);
}
getMeta(k) {
if (this.meta) {
return this.meta.get(k);
}
else {
return undefined;
}
}
getFullTextSearchAttributes() {
const fts = this.getMeta('fullTextSearch');
if (fts) {
if (fts instanceof Array) {
return fts;
}
else if (fts == '*') {
return [...this.schema.keys()];
}
else {
return undefined;
}
}
else {
return undefined;
}
}
addAttribute(n, attrSpec) {
if (this.schema.has(n)) {
throw new Error(`Attribute named ${n} already exists in ${this.moduleName}.${this.name}`);
}
if (attrSpec.properties !== undefined) {
normalizePropertyNames(attrSpec.properties);
}
this.schema.set(n, attrSpec);
return this;
}
removeAttribute(n) {
this.schema.delete(n);
return this;
}
reorderAttributes(desiredOrder) {
this.schema = new Map([...this.schema].sort((a, b) => {
return desiredOrder.indexOf(a[0]) - desiredOrder.indexOf(b[0]);
}));
}
addSystemAttribute(n, attrSpec) {
asSystemAttribute(attrSpec);
this.addAttribute(n, attrSpec);
return this;
}
findAttribute(predic) {
for (const k of this.schema.keys()) {
const attrSpec = this.schema.get(k);
if (attrSpec !== undefined) {
if (predic(attrSpec))
return {
name: k,
spec: attrSpec,
};
}
}
return undefined;
}
hasRefTo(modName, entryName) {
if (this.findAttribute((attrSpec) => {
if (attrSpec.properties !== undefined) {
const ref = attrSpec.properties.get('ref');
if (ref !== undefined) {
if (ref.getModuleName() == modName && ref.getEntryName() == entryName) {
return true;
}
}
}
return false;
}))
return true;
else
return false;
}
getRefOnAttribute(attrName) {
const fkspecs = this.getFkAttributeSpecs();
const a = fkspecs.find((v) => {
return v.columnName === attrName;
});
if (a) {
return [makeFqName(a.targetModuleName, a.targetEntityName), a.targetColumnName];
}
return undefined;
}
getIdAttributeName() {
const e = this.findAttribute((attrSpec) => {
return isIdAttribute(attrSpec);
});
if (e !== undefined) {
return e.name;
}
return undefined;
}
getFkAttributeSpecs() {
const result = new Array();
this.schema.forEach((attrSpec, columnName) => {
const refSpec = getRefSpec(attrSpec);
if (refSpec) {
const targetNames = forceAsFqName(refSpec, this.moduleName);
const parts = splitFqName(targetNames);
const targetModuleName = parts[0];
const refs = splitRefs(parts[1]);
const targetEntityName = refs[0];
let targetColumnName = '';
if (refs.length <= 1) {
targetColumnName = PathAttributeName;
}
else {
targetColumnName = refs[1];
}
result.push({
moduleName: this.moduleName,
entityName: this.name,
columnName,
targetModuleName,
targetEntityName,
targetColumnName,
onDelete: 'SET NULL',
onUpdate: 'CASCADE',
});
}
});
return result;
}
toString() {
return this.toString_();
}
toString_(internParentSchema = false) {
if (this.type == RecordType.EVENT && this.meta && this.meta.get(SystemDefinedEvent)) {
return '';
}
let s = `${RecordType[this.type].toLowerCase()} ${this.name}`;
let scm = this.schema;
if (this.parentEntryName && !internParentSchema) {
s = s.concat(` extends ${this.parentEntryName}`);
scm = newRecordSchema();
let modName = this.moduleName;
let pname = this.parentEntryName;
if (isFqName(pname)) {
const parts = splitFqName(pname);
modName = parts[0];
pname = parts[1];
}
const p = fetchModule(modName).getEntry(pname);
const pks = new Set(p.schema.keys());
this.schema.forEach((v, n) => {
if (!pks.has(n)) {
scm.set(n, v);
}
});
}
let scms = recordSchemaToString(scm);
if (this.rbac && this.rbac.length > 0) {
const rbs = this.rbac.map((rs) => {
return rs.toString();
});
scms = `${scms},\n @rbac [${rbs.join(',\n')}]`;
}
if (this.meta && this.meta.size > 0) {
const metaObj = Object.fromEntries(this.meta);
const ms = `@meta ${JSON.stringify(metaObj)}`;
scms = `${scms},\n ${ms}`;
}
if (this.isPublic()) {
s = `@public ${s}`;
}
return s.concat('\n{', scms, '\n}\n');
}
getUserAttributes() {
const recSchema = newRecordSchema();
this.schema.forEach((attrSpec, n) => {
if (!isSystemAttribute(attrSpec)) {
recSchema.set(n, attrSpec);
}
});
return recSchema;
}
getUserAttributeNames() {
return [...this.getUserAttributes().keys()];
}
}
function fetchModuleByEntryName(entryName, suspectModuleName) {
if (isFqName(entryName)) {
const path = nameToPath(entryName);
entryName = path.getEntryName();
suspectModuleName = path.getModuleName();
}
return {
module: fetchModule(suspectModuleName),
entryName: entryName,
moduleName: suspectModuleName,
};
}
function cloneParentSchema(parentName, currentModuleName) {
const fr = fetchModuleByEntryName(parentName, currentModuleName);
parentName = fr.entryName;
currentModuleName = fr.moduleName;
const mod = fr.module;
const entry = mod.getEntry(parentName);
const result = newRecordSchema();
entry.schema.forEach((attrSpec, attrName) => {
result.set(attrName, attrSpec);
});
return result;
}
function asPropertiesMap(props) {
if (props !== undefined && props.length > 0) {
const result = new Map();
props.forEach((p) => {
const n = p.name.substring(1);
if (p.value !== undefined && p.value.pairs !== undefined && p.value.pairs.length > 0) {
if (p.value.pairs.length == 1) {
const kvp = p.value.pairs[0];
if (kvp.key === undefined) {
result.set(n, normalizeKvPairValue(kvp));
}
else {
const v = new Map();
v.set(kvp.key, normalizeKvPairValue(kvp));
result.set(n, v);
}
}
else {
const v = new Map();
p.value.pairs.forEach((kvp) => {
let k = 'null';
if (kvp.key !== undefined)
k = kvp.key;
v.set(k, normalizeKvPairValue(kvp));
});
result.set(n, v);
}
}
else {
result.set(n, true);
}
});
return maybeProcessRefProperty(result);
}
return undefined;
}
function maybeProcessRefProperty(props) {
const v = props.get('ref');
if (v !== undefined) {
const parts = nameToPath(v);
if (!parts.hasModule()) {
parts.setModuleName(activeModule);
}
props.set('ref', parts);
}
return props;
}
function normalizeKvPairValue(kvp) {
const v = kvp.value;
if (v === undefined)
return true;
if (v.str !== undefined) {
return v.str;
}
else if (v.num !== undefined) {
return v.num;
}
else if (v.bool !== undefined) {
return v.bool === 'true' ? true : false;
}
else if (v.id !== undefined) {
return v.id;
}
else if (v.ref !== undefined) {
return v.ref;
}
else if (v.fnCall !== undefined) {
const fncall = v.fnCall;
if (fncall.args.length > 0) {
throw new Error('Cannot allow arguments in properties function-call');
}
return fncall.name + '()';
}
else if (v.array !== undefined) {
return v.array;
}
return null;
}
export const PlaceholderRecordEntry = new Record('--', DefaultModuleName);
export var RbacPermissionFlag;
(function (RbacPermissionFlag) {
RbacPermissionFlag[RbacPermissionFlag["CREATE"] = 0] = "CREATE";
RbacPermissionFlag[RbacPermissionFlag["READ"] = 1] = "READ";
RbacPermissionFlag[RbacPermissionFlag["UPDATE"] = 2] = "UPDATE";
RbacPermissionFlag[RbacPermissionFlag["DELETE"] = 3] = "DELETE";
})(RbacPermissionFlag || (RbacPermissionFlag = {}));
export class RbacSpecification {
constructor() {
this.resource = '';
this.roles = RbacSpecification.EmptyRoles;
this.permissions = new Set();
}
static from(def) {
const result = new RbacSpecification();
def.entries.forEach((se) => {
if (se.role) {
result.setRoles(se.role.roles);
}
else if (se.allow) {
result.setPermissions(se.allow.oprs.map((opr) => {
return opr.value;
}));
}
else if (se.expr) {
result.setExpression(se.expr.lhs, se.expr.rhs);
}
});
return result;
}
setResource(s) {
this.resource = s;
return this;
}
hasResource() {
return this.resource.length > 0;
}
setPermissions(perms) {
const ps = new Set();
perms.forEach((v) => {
const idx = v.toUpperCase();
const a = RbacPermissionFlag[idx];
if (a === undefined) {
throw new Error(`Not a valid RBAC permission - ${v}`);
}
ps.add(a);
});
this.permissions = ps;
return this;
}
hasPermissions() {
return this.permissions.size > 0;
}
hasCreatePermission() {
return this.permissions.has(RbacPermissionFlag.CREATE);
}
hasReadPermission() {
return this.permissions.has(RbacPermissionFlag.READ);
}
hasUpdatePermission() {
return this.permissions.has(RbacPermissionFlag.UPDATE);
}
hasDeletePermission() {
return this.permissions.has(RbacPermissionFlag.DELETE);
}
setRoles(roles) {
if (this.expression) {
throw new Error('Cannot set roles while `where` expression is set');
}
this.roles = new Set();
roles.forEach((r) => {
this.roles.add(r);
});
return this;
}
removeRoles() {
this.roles = RbacSpecification.EmptyRoles;
return this;
}
setExpression(lhs, rhs) {
if (this.roles != RbacSpecification.EmptyRoles) {
logger.warn('Cannot set `where` expression along with roles, removing roles');
this.removeRoles();
}
this.expression = {
lhs: lhs,
rhs: rhs,
};
return this;
}
removeExpression() {
this.expression = undefined;
return this;
}
toString() {
if (this.permissions.size <= 0) {
throw new Error(`Cannot emit RbacSpecification, no permissions are set`);
}
const rs = new Array();
this.roles.forEach((r) => {
rs.push(r);
});
let cond = '';
if (this.expression) {
cond = `where: ${this.expression.lhs} = ${this.expression.rhs}`;
}
else {
cond = `roles: [${rs.join(',')}]`;
}
const perms = new Array();
this.permissions.forEach((p) => {
perms.push(RbacPermissionFlag[p].toLowerCase());
});
return `(${cond}, allow: [${perms.join(',')}])`;
}
}
RbacSpecification.EmptyRoles = new Set();
export class Agent extends Record {
constructor(name, moduleName, attrs) {
super(Agent.EscapeName(name), moduleName);
this.type = RecordType.AGENT;
this.attributes = attrs ? attrs : newInstanceAttributes();
}
setName(n) {
this.name = Agent.EscapeName(n);
return this;
}
setLLM(llm) {
this.attributes.set('llm', llm);
return this;
}
getLLM() {
return this.attributes.get('llm');
}
removeAgentAttribute(n) {
this.attributes.delete(n);
return this;
}
removeLLM() {
return this.removeAgentAttribute('llm');
}
setInstruction(s) {
this.attributes.set('instruction', s);
return this;
}
getInstruction() {
return this.attributes.get('instruction');
}
removeInstruction() {
return this.removeAgentAttribute('instruction');
}
setType(type) {
this.attributes.set('type', type);
return this;
}
getType() {
return this.attributes.get('type');
}
removeType() {
return this.removeAgentAttribute('type');
}
setStrings(attrName, v) {
this.attributes.set(attrName, v.join(','));
return this;
}
getStrings(attrName) {
const v = this.attributes.get(attrName);
if (v) {
return v.split(',');
}
else {
return undefined;
}
}
setTools(tools) {
return this.setStrings('tools', tools);
}
getTools() {
return this.getStrings('tools');
}
removeTools() {
return this.removeAgentAttribute('tools');
}
setDocuments(docs) {
return this.setStrings('documents', docs);
}
getDocuments() {
return this.getStrings('documents');
}
removeDocuments() {
return this.removeAgentAttribute('documents');
}
setFlows(flows) {
return this.setStrings('flows', flows);
}
getFlows() {
return this.getStrings('flows');
}
getAgentFqName() {
return makeFqName(this.moduleName, this.getName());
}
setDirectives(conds) {
registerAgentDirectives(this.getAgentFqName(), conds);
return this;
}
removeDirectives() {
removeAgentDirectives(this.getAgentFqName());
return this;
}
getDirectives() {
return getAgentDirectives(this.getAgentFqName());
}
setScenarios(scenarios) {
registerAgentScenarios(this.getAgentFqName(), scenarios);
return this;
}
getScenarios() {
return getAgentScenarios(this.getAgentFqName());
}
removeScenarios() {
removeAgentScenarios(this.getAgentFqName());
return this;
}
setGlossary(glossary) {
registerAgentGlossary(this.getAgentFqName(), glossary);
return this;
}
getGlossary() {
return getAgentGlossary(this.getAgentFqName());
}
removeGlossary() {
removeAgentGlossary(this.getAgentFqName());
return this;
}
setResponseSchema(entryName) {
registerAgentResponseSchema(this.getAgentFqName(), entryName);
return this;
}
getResponseSchema() {
return getAgentResponseSchema(this.getAgentFqName());
}
removeResponseSchema() {
removeAgentResponseSchema(this.getAgentFqName());
return this;
}
toString() {
const attrs = new Array();
this.attributes.forEach((value, key) => {
const skip = key == 'moduleName' || (key == 'type' && value == 'flow-exec');
if (!skip && value !== null && value !== undefined) {
let v = value;
const isf = key == 'flows';
if (isf || key == 'tools') {
if (isf || v.indexOf(',') > 0 || v.indexOf('/') > 0)
v = `[${v}]`;
else
v = `"${v}"`;
}
else if (isString(v)) {
v = `"${v}"`;
}
attrs.push(` ${key} ${v}`);
}
});
const fqName = makeFqName(this.moduleName, this.getName());
const conds = getAgentDirectivesJson(fqName);
if (conds) {
attrs.push(` directives ${conds}`);
}
const scns = getAgentScenariosJson(fqName);
if (scns) {
attrs.push(` scenarios ${scns}`);
}
const gls = getAgentGlossaryJson(fqName);
if (gls) {
attrs.push(` glossary ${gls}`);
}
const rscm = getAgentResponseSchema(fqName);
if (rscm) {
attrs.push(` responseSchema ${rscm}`);
}
const s = `agent ${Agent.NormalizeName(this.name)}
{
${attrs.join(',\n')}
}`;
if (this.isPublic()) {
return `@public ${s}`;
}
else {
return s;
}
}
static EscapeName(n) {
if (n.endsWith(Agent.Suffix)) {
return n;
}
return `${n}${Agent.Suffix}`;
}
static NormalizeName(n) {
if (n.endsWith(Agent.Suffix)) {
return n.substring(0, n.lastIndexOf(Agent.Suffix));
}
else {
return n;
}
}
getName() {
return Agent.NormalizeName(this.name);
}
}
Agent.Suffix = '_agent';
const SysAttr_Created = '__created';
const SysAttr_LastModified = '__last_modified';
const SysAttr_CreatedBy = '__created_by';
const SysAttr_LastModifiedBy = '__last_modified_by';
const SysAttr_CreatedSpec = asSystemAttribute({
type: 'DateTime',
properties: new Map().set('default', 'now()'),
});
const SysAttr_LastModifiedSpec = SysAttr_CreatedSpec;
const SysAttr_CreatedBySpec = asSystemAttribute({
type: 'String',
properties: new Map().set('optional', true),
});
const SysAttr_LastModifiedBySpec = SysAttr_CreatedBySpec;
export class Entity extends Record {
constructor(name, moduleName, scm, parentEntryName) {
super(name, moduleName, scm, parentEntryName);
this.type = RecordType.ENTITY;
this.addMetaAttributes();
}
setRbacSpecifications(rbac) {
this.rbac = rbac;
return this;
}
getRbacSpecifications() {
return this.rbac;
}
isConfigEntity() {
const v = this.getMeta('configEntity');
return v == true;
}
}
export class Event extends Record {
constructor() {
super(...arguments);
this.type = RecordType.EVENT;
}
isSystemDefined() {
var _a;
return ((_a = this.meta) === null || _a === void 0 ? void 0 : _a.get(SystemDefinedEvent)) === 'true';
}
}
var RelType;
(function (RelType) {
RelType[RelType["CONTAINS"] = 0] = "CONTAINS";
RelType[RelType["BETWEEN"] = 1] = "BETWEEN";
})(RelType || (RelType = {}));
export function newRelNodeEntry(nodeFqName, alias) {
const p = nameToPath(nodeFqName);
return {
path: p,
alias: alias ? alias : p.getEntryName(),
origName: nodeFqName,
origAlias: alias,
};
}
function relNodeEntryToString(node) {
let n = `${node.origName}`;
if (node.origAlias) {
n = n.concat(` @as ${node.origAlias}`);
}
return n;
}
function asRelNodeEntry(n) {
const path = nameToPath(n.name);
let modName = activeModule;
const entryName = path.getEntryName();
if (path.hasModule()) {
modName = path.getModuleName();
}
let alias = entryName;
if (n.alias !== undefined) {
alias = n.alias;
}
return {
path: new Path(modName, entryName),
alias: alias,
origName: n.name,
origAlias: n.alias,
};
}
const OneToOne = 'one_one';
const OneToMany = 'one_many';
const ManyToMany = 'many_many';
export class Relationship extends Record {
constructor(name, typ, node1, node2, moduleName, scm, props) {
super(name, moduleName, scm);
this.type = RecordType.RELATIONSHIP;
this.relType = RelType.CONTAINS;
if (typ == 'between') {
this.relType = RelType.BETWEEN;
this.addMetaAttributes();
}
this.node1 = node1;
this.node2 = node2;
this.properties = props;
this.updateSchemaWithNodeAttributes();
}
updateSchemaWithNodeAttributes() {
const attrSpec1 = {
type: 'string',
};
this.addSystemAttribute(this.node1.alias, attrSpec1);
const attrSpec2 = {
type: 'string',
};
this.addSystemAttribute(this.node2.alias, attrSpec2);
if (this.relType == RelType.BETWEEN && this.isOneToMany()) {
const attrSpec3 = {
type: 'string',
properties: new Map().set('unique', true),
};
this.addSystemAttribute(this.joinNodesAttributeName(), attrSpec3);
}
}
joinNodesAttributeName() {
return this.node1.alias + '_' + this.node2.alias;
}
setBetweenRef(inst, refPath, isQuery = false) {
const refAttrName = `__${this.node1.alias.toLowerCase()}`;
if (isQuery) {
inst.addQuery(refAttrName, '=', refPath);
}
else {
inst.attributes.set(refAttrName, refPath);
}
}
isContains() {
return this.relType == RelType.CONTAINS;
}
isBetween() {
return this.relType == RelType.BETWEEN;
}
parentNode() {
return this.node1;
}
childNode() {
return this.node2;
}
hasBooleanFlagSet(flag) {
if (this.properties !== undefined) {
return this.properties.get(flag) == true;
}
return false;
}
setProperty(p, v) {
if (this.properties === undefined) {
this.properties = new Map();
}
this.properties.set(p, v);
return this;
}
isOneToOne() {
return this.isBetween() && this.hasBooleanFlagSet(OneToOne);
}
isOneToMany() {
return this.isBetween() && this.hasBooleanFlagSet(OneToMany);
}
isManyToMany() {
if (this.isBetween()) {
return (this.hasBooleanFlagSet(ManyToMany) ||
(!this.hasBooleanFlagSet(OneToOne) && !this.hasBooleanFlagSet(OneToMany)));
}
else {
return false;
}
}
setOneToOne(flag = true) {
if (flag) {
this.setOneToMany(false).setManyToMany(false);
}
return this.setProperty(OneToOne, flag);
}
setOneToMany(flag = true) {
if (flag) {
this.setOneToOne(false).setManyToMany(false);
}
return this.setProperty(OneToMany, flag);
}
setManyToMany(flag = true) {
this.setOneToOne(false).setOneToMany(false);
return this.setProperty(ManyToMany, flag);
}
isFirstNode(inst) {
return this.isFirstNodeName(inst.getFqName());
}
getAliasFor(inst) {
return this.getAliasForName(inst.getFqName());
}
getInverseAliasFor(inst) {
return this.getInverseAliasForName(inst.getFqName());
}
isFirstNodeName(fqName) {
return fqName == this.node1.path.asFqName();
}
getAliasForName(fqName) {
if (this.isFirstNodeName(fqName)) {
return this.node1.alias;
}
else {
return this.node2.alias;
}
}
getInverseAliasForName(fqName) {
if (this.isFirstNodeName(fqName)) {
return this.node2.alias;
}
else {
return this.node1.alias;
}
}
isParent(inst) {
return inst.getFqName() == this.node1.path.asFqName();
}
getParentFqName() {
return this.node1.path.asFqName();
}
getChildFqName() {
return this.node2.path.asFqName();
}
toString() {
const n1 = relNodeEntryToString(this.node1);
const n2 = relNodeEntryToString(this.node2);
let s = `relationship ${this.name} ${RelType[this.relType].toLowerCase()} (${n1}, ${n2})`;
if (this.isBetween()) {
if (this.isOneToOne()) {
s = `${s} @${OneToOne}`;
}
else if (this.isOneToMany()) {
s = `${s} @${OneToMany}`;
}
}
if (this.getUserAttributes().size > 0) {
const attrs = [];
this.getUserAttributes().forEach((attrSpec, n) => {
attrs.push(`${n} ${attributeSpecToString(attrSpec)}`);
});
s = s.concat(`{\n ${attrs.join(',\n')} }`);
}
return s.concat('\n');
}
}
export class Workflow extends ModuleEntry {
constructor(name, patterns, moduleName, isPrePost = false) {
super(name, moduleName);
this.statements = patterns;
this.isPrePost = isPrePost;
}
async addStatement(stmtCode) {
const result = await parseStatement(stmtCode);
this.statements.push(result);
return this;
}
setStatementAtHelper(statements, newStmt, index) {
let stmt = statements[index[0]];
const isFe = stmt.pattern.forEach;
const isIf = stmt.pattern.if;
if (isFe || isIf) {
for (let i = 1; i < index.length; ++i) {
const found = i == index.length - 1;
let idx = index[i];
if (stmt.pattern.forEach) {
if (found) {
if (!newStmt) {
stmt.pattern.forEach.statements.splice(idx, 1);
}
else {
stmt.pattern.forEach.statements[idx] = newStmt;
}
}
else
stmt = stmt.pattern.forEach.statements[idx];
}
else if (stmt.pattern.if) {
if (idx < 0 || isMinusZero(idx)) {
if (stmt.pattern.if.else) {
idx *= -1;
if (found) {
if (!newStmt) {
stmt.pattern.if.else.statements.splice(idx, 1);
}
else {
stmt.pattern.if.else.statements[idx] = newStmt;
}
}
else
stmt = stmt.pattern.if.else.statements[idx];
}
else {
throw new Error('No else part in if');
}
}
else {
if (found) {
if (!newStmt) {
stmt.pattern.if.statements.splice(idx, 1);
}
else {
stmt.pattern.if.statements[idx] = newStmt;
}
}
else
stmt = stmt.pattern.if.statements[idx];
}
}
else {
throw new Error('Cannot dig further into statements');
}
}
}
return this;
}
async setStatementAt(stmtCode, index) {
const result = await parseStatement(stmtCode);
if (index instanceof Array) {
if (index.length == 1) {
this.statements[index[0]] = result;
return this;
}
else {
return this.setStatementAtHelper(this.statements, result, index);
}
}
else {
this.statements[index] = result;
}
return this;
}
removeStatementAt(index) {
if (index instanceof Array) {
if (index.length == 1) {
this.statements.splice(index[0], 1);
return this;
}
else {
return this.setStatementAtHelper(this.statements, undefined, index);
}
}
else {
this.statements.splice(index, 1);
}
return this;
}
statementsToStringsHelper(statements) {
const ss = [];
statements.forEach((stmt) => {
var _a, _b;
if (stmt.pattern.forEach) {
ss.push(` for ${stmt.pattern.forEach.var} in ${(_a = stmt.pattern.forEach.src.$cstNode) === null || _a === void 0 ? void 0 : _a.text} {
${joinStatements(this.statementsToStringsHelper(stmt.pattern.forEach.statements))}
}`);
}
else if (stmt.pattern.if) {
let s = ` if (${(_b = stmt.pattern.if.cond.$cstNode) === null || _b === void 0 ? void 0 : _b.text}) {
${joinStatements(this.statementsToStringsHelper(stmt.pattern.if.statements))}
}`;
if (stmt.pattern.if.else) {
s = s.concat(` else {
${joinStatements(this.statementsToStringsHelper(stmt.pattern.if.else.statements))}
}`);
}
ss.push(s);
}
else if (stmt.$cstNode) {
ss.push(` ${stmt.$cstNode.text.trimStart()}`);
}
});
return ss;
}
statementsToStrings() {
return this.statementsToStringsHelper(this.statements);
}
setPublic(flag) {
super.setPublic(flag);
if (!this.isPrePost) {
const n = normalizeWorkflowName(this.name);
const event = getEvent(n, this.moduleName);
event.setPublic(flag);
}
return this;
}
toString() {
const n = this.isPrePost ? untangleWorkflowName(this.name) : this.name;
const nn = normalizeWorkflowName(n);
let s = `workflow ${nn} {\n`;
const ss = this.statementsToStringsHelper(this.statements);
s = s.concat(joinStatements(ss));
if (!this.isPrePost) {
const event = getEvent(nn, this.moduleName);
if ((event.isPublic() && event.isSystemDefined()) || this.isPublic()) {
s = `@public ${s}`;
}
}
else if (this.isPublic()) {
s = `@public ${s}`;
}
return s.concat('\n}');
}
}
export class Flow extends ModuleEntry {
constructor(name, moduleName, flow) {
super(name, moduleName);
this.flowSteps = new Array();
flow === null || flow === void 0 ? void 0 : flow.split('\n').forEach((step) => {
const s = step.trim();
if (s.length > 0) {
this.flowSteps.push(s);
}
});
}
getFlow() {
return this.flowSteps.join('\n');
}
removeStep(index) {
this.flowSteps.splice(index, 1);
return this;
}
insertStep(index, s) {
this.flowSteps.splice(index, 0, s);
return this;
}
appendStep(s) {
this.flowSteps.push(s);
return this;
}
stepsCount() {
return this.flowSteps.length;
}
toGraph() {
const result = new Array();
this.flowSteps.forEach((s) => {
const fp = FlowStepPattern.Parse(s);
if (fp.condition) {
const orig = result.find((v) => {
return v.label == fp.first;
});
if (orig) {
const nxs = orig.next;
nxs === null || nxs === void 0 ? void 0 : nxs.push(fp.next);
const conds = orig.on;
conds === null || conds === void 0 ? void 0 : conds.push(fp.condition);
}
else {
result.push({
label: fp.first,
type: 'condition',
on: [fp.condition],
next: [fp.next],
});
}
}
else {
result.push({
label: fp.first,
type: 'action',
next: [fp.next],
});
}
});
return result;
}
static asFlowName(n) {
return `${n}.flow`;
}
static normaliseFlowName(n) {
const i = n.lastIndexOf('.flow');
if (i > 0) {
return n.substring(0, i);
}
else {
return n;
}
}
toString() {
return `flow ${Flow.normaliseFlowName(this.name)} {
${this.getFlow()}
}`;
}
}
export class Scenario extends ModuleEntry {
constructor(name, moduleName, scn) {
super(name, moduleName);
this.def = scn;
}
toString() {
if (this.def.ifPattern) {
return `scenario ${this.name} {\n ${this.def.ifPattern.toString()}\n}\n`;
}
const s = `if ("${this.def.user}") {
${this.def.ai}
}`;
return `scenario ${this.name} {\n ${s}\n}\n`;
}
}
export class Directive extends ModuleEntry {
constructor(name, moduleName, def) {
super(name, moduleName);
this.def = def;
}
toString() {
if (this.def.ifPattern) {
return `directive ${this.name} {
${this.def.if}
}`;
}
else {
const obj = {
if: this.def.if,
then: this.def.then,
};
return `directive ${this.name} ${JSON.stringify(obj)}`;
}
}
}
export class GlossaryEntry extends ModuleEntry {
constructor(name, moduleName, def) {
super(name, moduleName);
this.def = def;
}
toString() {
const ss = new Array();
ss.push(` name "${this.def.name}"`);
ss.push(` meaning "${this.def.meaning}"`);
if (this.def.synonyms) {
ss.push(` synonyms "${this.def.synonyms}"`);
}
return `glossaryEntry ${this.name} \n{\n${ss.join(',\n')}\n}`;
}
}
export function flowGraphNext(graph, currentNode, onCondition) {
var _a;
if (!currentNode) {
return graph[0];
}
const node = graph.find((n) => {
return n.label == currentNode.label;
});
if (node) {
if (onCondition) {
const c = (_a = node.on) === null || _a === void 0 ? void 0 : _a.findIndex((v) => {
return v == onCondition;
});
if (c !== undefined) {
const next = node.next[c];
const r = graph.find((n) => {
return n.label == next;
});
return r || { label: next, type: 'action', next: [] };
}
else {
return undefined;
}
}
else {
return graph.find((n) => {
return n.label == node.next[0];
});
}
}
return undefined;
}
export class Retry extends ModuleEntry {
constructor(name, moduleName, attempts) {
super(name, moduleName);
this.attempts = attempts <= 0 ? 0 : attempts;
this.backoff = {
strategy: undefined,
delay: undefined,
magnitude: undefined,
factor: undefined,
};
}
setExponentialBackoff() {
this.backoff.strategy = 'e';
return this;
}
isExponentialBackoff() {
return this.backoff.strategy === 'e';
}
setLinearBackoff() {
this.backoff.strategy = 'l';
return this;
}
isLinearBackoff() {
return this.backoff.strategy === 'l';
}
setConstantBackoff() {
this.backoff.strategy = 'c';
return this;
}
isConstantBackoff() {
return this.backoff.strategy === undefined || this.backoff.strategy === 'c';
}
setBackoffDelay(n) {
if (n > 0) {
this.backoff.delay = n;
}
return this;
}
setBackoffMagnitudeAsMilliseconds() {
this.backoff.magnitude = 'ms';
return this;
}
backoffMagnitudeIsMilliseconds() {