agentlang 0.0.19 → 0.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/cli/main.d.ts.map +1 -1
- package/out/cli/main.js +18 -0
- package/out/cli/main.js.map +1 -1
- package/out/extension/main.cjs +250 -250
- package/out/extension/main.cjs.map +2 -2
- package/out/language/generated/ast.d.ts +23 -4
- package/out/language/generated/ast.d.ts.map +1 -1
- package/out/language/generated/ast.js +29 -1
- package/out/language/generated/ast.js.map +1 -1
- package/out/language/generated/grammar.d.ts.map +1 -1
- package/out/language/generated/grammar.js +251 -171
- package/out/language/generated/grammar.js.map +1 -1
- package/out/language/main.cjs +773 -674
- package/out/language/main.cjs.map +3 -3
- package/out/runtime/agents/common.d.ts +1 -1
- package/out/runtime/agents/common.d.ts.map +1 -1
- package/out/runtime/agents/common.js +4 -1
- package/out/runtime/agents/common.js.map +1 -1
- package/out/runtime/defs.d.ts +4 -0
- package/out/runtime/defs.d.ts.map +1 -1
- package/out/runtime/defs.js +8 -0
- package/out/runtime/defs.js.map +1 -1
- package/out/runtime/interpreter.d.ts.map +1 -1
- package/out/runtime/interpreter.js +48 -2
- package/out/runtime/interpreter.js.map +1 -1
- package/out/runtime/jsmodules.d.ts +0 -1
- package/out/runtime/jsmodules.d.ts.map +1 -1
- package/out/runtime/jsmodules.js +26 -34
- package/out/runtime/jsmodules.js.map +1 -1
- package/out/runtime/loader.d.ts.map +1 -1
- package/out/runtime/loader.js +42 -21
- package/out/runtime/loader.js.map +1 -1
- package/out/runtime/module.d.ts +2 -2
- package/out/runtime/module.d.ts.map +1 -1
- package/out/runtime/module.js +19 -3
- package/out/runtime/module.js.map +1 -1
- package/out/runtime/modules/ai.d.ts +1 -0
- package/out/runtime/modules/ai.d.ts.map +1 -1
- package/out/runtime/modules/ai.js +1 -0
- package/out/runtime/modules/ai.js.map +1 -1
- package/out/runtime/modules/core.js +1 -1
- package/out/runtime/modules/core.js.map +1 -1
- package/out/runtime/openapi.d.ts +16 -0
- package/out/runtime/openapi.d.ts.map +1 -0
- package/out/runtime/openapi.js +51 -0
- package/out/runtime/openapi.js.map +1 -0
- package/out/runtime/resolvers/interface.d.ts.map +1 -1
- package/out/runtime/resolvers/interface.js +11 -5
- package/out/runtime/resolvers/interface.js.map +1 -1
- package/out/runtime/resolvers/registry.d.ts +1 -2
- package/out/runtime/resolvers/registry.d.ts.map +1 -1
- package/out/runtime/resolvers/registry.js +2 -1
- package/out/runtime/resolvers/registry.js.map +1 -1
- package/out/runtime/state.d.ts +23 -0
- package/out/runtime/state.d.ts.map +1 -1
- package/out/runtime/state.js +7 -0
- package/out/runtime/state.js.map +1 -1
- package/out/runtime/util.d.ts +1 -0
- package/out/runtime/util.d.ts.map +1 -1
- package/out/runtime/util.js +20 -0
- package/out/runtime/util.js.map +1 -1
- package/out/syntaxes/agentlang.monarch.js +1 -1
- package/out/syntaxes/agentlang.monarch.js.map +1 -1
- package/package.json +2 -5
- package/src/cli/main.ts +19 -0
- package/src/language/agentlang.langium +9 -3
- package/src/language/generated/ast.ts +55 -4
- package/src/language/generated/grammar.ts +251 -171
- package/src/runtime/agents/common.ts +4 -1
- package/src/runtime/defs.ts +12 -0
- package/src/runtime/interpreter.ts +48 -1
- package/src/runtime/jsmodules.ts +26 -37
- package/src/runtime/loader.ts +46 -21
- package/src/runtime/module.ts +27 -3
- package/src/runtime/modules/ai.ts +2 -0
- package/src/runtime/modules/core.ts +1 -1
- package/src/runtime/openapi.ts +74 -0
- package/src/runtime/resolvers/interface.ts +14 -9
- package/src/runtime/resolvers/registry.ts +3 -2
- package/src/runtime/state.ts +9 -0
- package/src/runtime/util.ts +22 -0
- package/src/syntaxes/agentlang.monarch.ts +1 -1
|
@@ -145,9 +145,12 @@ are invalid, because the alias 'employee' is not defined:
|
|
|
145
145
|
|
|
146
146
|
A fix for the reference-error is shown below:
|
|
147
147
|
|
|
148
|
-
{Employee {id? 101}} @as employee;
|
|
148
|
+
{Employee {id? 101}} @as [employee];
|
|
149
149
|
{SendEmail {to employee.email, body "hello"}}
|
|
150
150
|
|
|
151
|
+
Note that the alias for the query is '[employee]' so that the resultset is destructured to select exactly one instance of Employee
|
|
152
|
+
selected into the reference. You must follow this pattern if your goal is to select exactly a single instance.
|
|
153
|
+
|
|
151
154
|
Keep in mind that the only valid syntax for the 'if' condition is:
|
|
152
155
|
|
|
153
156
|
if (<expr>) {
|
package/src/runtime/defs.ts
CHANGED
|
@@ -76,3 +76,15 @@ export class CodeMismatchError extends Error {
|
|
|
76
76
|
super(message || 'The verification code is incorrect. Please try again.', options);
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
|
+
|
|
80
|
+
export let FetchModuleFn: any = undefined;
|
|
81
|
+
|
|
82
|
+
export function setModuleFnFetcher(f: Function) {
|
|
83
|
+
FetchModuleFn = f;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export let SetSubscription: any = undefined;
|
|
87
|
+
|
|
88
|
+
export function setSubscriptionFn(f: Function) {
|
|
89
|
+
SetSubscription = f;
|
|
90
|
+
}
|
|
@@ -54,6 +54,7 @@ import {
|
|
|
54
54
|
DefaultModuleName,
|
|
55
55
|
escapeFqName,
|
|
56
56
|
escapeQueryName,
|
|
57
|
+
escapeSpecialChars,
|
|
57
58
|
fqNameFromPath,
|
|
58
59
|
isFqName,
|
|
59
60
|
isPath,
|
|
@@ -80,6 +81,7 @@ import {
|
|
|
80
81
|
setTimerRunning,
|
|
81
82
|
} from './modules/core.js';
|
|
82
83
|
import { invokeModuleFn } from './jsmodules.js';
|
|
84
|
+
import { invokeOpenApiEvent, isOpenApiEventInstance } from './openapi.js';
|
|
83
85
|
|
|
84
86
|
export type Result = any;
|
|
85
87
|
|
|
@@ -545,6 +547,15 @@ export async function evaluate(
|
|
|
545
547
|
}
|
|
546
548
|
await evaluateStatements(wf.statements, env, continuation);
|
|
547
549
|
return env.getLastResult();
|
|
550
|
+
} else if (isOpenApiEventInstance(eventInstance)) {
|
|
551
|
+
env = new Environment(eventInstance.name + '.env', activeEnv);
|
|
552
|
+
await handleOpenApiEvent(eventInstance, env);
|
|
553
|
+
const r = env.getLastResult();
|
|
554
|
+
if (continuation) continuation(r);
|
|
555
|
+
return r;
|
|
556
|
+
} else {
|
|
557
|
+
if (continuation) continuation(null);
|
|
558
|
+
return null;
|
|
548
559
|
}
|
|
549
560
|
} else {
|
|
550
561
|
throw new Error('Not an event - ' + eventInstance.name);
|
|
@@ -1180,6 +1191,7 @@ async function evaluateCrudMap(crud: CrudMap, env: Environment): Promise<void> {
|
|
|
1180
1191
|
}
|
|
1181
1192
|
} else if (isEventInstance(inst)) {
|
|
1182
1193
|
if (isAgentEventInstance(inst)) await handleAgentInvocation(inst, env);
|
|
1194
|
+
else if (isOpenApiEventInstance(inst)) await handleOpenApiEvent(inst, env);
|
|
1183
1195
|
else await evaluate(inst, (result: Result) => env.setLastResult(result), env);
|
|
1184
1196
|
} else {
|
|
1185
1197
|
env.setLastResult(inst);
|
|
@@ -1350,11 +1362,37 @@ async function handleAgentInvocation(agentEventInst: Instance, env: Environment)
|
|
|
1350
1362
|
}
|
|
1351
1363
|
}
|
|
1352
1364
|
}
|
|
1365
|
+
if (agent.output) {
|
|
1366
|
+
await pushToAgent(agent.output, env.getLastResult(), env);
|
|
1367
|
+
}
|
|
1353
1368
|
} else {
|
|
1354
1369
|
logger.warn(`Agent ${agent.name} failed to generate a response`);
|
|
1355
1370
|
}
|
|
1356
1371
|
}
|
|
1357
1372
|
|
|
1373
|
+
function agentInputAsString(result: any): string {
|
|
1374
|
+
if (!isString(result)) {
|
|
1375
|
+
if (result instanceof Instance) {
|
|
1376
|
+
return JSON.stringify((result as Instance).asObject());
|
|
1377
|
+
} else if (result instanceof Array) {
|
|
1378
|
+
return `[${(result as Array<any>)
|
|
1379
|
+
.map((r: any) => {
|
|
1380
|
+
return agentInputAsString(r);
|
|
1381
|
+
})
|
|
1382
|
+
.join(',')}]`;
|
|
1383
|
+
} else {
|
|
1384
|
+
return JSON.stringify(result);
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
return result;
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
async function pushToAgent(agentName: string, result: any, env: Environment) {
|
|
1391
|
+
const r = escapeSpecialChars(agentInputAsString(result));
|
|
1392
|
+
const pat = `{${agentName} {message "\n${r}"}}`;
|
|
1393
|
+
env.setLastResult(await parseAndEvaluateStatement(pat, undefined, env));
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1358
1396
|
function cleanupAgentResponse(response: string | undefined): string | undefined {
|
|
1359
1397
|
if (response) {
|
|
1360
1398
|
const resp = response.trim();
|
|
@@ -1387,6 +1425,15 @@ function cleanupAgentResponse(response: string | undefined): string | undefined
|
|
|
1387
1425
|
}
|
|
1388
1426
|
}
|
|
1389
1427
|
|
|
1428
|
+
async function handleOpenApiEvent(eventInst: Instance, env: Environment): Promise<void> {
|
|
1429
|
+
const r = await invokeOpenApiEvent(
|
|
1430
|
+
eventInst.moduleName,
|
|
1431
|
+
eventInst.name,
|
|
1432
|
+
eventInst.attributesAsObject()
|
|
1433
|
+
);
|
|
1434
|
+
env.setLastResult(r);
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1390
1437
|
async function evaluateUpsert(crud: CrudMap, env: Environment): Promise<void> {
|
|
1391
1438
|
env.setInUpsertMode(true);
|
|
1392
1439
|
try {
|
|
@@ -1650,7 +1697,7 @@ async function runPrePostEvents(
|
|
|
1650
1697
|
if (env.hasHandlers()) {
|
|
1651
1698
|
throw reason;
|
|
1652
1699
|
} else {
|
|
1653
|
-
|
|
1700
|
+
throw new Error(`${prefix}: ${reason}`);
|
|
1654
1701
|
}
|
|
1655
1702
|
};
|
|
1656
1703
|
if (trigInfo.async) {
|
package/src/runtime/jsmodules.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { logger } from './logger.js';
|
|
2
|
-
import { setSubscription } from './resolvers/registry.js';
|
|
3
2
|
import { now, splitRefs } from './util.js';
|
|
4
3
|
import { isNodeEnv } from '../utils/runtime.js';
|
|
4
|
+
import { setModuleFnFetcher } from './defs.js';
|
|
5
5
|
|
|
6
6
|
let dirname: any = undefined;
|
|
7
7
|
let sep: any = undefined;
|
|
@@ -26,39 +26,37 @@ const importedModules = new Map<string, any>();
|
|
|
26
26
|
|
|
27
27
|
// Usage: importModule("./mymodels/acme.js")
|
|
28
28
|
export async function importModule(path: string, name: string, moduleFileName?: string) {
|
|
29
|
-
if (
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
if (moduleFileName) {
|
|
33
|
-
let s: string = dirname(moduleFileName);
|
|
34
|
-
if (s.startsWith('./')) {
|
|
35
|
-
s = s.substring(2);
|
|
29
|
+
if (isNodeEnv) {
|
|
30
|
+
if (importedModules.has(name)) {
|
|
31
|
+
logger.warn(`Alias '${name}' will overwrite a previously imported module`);
|
|
36
32
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
33
|
+
if (moduleFileName) {
|
|
34
|
+
let s: string = dirname(moduleFileName);
|
|
35
|
+
if (s.startsWith('./')) {
|
|
36
|
+
s = s.substring(2);
|
|
37
|
+
} else if (s == '.') {
|
|
38
|
+
s = process.cwd();
|
|
39
|
+
}
|
|
40
|
+
path = `${s}${sep}${path}`;
|
|
41
|
+
}
|
|
42
|
+
if (!(path.startsWith(sep) || path.startsWith('.'))) {
|
|
43
|
+
path = process.cwd() + sep + path;
|
|
44
|
+
}
|
|
45
|
+
const m = await import(/* @vite-ignore */ path);
|
|
46
|
+
importedModules.set(name, m);
|
|
47
|
+
// e.g of dynamic fn-call:
|
|
48
|
+
//// let f = eval("(a, b) => m.add(a, b)");
|
|
49
|
+
//// console.log(f(10, 20))
|
|
50
|
+
return m;
|
|
51
|
+
} else {
|
|
52
|
+
return {};
|
|
41
53
|
}
|
|
42
|
-
const m = await import(/* @vite-ignore */ path);
|
|
43
|
-
importedModules.set(name, m);
|
|
44
|
-
// e.g of dynamic fn-call:
|
|
45
|
-
//// let f = eval("(a, b) => m.add(a, b)");
|
|
46
|
-
//// console.log(f(10, 20))
|
|
47
|
-
return m;
|
|
48
54
|
}
|
|
49
55
|
|
|
50
56
|
export function moduleImported(moduleName: string): boolean {
|
|
51
57
|
return importedModules.has(moduleName);
|
|
52
58
|
}
|
|
53
59
|
|
|
54
|
-
const ReservedImports = new Set<string>(['resolvers']);
|
|
55
|
-
|
|
56
|
-
export function validateImportName(n: string) {
|
|
57
|
-
if (ReservedImports.has(n)) {
|
|
58
|
-
throw new Error(`${n} is an import reserved by the runtime`);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
60
|
function maybeEvalFunction(fnName: string): Function | undefined {
|
|
63
61
|
try {
|
|
64
62
|
return eval(fnName);
|
|
@@ -68,14 +66,6 @@ function maybeEvalFunction(fnName: string): Function | undefined {
|
|
|
68
66
|
}
|
|
69
67
|
}
|
|
70
68
|
|
|
71
|
-
function invokeReservedFn(moduleName: string, fnName: string, args: Array<any> | null) {
|
|
72
|
-
if (moduleName == 'resolvers' && fnName == 'setSubscription' && args != null) {
|
|
73
|
-
return setSubscription(args[0], args[1]);
|
|
74
|
-
} else {
|
|
75
|
-
throw new Error(`Failed to call ${moduleName}.${fnName} with the given arguments`);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
69
|
async function invokeBuiltInFn(fnName: string, args: Array<any> | null, isAsync: boolean = false) {
|
|
80
70
|
if (fnName == 'now') {
|
|
81
71
|
return now();
|
|
@@ -112,9 +102,6 @@ export async function invokeModuleFn(
|
|
|
112
102
|
}
|
|
113
103
|
}
|
|
114
104
|
const mname = refs[0];
|
|
115
|
-
if (ReservedImports.has(mname)) {
|
|
116
|
-
return invokeReservedFn(mname, refs[1], args);
|
|
117
|
-
}
|
|
118
105
|
const m = importedModules.get(mname);
|
|
119
106
|
if (m != undefined) {
|
|
120
107
|
const f = m[refs[1]];
|
|
@@ -151,3 +138,5 @@ export function getModuleFn(fqFnName: string): Function | undefined {
|
|
|
151
138
|
return m[refs[1]];
|
|
152
139
|
} else return undefined;
|
|
153
140
|
}
|
|
141
|
+
|
|
142
|
+
setModuleFnFetcher(getModuleFn);
|
package/src/runtime/loader.ts
CHANGED
|
@@ -63,9 +63,11 @@ import { Environment, evaluateStatements, GlobalEnvironment } from './interprete
|
|
|
63
63
|
import { createPermission, createRole } from './modules/auth.js';
|
|
64
64
|
import { AgentEntityName, CoreAIModuleName, LlmEntityName } from './modules/ai.js';
|
|
65
65
|
import { GenericResolver, GenericResolverMethods } from './resolvers/interface.js';
|
|
66
|
-
import { registerResolver, setResolver
|
|
66
|
+
import { registerResolver, setResolver } from './resolvers/registry.js';
|
|
67
67
|
import { ConfigSchema } from './state.js';
|
|
68
|
-
import { getModuleFn, importModule
|
|
68
|
+
import { getModuleFn, importModule } from './jsmodules.js';
|
|
69
|
+
import { SetSubscription } from './defs.js';
|
|
70
|
+
import { ExtendedFileSystem } from '../utils/fs/interfaces.js';
|
|
69
71
|
|
|
70
72
|
export async function extractDocument(
|
|
71
73
|
fileName: string,
|
|
@@ -135,6 +137,31 @@ export const DefaultAppSpec: ApplicationSpec = {
|
|
|
135
137
|
version: '0.0.1',
|
|
136
138
|
};
|
|
137
139
|
|
|
140
|
+
async function getAllModules(
|
|
141
|
+
dir: string,
|
|
142
|
+
fs: ExtendedFileSystem,
|
|
143
|
+
drill: boolean = true
|
|
144
|
+
): Promise<string[]> {
|
|
145
|
+
let alFiles = new Array<string>();
|
|
146
|
+
if (!(await fs.exists(dir))) {
|
|
147
|
+
return alFiles;
|
|
148
|
+
}
|
|
149
|
+
const directoryContents = await fs.readdir(dir);
|
|
150
|
+
for (let i = 0; i < directoryContents.length; ++i) {
|
|
151
|
+
const file = directoryContents[i];
|
|
152
|
+
if (path.extname(file).toLowerCase() == '.al') {
|
|
153
|
+
alFiles.push(dir + path.sep + file);
|
|
154
|
+
} else if (drill) {
|
|
155
|
+
const fullPath = dir + path.sep + file;
|
|
156
|
+
const stat = await fs.stat(fullPath);
|
|
157
|
+
if (stat.isDirectory()) {
|
|
158
|
+
alFiles = alFiles.concat(await getAllModules(fullPath, fs));
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return alFiles;
|
|
163
|
+
}
|
|
164
|
+
|
|
138
165
|
async function loadApp(appDir: string, fsOptions?: any, callback?: Function): Promise<string> {
|
|
139
166
|
// Initialize filesystem if not already done
|
|
140
167
|
const fs = await getFileSystem(fsOptions);
|
|
@@ -142,19 +169,11 @@ async function loadApp(appDir: string, fsOptions?: any, callback?: Function): Pr
|
|
|
142
169
|
const appJsonFile = `${appDir}${path.sep}package.json`;
|
|
143
170
|
const s: string = await fs.readFile(appJsonFile);
|
|
144
171
|
const appSpec: ApplicationSpec = JSON.parse(s);
|
|
145
|
-
const alFiles: Array<string> = new Array<string>();
|
|
146
|
-
const directoryContents = await fs.readdir(appDir);
|
|
147
172
|
let lastModuleLoaded: string = '';
|
|
148
173
|
async function cont2() {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}
|
|
153
|
-
directoryContents.forEach(file => {
|
|
154
|
-
if (path.extname(file).toLowerCase() == '.al') {
|
|
155
|
-
alFiles.push(appDir + path.sep + file);
|
|
156
|
-
}
|
|
157
|
-
});
|
|
174
|
+
const fls01 = await getAllModules(appDir, fs, false);
|
|
175
|
+
const fls02 = await getAllModules(appDir + path.sep + 'src', fs);
|
|
176
|
+
const alFiles = fls01.concat(fls02);
|
|
158
177
|
for (let i = 0; i < alFiles.length; ++i) {
|
|
159
178
|
lastModuleLoaded = (await loadModule(alFiles[i], fsOptions)).name;
|
|
160
179
|
}
|
|
@@ -164,7 +183,10 @@ async function loadApp(appDir: string, fsOptions?: any, callback?: Function): Pr
|
|
|
164
183
|
for (const [depName, _] of Object.entries(appSpec.dependencies)) {
|
|
165
184
|
try {
|
|
166
185
|
const depDirName = `./node_modules/${depName}`;
|
|
167
|
-
const
|
|
186
|
+
const fls01 = await fs.readdir(depDirName);
|
|
187
|
+
const srcDir = depDirName + path.sep + 'src';
|
|
188
|
+
const hasSrc = await fs.exists(srcDir);
|
|
189
|
+
const files = hasSrc ? fls01.concat(await fs.readdir(srcDir)) : fls01;
|
|
168
190
|
if (
|
|
169
191
|
files.find(file => {
|
|
170
192
|
return path.extname(file).toLowerCase() == '.al';
|
|
@@ -356,7 +378,7 @@ export function addRelationshipFromDef(
|
|
|
356
378
|
}
|
|
357
379
|
|
|
358
380
|
export function addWorkflowFromDef(def: WorkflowDefinition, moduleName: string): Workflow {
|
|
359
|
-
return addWorkflow(def.name, moduleName, def.statements);
|
|
381
|
+
return addWorkflow(def.name, moduleName, def.statements, def.hints);
|
|
360
382
|
}
|
|
361
383
|
|
|
362
384
|
const StandaloneStatements = new Map<string, Statement[]>();
|
|
@@ -489,7 +511,7 @@ function addResolverDefinition(def: ResolverDefinition, moduleName: string) {
|
|
|
489
511
|
resolver.subs = {
|
|
490
512
|
subscribe: subsFn,
|
|
491
513
|
};
|
|
492
|
-
if (subsEvent)
|
|
514
|
+
if (subsEvent) SetSubscription(subsEvent, resolverName);
|
|
493
515
|
resolver.subscribe();
|
|
494
516
|
}
|
|
495
517
|
});
|
|
@@ -537,7 +559,6 @@ export async function internModule(
|
|
|
537
559
|
const mn = module.name;
|
|
538
560
|
const r = addModule(mn);
|
|
539
561
|
module.imports.forEach(async (imp: Import) => {
|
|
540
|
-
validateImportName(imp.name);
|
|
541
562
|
await importModule(imp.path, imp.name, moduleFileName);
|
|
542
563
|
});
|
|
543
564
|
for (let i = 0; i < module.defs.length; ++i) {
|
|
@@ -569,11 +590,15 @@ export async function loadRawConfig(
|
|
|
569
590
|
fsOptions?: any
|
|
570
591
|
): Promise<any> {
|
|
571
592
|
const fs = await getFileSystem(fsOptions);
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
593
|
+
if (await fs.exists(configFileName)) {
|
|
594
|
+
let rawConfig = preprocessRawConfig(JSON.parse(await fs.readFile(configFileName)));
|
|
595
|
+
if (validate) {
|
|
596
|
+
rawConfig = ConfigSchema.parse(rawConfig);
|
|
597
|
+
}
|
|
598
|
+
return rawConfig;
|
|
599
|
+
} else {
|
|
600
|
+
return { service: { port: 8080 } };
|
|
575
601
|
}
|
|
576
|
-
return rawConfig;
|
|
577
602
|
}
|
|
578
603
|
|
|
579
604
|
export function generateRawConfig(configObj: any): string {
|
package/src/runtime/module.ts
CHANGED
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
RbacSpecEntry,
|
|
20
20
|
RbacSpecEntries,
|
|
21
21
|
RbacOpr,
|
|
22
|
+
WorkflowHint,
|
|
22
23
|
} from '../language/generated/ast.js';
|
|
23
24
|
import {
|
|
24
25
|
Path,
|
|
@@ -43,7 +44,12 @@ import {
|
|
|
43
44
|
} from './util.js';
|
|
44
45
|
import { parseStatement } from '../language/parser.js';
|
|
45
46
|
import { ActiveSessionInfo, AdminSession } from './auth/defs.js';
|
|
46
|
-
import {
|
|
47
|
+
import {
|
|
48
|
+
DefaultIdAttributeName,
|
|
49
|
+
FetchModuleFn,
|
|
50
|
+
PathAttributeName,
|
|
51
|
+
SetSubscription,
|
|
52
|
+
} from './defs.js';
|
|
47
53
|
import { logger } from './logger.js';
|
|
48
54
|
|
|
49
55
|
export class ModuleEntry {
|
|
@@ -1594,6 +1600,7 @@ export const propertyNames = new Set([
|
|
|
1594
1600
|
'@indexed',
|
|
1595
1601
|
'@default',
|
|
1596
1602
|
'@optional',
|
|
1603
|
+
'@check',
|
|
1597
1604
|
'@unique',
|
|
1598
1605
|
'@autoincrement',
|
|
1599
1606
|
'@array',
|
|
@@ -1856,7 +1863,8 @@ function normalizeWorkflowName(n: string): string {
|
|
|
1856
1863
|
export function addWorkflow(
|
|
1857
1864
|
name: string,
|
|
1858
1865
|
moduleName = activeModule,
|
|
1859
|
-
statements?: Statement[]
|
|
1866
|
+
statements?: Statement[],
|
|
1867
|
+
hints?: WorkflowHint[]
|
|
1860
1868
|
): Workflow {
|
|
1861
1869
|
const module: Module = fetchModule(moduleName);
|
|
1862
1870
|
if (module.hasEntry(name)) {
|
|
@@ -1869,6 +1877,13 @@ export function addWorkflow(
|
|
|
1869
1877
|
event.addMeta(SystemDefinedEvent, 'true');
|
|
1870
1878
|
}
|
|
1871
1879
|
if (!statements) statements = new Array<Statement>();
|
|
1880
|
+
if (hints && hints.length > 0) {
|
|
1881
|
+
hints.forEach((hint: WorkflowHint) => {
|
|
1882
|
+
if (hint.subs) {
|
|
1883
|
+
SetSubscription(makeFqName(moduleName, name), hint.subs.resolverName);
|
|
1884
|
+
}
|
|
1885
|
+
});
|
|
1886
|
+
}
|
|
1872
1887
|
return module.addEntry(new Workflow(asWorkflowName(name), statements, moduleName)) as Workflow;
|
|
1873
1888
|
}
|
|
1874
1889
|
|
|
@@ -2103,13 +2118,22 @@ function checkOneOfValue(attrSpec: AttributeSpec, attrName: string, attrValue: a
|
|
|
2103
2118
|
return false;
|
|
2104
2119
|
}
|
|
2105
2120
|
|
|
2121
|
+
function getCheckPredicate(attrSpec: AttributeSpec): any {
|
|
2122
|
+
const p = getAnyProperty('check', attrSpec);
|
|
2123
|
+
if (isString(p)) {
|
|
2124
|
+
return FetchModuleFn(p);
|
|
2125
|
+
}
|
|
2126
|
+
return undefined;
|
|
2127
|
+
}
|
|
2128
|
+
|
|
2106
2129
|
function validateType(attrName: string, attrValue: any, attrSpec: AttributeSpec) {
|
|
2107
2130
|
if (attrSpec.type == 'Path') {
|
|
2108
2131
|
if (!isPath(attrValue, getRefSpec(attrSpec))) {
|
|
2109
2132
|
throw new Error(`Failed to validate Path ${attrValue} passed to ${attrName}`);
|
|
2110
2133
|
}
|
|
2111
2134
|
}
|
|
2112
|
-
|
|
2135
|
+
let predic = getCheckPredicate(attrSpec);
|
|
2136
|
+
predic = predic ? predic : builtInChecks.get(attrSpec.type);
|
|
2113
2137
|
if (predic != undefined) {
|
|
2114
2138
|
if (isArrayAttribute(attrSpec)) {
|
|
2115
2139
|
if (!(attrValue instanceof Array)) {
|
|
@@ -34,6 +34,7 @@ entity ${AgentEntityName} {
|
|
|
34
34
|
tools String @optional, // comma-separated list of tool names
|
|
35
35
|
documents String @optional, // comma-separated list of document names
|
|
36
36
|
channels String @optional, // comma-separated list of channel names
|
|
37
|
+
output String @optional, // fq-name of another agent to which the result will be pushed
|
|
37
38
|
llm String
|
|
38
39
|
}
|
|
39
40
|
|
|
@@ -72,6 +73,7 @@ export class AgentInstance {
|
|
|
72
73
|
documents: string | undefined;
|
|
73
74
|
channels: string | undefined;
|
|
74
75
|
runWorkflows: boolean = true;
|
|
76
|
+
output: string | undefined;
|
|
75
77
|
|
|
76
78
|
private constructor() {}
|
|
77
79
|
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { parseAndIntern } from './loader.js';
|
|
2
|
+
import { logger } from './logger.js';
|
|
3
|
+
import { Instance } from './module.js';
|
|
4
|
+
import { isReservedName } from './util.js';
|
|
5
|
+
import { OpenAPIClient, OpenAPIClientAxios } from 'openapi-client-axios';
|
|
6
|
+
|
|
7
|
+
export type OpenApiHandle = {
|
|
8
|
+
api: OpenAPIClientAxios;
|
|
9
|
+
client: OpenAPIClient;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
let OpenApiModules: Map<string, OpenApiHandle> | undefined = undefined;
|
|
13
|
+
|
|
14
|
+
export async function registerOpenApiModule(
|
|
15
|
+
moduleName: string,
|
|
16
|
+
handle: OpenApiHandle
|
|
17
|
+
): Promise<string> {
|
|
18
|
+
if (OpenApiModules == undefined) {
|
|
19
|
+
OpenApiModules = new Map();
|
|
20
|
+
}
|
|
21
|
+
const m = new Map(Object.entries(handle.client));
|
|
22
|
+
const events = new Array<string>();
|
|
23
|
+
m.forEach((v: any, k: string) => {
|
|
24
|
+
if (v instanceof Function) {
|
|
25
|
+
if (isReservedName(k)) {
|
|
26
|
+
k = `_${k}`;
|
|
27
|
+
}
|
|
28
|
+
logger.debug(`OpenAPI event: ${moduleName}/${k}`);
|
|
29
|
+
events.push(
|
|
30
|
+
`event ${k} {parameters Any @optional, data Any @optional, config Any @optional}`
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
await parseAndIntern(`module ${moduleName}\n${events.join('\n')}`);
|
|
35
|
+
OpenApiModules.set(moduleName, handle);
|
|
36
|
+
return moduleName;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function isOpenApiModule(moduleName: string): boolean {
|
|
40
|
+
return OpenApiModules != undefined && OpenApiModules.has(moduleName);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type OpenApiArgs = {
|
|
44
|
+
parameters?: any;
|
|
45
|
+
data?: any;
|
|
46
|
+
config?: any;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export async function invokeOpenApiEvent(
|
|
50
|
+
moduleName: string,
|
|
51
|
+
eventName: string,
|
|
52
|
+
params: OpenApiArgs
|
|
53
|
+
): Promise<any> {
|
|
54
|
+
if (OpenApiModules) {
|
|
55
|
+
const handle = OpenApiModules.get(moduleName);
|
|
56
|
+
if (handle) {
|
|
57
|
+
const f = handle.client[eventName];
|
|
58
|
+
if (!f) {
|
|
59
|
+
throw new Error(`No event ${eventName} found in ${moduleName}`);
|
|
60
|
+
} else {
|
|
61
|
+
const r: any = await f(params.parameters, params.data, params.config);
|
|
62
|
+
return r.data;
|
|
63
|
+
}
|
|
64
|
+
} else {
|
|
65
|
+
throw new Error(`No OpenAPI module found - ${moduleName}`);
|
|
66
|
+
}
|
|
67
|
+
} else {
|
|
68
|
+
throw new Error(`OpenAPI module ${moduleName} not initialized`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function isOpenApiEventInstance(eventInst: Instance): boolean {
|
|
73
|
+
return isOpenApiModule(eventInst.moduleName);
|
|
74
|
+
}
|
|
@@ -193,15 +193,20 @@ export class Resolver {
|
|
|
193
193
|
|
|
194
194
|
public async onSubscription(result: any): Promise<any> {
|
|
195
195
|
if (result != undefined) {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
196
|
+
try {
|
|
197
|
+
const eventName = getSubscriptionEvent(this.name);
|
|
198
|
+
if (eventName) {
|
|
199
|
+
const path = splitFqName(eventName);
|
|
200
|
+
const inst = makeInstance(
|
|
201
|
+
path.getModuleName(),
|
|
202
|
+
path.getEntryName(),
|
|
203
|
+
newInstanceAttributes().set('data', result)
|
|
204
|
+
);
|
|
205
|
+
return await evaluate(inst);
|
|
206
|
+
}
|
|
207
|
+
} catch (err: any) {
|
|
208
|
+
logger.error(`Resolver ${this.name} raised error in onSubscription handler: ${err}`);
|
|
209
|
+
return undefined;
|
|
205
210
|
}
|
|
206
211
|
}
|
|
207
212
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { setSubscriptionFn } from '../defs.js';
|
|
1
2
|
import { Resolver, setSubscriptionEvent } from './interface.js';
|
|
2
3
|
|
|
3
4
|
type MakeResolver = () => Resolver;
|
|
@@ -17,8 +18,6 @@ export function setResolver(fqEntryName: string, resolverName: string) {
|
|
|
17
18
|
}
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
export const setSubscription = setSubscriptionEvent;
|
|
21
|
-
|
|
22
21
|
export function getResolverNameForPath(fqEntryName: string): string | undefined {
|
|
23
22
|
return resolverPathMappings.get(fqEntryName);
|
|
24
23
|
}
|
|
@@ -31,3 +30,5 @@ export function getResolver(fqEntryName: string): Resolver {
|
|
|
31
30
|
}
|
|
32
31
|
throw new Error(`No resolver registered for ${fqEntryName}`);
|
|
33
32
|
}
|
|
33
|
+
|
|
34
|
+
setSubscriptionFn(setSubscriptionEvent);
|
package/src/runtime/state.ts
CHANGED
|
@@ -93,6 +93,15 @@ export const ConfigSchema = z.object({
|
|
|
93
93
|
}),
|
|
94
94
|
])
|
|
95
95
|
.optional(),
|
|
96
|
+
openapi: z
|
|
97
|
+
.array(
|
|
98
|
+
z.object({
|
|
99
|
+
specUrl: z.string(),
|
|
100
|
+
baseUrl: z.string().optional(),
|
|
101
|
+
name: z.string(),
|
|
102
|
+
})
|
|
103
|
+
)
|
|
104
|
+
.optional(),
|
|
96
105
|
});
|
|
97
106
|
|
|
98
107
|
export type Config = z.infer<typeof ConfigSchema>;
|
package/src/runtime/util.ts
CHANGED
|
@@ -472,3 +472,25 @@ export function areSetsEqual<T>(set1: Set<T>, set2: Set<T>): boolean {
|
|
|
472
472
|
}
|
|
473
473
|
return true;
|
|
474
474
|
}
|
|
475
|
+
|
|
476
|
+
const ReservedNames = new Set([
|
|
477
|
+
'if',
|
|
478
|
+
'else',
|
|
479
|
+
'for',
|
|
480
|
+
'or',
|
|
481
|
+
'and',
|
|
482
|
+
'entity',
|
|
483
|
+
'record',
|
|
484
|
+
'event',
|
|
485
|
+
'workflow',
|
|
486
|
+
'create',
|
|
487
|
+
'delete',
|
|
488
|
+
'update',
|
|
489
|
+
'upsert',
|
|
490
|
+
'agent',
|
|
491
|
+
'resolver',
|
|
492
|
+
]);
|
|
493
|
+
|
|
494
|
+
export function isReservedName(s: string): boolean {
|
|
495
|
+
return ReservedNames.has(s);
|
|
496
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Monarch syntax highlighting for the agentlang language.
|
|
2
2
|
export default {
|
|
3
3
|
keywords: [
|
|
4
|
-
'@actions','@after','@as','@async','@before','@catch','@distinct','@enum','@expr','@from','@into','@meta','@oneof','@rbac','@ref','@then','@upsert','@with_unique','agent','allow','and','await','between','contains','create','delete','else','entity','error','event','extends','false','for','if','import','in','like','module','not','not_found','onSubscription','or','purge','query','read','record','relationship','resolver','return','roles','subscribe','true','update','upsert','where','workflow'
|
|
4
|
+
'@actions','@after','@as','@async','@before','@catch','@distinct','@enum','@expr','@from','@into','@meta','@oneof','@rbac','@ref','@subs','@then','@upsert','@with_unique','agent','allow','and','await','between','contains','create','delete','else','entity','error','event','extends','false','for','if','import','in','like','module','not','not_found','onSubscription','or','purge','query','read','record','relationship','resolver','return','roles','subscribe','true','update','upsert','where','workflow'
|
|
5
5
|
],
|
|
6
6
|
operators: [
|
|
7
7
|
'!=','*','+',',','-','.','/',':',';','<','<=','<>','=','>','>=','?','@'
|