agentlang 0.0.8 → 0.0.10
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/api/http.js +1 -1
- package/out/api/http.js.map +1 -1
- package/out/language/parser.d.ts +1 -0
- package/out/language/parser.d.ts.map +1 -1
- package/out/language/parser.js +4 -0
- package/out/language/parser.js.map +1 -1
- package/out/runtime/interpreter.d.ts +14 -1
- package/out/runtime/interpreter.d.ts.map +1 -1
- package/out/runtime/interpreter.js +134 -13
- package/out/runtime/interpreter.js.map +1 -1
- package/out/runtime/jsmodules.d.ts +2 -2
- package/out/runtime/jsmodules.d.ts.map +1 -1
- package/out/runtime/jsmodules.js +12 -4
- package/out/runtime/jsmodules.js.map +1 -1
- package/out/runtime/loader.d.ts +1 -1
- package/out/runtime/loader.d.ts.map +1 -1
- package/out/runtime/loader.js +5 -5
- package/out/runtime/loader.js.map +1 -1
- package/out/runtime/module.d.ts +4 -1
- package/out/runtime/module.d.ts.map +1 -1
- package/out/runtime/module.js +56 -11
- 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 +16 -4
- package/out/runtime/modules/ai.js.map +1 -1
- package/out/runtime/modules/core.d.ts +7 -0
- package/out/runtime/modules/core.d.ts.map +1 -1
- package/out/runtime/modules/core.js +80 -2
- package/out/runtime/modules/core.js.map +1 -1
- package/out/runtime/resolvers/interface.d.ts +4 -3
- package/out/runtime/resolvers/interface.d.ts.map +1 -1
- package/out/runtime/resolvers/interface.js +4 -4
- package/out/runtime/resolvers/interface.js.map +1 -1
- package/out/runtime/resolvers/sqldb/impl.js +2 -2
- package/out/runtime/resolvers/sqldb/impl.js.map +1 -1
- package/out/runtime/util.d.ts.map +1 -1
- package/out/runtime/util.js +3 -2
- package/out/runtime/util.js.map +1 -1
- package/package.json +1 -1
- package/src/api/http.ts +1 -1
- package/src/language/parser.ts +5 -0
- package/src/runtime/interpreter.ts +148 -13
- package/src/runtime/jsmodules.ts +12 -4
- package/src/runtime/loader.ts +8 -5
- package/src/runtime/module.ts +61 -11
- package/src/runtime/modules/ai.ts +15 -4
- package/src/runtime/modules/core.ts +109 -2
- package/src/runtime/resolvers/interface.ts +6 -6
- package/src/runtime/resolvers/sqldb/impl.ts +2 -2
- package/src/runtime/util.ts +4 -2
|
@@ -74,6 +74,7 @@ import {
|
|
|
74
74
|
addCreateAudit,
|
|
75
75
|
addDeleteAudit,
|
|
76
76
|
addUpdateAudit,
|
|
77
|
+
createSuspension,
|
|
77
78
|
maybeCancelTimer,
|
|
78
79
|
setTimerRunning,
|
|
79
80
|
} from './modules/core.js';
|
|
@@ -103,6 +104,8 @@ function mkEnvName(name: string | undefined, parent: Environment | undefined): s
|
|
|
103
104
|
}
|
|
104
105
|
}
|
|
105
106
|
|
|
107
|
+
type CatchHandlers = Map<string, Statement>;
|
|
108
|
+
|
|
106
109
|
export class Environment extends Instance {
|
|
107
110
|
parent: Environment | undefined;
|
|
108
111
|
|
|
@@ -119,6 +122,8 @@ export class Environment extends Instance {
|
|
|
119
122
|
private inUpsertMode: boolean = false;
|
|
120
123
|
private inDeleteMode: boolean = false;
|
|
121
124
|
private inKernelMode: boolean = false;
|
|
125
|
+
private suspensionId: string | undefined;
|
|
126
|
+
private activeCatchHandlers: Array<CatchHandlers>;
|
|
122
127
|
|
|
123
128
|
constructor(name?: string, parent?: Environment) {
|
|
124
129
|
super(
|
|
@@ -138,10 +143,13 @@ export class Environment extends Instance {
|
|
|
138
143
|
this.activeResolvers = parent.activeResolvers;
|
|
139
144
|
this.inUpsertMode = parent.inUpsertMode;
|
|
140
145
|
this.inKernelMode = parent.inKernelMode;
|
|
146
|
+
this.activeCatchHandlers = parent.activeCatchHandlers;
|
|
147
|
+
this.suspensionId = parent.suspensionId;
|
|
141
148
|
} else {
|
|
142
149
|
this.activeModule = DefaultModuleName;
|
|
143
150
|
this.activeResolvers = new Map<string, Resolver>();
|
|
144
151
|
this.activeTransactions = new Map<string, string>();
|
|
152
|
+
this.activeCatchHandlers = new Array<CatchHandlers>();
|
|
145
153
|
}
|
|
146
154
|
}
|
|
147
155
|
|
|
@@ -149,6 +157,47 @@ export class Environment extends Instance {
|
|
|
149
157
|
return new Environment(undefined, parent);
|
|
150
158
|
}
|
|
151
159
|
|
|
160
|
+
static fromInstance(inst: Instance): Environment {
|
|
161
|
+
const env = new Environment();
|
|
162
|
+
env.attributes = inst.attributes;
|
|
163
|
+
return env;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
override asSerializableObject(): object {
|
|
167
|
+
const obj: any = super.asSerializableObject();
|
|
168
|
+
obj.activeModule = this.activeModule;
|
|
169
|
+
if (this.activeEventInstance) {
|
|
170
|
+
obj.activeEventInstance = this.activeEventInstance.asSerializableObject();
|
|
171
|
+
}
|
|
172
|
+
obj.activeUser = this.activeUser;
|
|
173
|
+
obj.activeUserSet = this.activeUserSet;
|
|
174
|
+
obj.inUpsertMode = this.inUpsertMode;
|
|
175
|
+
obj.inDeleteMode = this.inDeleteMode;
|
|
176
|
+
obj.inKernelMode = this.inKernelMode;
|
|
177
|
+
if (this.parent) {
|
|
178
|
+
obj.parent = this.parent.asSerializableObject();
|
|
179
|
+
}
|
|
180
|
+
return obj;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
static override FromSerializableObject(obj: any): Environment {
|
|
184
|
+
const inst = Instance.FromSerializableObject(obj, PlaceholderRecordEntry);
|
|
185
|
+
const env = Environment.fromInstance(inst);
|
|
186
|
+
env.activeModule = obj.activeModule;
|
|
187
|
+
if (obj.activeEventInstance) {
|
|
188
|
+
env.activeEventInstance = Instance.FromSerializableObject(obj.activeEventInstance);
|
|
189
|
+
}
|
|
190
|
+
env.activeUser = obj.activeUser;
|
|
191
|
+
env.activeUserSet = obj.activeUserSet;
|
|
192
|
+
env.inUpsertMode = obj.inUpsertMode;
|
|
193
|
+
env.inDeleteMode = obj.inDeleteMode;
|
|
194
|
+
env.inKernelMode = obj.inKernelMode;
|
|
195
|
+
if (obj.parent) {
|
|
196
|
+
env.parent = Environment.FromSerializableObject(obj.parent);
|
|
197
|
+
}
|
|
198
|
+
return env;
|
|
199
|
+
}
|
|
200
|
+
|
|
152
201
|
override lookup(k: string): Result {
|
|
153
202
|
const v = this.attributes.get(k);
|
|
154
203
|
if (v == undefined) {
|
|
@@ -200,6 +249,35 @@ export class Environment extends Instance {
|
|
|
200
249
|
return this.activeEventInstance;
|
|
201
250
|
}
|
|
202
251
|
|
|
252
|
+
isSuspended(): boolean {
|
|
253
|
+
return this.suspensionId != undefined;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
suspend(): string {
|
|
257
|
+
if (this.suspensionId == undefined) {
|
|
258
|
+
const id = crypto.randomUUID();
|
|
259
|
+
this.propagateSuspension(id);
|
|
260
|
+
return id;
|
|
261
|
+
} else {
|
|
262
|
+
return this.suspensionId;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
protected propagateSuspension(suspId: string) {
|
|
267
|
+
this.suspensionId = suspId;
|
|
268
|
+
if (this.parent) {
|
|
269
|
+
this.parent.propagateSuspension(suspId);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
getSuspensionId(): string {
|
|
274
|
+
if (this.suspensionId) {
|
|
275
|
+
return this.suspensionId;
|
|
276
|
+
} else {
|
|
277
|
+
throw new Error('SuspensionId is not set');
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
203
281
|
getActiveAuthContext(): ActiveSessionInfo | undefined {
|
|
204
282
|
if (this.activeEventInstance) {
|
|
205
283
|
return this.activeEventInstance.getAuthContext();
|
|
@@ -285,7 +363,7 @@ export class Environment extends Instance {
|
|
|
285
363
|
getResolver(resolverName: string): Resolver | undefined {
|
|
286
364
|
const r: Resolver | undefined = this.getActiveResolvers().get(resolverName);
|
|
287
365
|
if (r) {
|
|
288
|
-
return r.
|
|
366
|
+
return r.setEnvironment(this);
|
|
289
367
|
}
|
|
290
368
|
return undefined;
|
|
291
369
|
}
|
|
@@ -293,7 +371,7 @@ export class Environment extends Instance {
|
|
|
293
371
|
async addResolver(resolver: Resolver): Promise<Environment> {
|
|
294
372
|
this.getActiveResolvers().set(resolver.getName(), resolver);
|
|
295
373
|
await this.ensureTransactionForResolver(resolver);
|
|
296
|
-
resolver.
|
|
374
|
+
resolver.setEnvironment(this);
|
|
297
375
|
return this;
|
|
298
376
|
}
|
|
299
377
|
|
|
@@ -393,6 +471,26 @@ export class Environment extends Instance {
|
|
|
393
471
|
isInKernelMode(): boolean {
|
|
394
472
|
return this.inKernelMode;
|
|
395
473
|
}
|
|
474
|
+
|
|
475
|
+
pushHandlers(handlers: CatchHandlers): boolean {
|
|
476
|
+
if (handlers.has('error')) {
|
|
477
|
+
this.activeCatchHandlers.push(handlers);
|
|
478
|
+
return true;
|
|
479
|
+
}
|
|
480
|
+
return false;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
hasHandlers(): boolean {
|
|
484
|
+
return this.activeCatchHandlers.length > 0;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
popHandlers(): CatchHandlers {
|
|
488
|
+
const r = this.activeCatchHandlers.pop();
|
|
489
|
+
if (r == undefined) {
|
|
490
|
+
throw new Error(`No more handlers to pop`);
|
|
491
|
+
}
|
|
492
|
+
return r;
|
|
493
|
+
}
|
|
396
494
|
}
|
|
397
495
|
|
|
398
496
|
export const GlobalEnvironment = new Environment();
|
|
@@ -402,7 +500,7 @@ export async function evaluate(
|
|
|
402
500
|
continuation?: Function,
|
|
403
501
|
activeEnv?: Environment,
|
|
404
502
|
kernelCall?: boolean
|
|
405
|
-
): Promise<
|
|
503
|
+
): Promise<Result> {
|
|
406
504
|
let env: Environment | undefined;
|
|
407
505
|
let txnRolledBack: boolean = false;
|
|
408
506
|
try {
|
|
@@ -415,17 +513,22 @@ export async function evaluate(
|
|
|
415
513
|
env.setInKernelMode(true);
|
|
416
514
|
}
|
|
417
515
|
await evaluateStatements(wf.statements, env, continuation);
|
|
516
|
+
return env.getLastResult();
|
|
418
517
|
}
|
|
419
518
|
} else {
|
|
420
519
|
throw new Error('Not an event - ' + eventInstance.name);
|
|
421
520
|
}
|
|
422
521
|
} catch (err) {
|
|
423
|
-
if (env
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
522
|
+
if (env && env.hasHandlers()) {
|
|
523
|
+
throw err;
|
|
524
|
+
} else {
|
|
525
|
+
if (env != undefined && activeEnv == undefined) {
|
|
526
|
+
await env.rollbackAllTransactions().then(() => {
|
|
527
|
+
txnRolledBack = true;
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
throw err;
|
|
427
531
|
}
|
|
428
|
-
throw err;
|
|
429
532
|
} finally {
|
|
430
533
|
if (!txnRolledBack && env != undefined && activeEnv == undefined) {
|
|
431
534
|
await env.commitAllTransactions();
|
|
@@ -466,6 +569,14 @@ export function makeEventEvaluator(moduleName: string): Function {
|
|
|
466
569
|
};
|
|
467
570
|
}
|
|
468
571
|
|
|
572
|
+
function statemtentString(stmt: Statement): string {
|
|
573
|
+
if (stmt.$cstNode) {
|
|
574
|
+
return stmt.$cstNode.text;
|
|
575
|
+
} else {
|
|
576
|
+
throw new Error(`Failed to fetch text for statement - ${stmt}`);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
469
580
|
export async function evaluateStatements(
|
|
470
581
|
stmts: Statement[],
|
|
471
582
|
env: Environment,
|
|
@@ -473,6 +584,20 @@ export async function evaluateStatements(
|
|
|
473
584
|
) {
|
|
474
585
|
for (let i = 0; i < stmts.length; ++i) {
|
|
475
586
|
await evaluateStatement(stmts[i], env);
|
|
587
|
+
if (env.isSuspended()) {
|
|
588
|
+
const cont = stmts.slice(i + 1, stmts.length);
|
|
589
|
+
if (cont.length > 0) {
|
|
590
|
+
const suspId = await createSuspension(
|
|
591
|
+
env.getSuspensionId(),
|
|
592
|
+
cont.map((stmt: Statement) => {
|
|
593
|
+
return statemtentString(stmt);
|
|
594
|
+
}),
|
|
595
|
+
env
|
|
596
|
+
);
|
|
597
|
+
env.setLastResult({ suspension: suspId || 'null' });
|
|
598
|
+
break;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
476
601
|
}
|
|
477
602
|
if (continuation != undefined) {
|
|
478
603
|
continuation(env.getLastResult());
|
|
@@ -482,10 +607,12 @@ export async function evaluateStatements(
|
|
|
482
607
|
async function evaluateStatement(stmt: Statement, env: Environment): Promise<void> {
|
|
483
608
|
const hints = stmt.hints;
|
|
484
609
|
const hasHints = hints && hints.length > 0;
|
|
485
|
-
const handlers:
|
|
486
|
-
|
|
487
|
-
: undefined;
|
|
610
|
+
const handlers: CatchHandlers | undefined = hasHints ? maybeFindHandlers(hints) : undefined;
|
|
611
|
+
let handlersPushed = false;
|
|
488
612
|
try {
|
|
613
|
+
if (handlers) {
|
|
614
|
+
handlersPushed = env.pushHandlers(handlers);
|
|
615
|
+
}
|
|
489
616
|
await evaluatePattern(stmt.pattern, env);
|
|
490
617
|
if (hasHints) {
|
|
491
618
|
maybeBindStatementResultToAlias(hints, env);
|
|
@@ -508,6 +635,10 @@ async function evaluateStatement(stmt: Statement, env: Environment): Promise<voi
|
|
|
508
635
|
} else {
|
|
509
636
|
throw reason;
|
|
510
637
|
}
|
|
638
|
+
} finally {
|
|
639
|
+
if (handlersPushed && env.hasHandlers()) {
|
|
640
|
+
env.popHandlers();
|
|
641
|
+
}
|
|
511
642
|
}
|
|
512
643
|
}
|
|
513
644
|
|
|
@@ -652,7 +783,7 @@ function getMapKey(k: MapKey): Result {
|
|
|
652
783
|
else if (k.bool != undefined) k.bool == 'true' ? true : false;
|
|
653
784
|
}
|
|
654
785
|
|
|
655
|
-
const DefaultResolverName: string = '
|
|
786
|
+
const DefaultResolverName: string = '-';
|
|
656
787
|
|
|
657
788
|
async function getResolverForPath(
|
|
658
789
|
entryName: string,
|
|
@@ -1384,7 +1515,11 @@ async function runPrePostEvents(
|
|
|
1384
1515
|
logger.debug(`${prefix}: ${value}`);
|
|
1385
1516
|
};
|
|
1386
1517
|
const catchHandler = (reason: any) => {
|
|
1387
|
-
|
|
1518
|
+
if (env.hasHandlers()) {
|
|
1519
|
+
throw reason;
|
|
1520
|
+
} else {
|
|
1521
|
+
logger.error(`${prefix}: ${reason}`);
|
|
1522
|
+
}
|
|
1388
1523
|
};
|
|
1389
1524
|
if (trigInfo.async) {
|
|
1390
1525
|
evaluate(eventInst, callback).catch(catchHandler);
|
package/src/runtime/jsmodules.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { dirname, sep } from 'path';
|
|
1
2
|
import { logger } from './logger.js';
|
|
2
3
|
import { setSubscription } from './resolvers/registry.js';
|
|
3
4
|
import { now, splitRefs } from './util.js';
|
|
@@ -5,12 +6,19 @@ import { now, splitRefs } from './util.js';
|
|
|
5
6
|
const importedModules = new Map<string, any>();
|
|
6
7
|
|
|
7
8
|
// Usage: importModule("./mymodels/acme.js")
|
|
8
|
-
export async function importModule(path: string, name: string) {
|
|
9
|
+
export async function importModule(path: string, name: string, moduleFileName?: string) {
|
|
9
10
|
if (importedModules.has(name)) {
|
|
10
11
|
logger.warn(`Alias '${name}' will overwrite a previously imported module`);
|
|
11
12
|
}
|
|
12
|
-
if (
|
|
13
|
-
|
|
13
|
+
if (moduleFileName) {
|
|
14
|
+
let s: string = dirname(moduleFileName);
|
|
15
|
+
if (s.startsWith('./')) {
|
|
16
|
+
s = s.substring(2);
|
|
17
|
+
}
|
|
18
|
+
path = `${s}${sep}${path}`;
|
|
19
|
+
}
|
|
20
|
+
if (!(path.startsWith(sep) || path.startsWith('.'))) {
|
|
21
|
+
path = process.cwd() + sep + path;
|
|
14
22
|
}
|
|
15
23
|
const m = await import(/* @vite-ignore */ path);
|
|
16
24
|
importedModules.set(name, m);
|
|
@@ -26,7 +34,7 @@ export function moduleImported(moduleName: string): boolean {
|
|
|
26
34
|
|
|
27
35
|
const ReservedImports = new Set<string>(['resolvers']);
|
|
28
36
|
|
|
29
|
-
export function
|
|
37
|
+
export function validateImportName(n: string) {
|
|
30
38
|
if (ReservedImports.has(n)) {
|
|
31
39
|
throw new Error(`${n} is an import reserved by the runtime`);
|
|
32
40
|
}
|
package/src/runtime/loader.ts
CHANGED
|
@@ -64,7 +64,7 @@ import { AgentEntityName, CoreAIModuleName, LlmEntityName } from './modules/ai.j
|
|
|
64
64
|
import { GenericResolver, GenericResolverMethods } from './resolvers/interface.js';
|
|
65
65
|
import { registerResolver, setResolver, setSubscription } from './resolvers/registry.js';
|
|
66
66
|
import { ConfigSchema } from './state.js';
|
|
67
|
-
import { getModuleFn, importModule,
|
|
67
|
+
import { getModuleFn, importModule, validateImportName } from './jsmodules.js';
|
|
68
68
|
|
|
69
69
|
export async function extractDocument(
|
|
70
70
|
fileName: string,
|
|
@@ -258,7 +258,7 @@ async function loadModule(fileName: string, fsOptions?: any, callback?: Function
|
|
|
258
258
|
|
|
259
259
|
// Extract the AST node
|
|
260
260
|
const module = await extractAstNode<ModuleDefinition>(fileName, services);
|
|
261
|
-
const result: Module = await internModule(module);
|
|
261
|
+
const result: Module = await internModule(module, fileName);
|
|
262
262
|
console.log(chalk.green(`Module ${chalk.bold(result.name)} loaded`));
|
|
263
263
|
logger.info(`Module ${result.name} loaded`);
|
|
264
264
|
if (callback) {
|
|
@@ -544,12 +544,15 @@ export async function parseAndIntern(code: string, moduleName?: string) {
|
|
|
544
544
|
await internModule(r.parseResult.value);
|
|
545
545
|
}
|
|
546
546
|
|
|
547
|
-
export async function internModule(
|
|
547
|
+
export async function internModule(
|
|
548
|
+
module: ModuleDefinition,
|
|
549
|
+
moduleFileName?: string
|
|
550
|
+
): Promise<Module> {
|
|
548
551
|
const mn = module.name;
|
|
549
552
|
const r = addModule(mn);
|
|
550
553
|
module.imports.forEach(async (imp: Import) => {
|
|
551
|
-
|
|
552
|
-
await importModule(imp.path, imp.name);
|
|
554
|
+
validateImportName(imp.name);
|
|
555
|
+
await importModule(imp.path, imp.name, moduleFileName);
|
|
553
556
|
});
|
|
554
557
|
for (let i = 0; i < module.defs.length; ++i) {
|
|
555
558
|
const def = module.defs[i];
|
package/src/runtime/module.ts
CHANGED
|
@@ -469,6 +469,11 @@ export class Record extends ModuleEntry {
|
|
|
469
469
|
});
|
|
470
470
|
scms = `${scms},\n @rbac [${rbs.join(',\n')}]`;
|
|
471
471
|
}
|
|
472
|
+
if (this.meta && this.meta.size > 0) {
|
|
473
|
+
const metaObj = Object.fromEntries(this.meta);
|
|
474
|
+
const ms = `@meta ${JSON.stringify(metaObj)}`;
|
|
475
|
+
scms = `${scms},\n ${ms}`;
|
|
476
|
+
}
|
|
472
477
|
return s.concat('\n{', scms, '\n}\n');
|
|
473
478
|
}
|
|
474
479
|
|
|
@@ -2189,21 +2194,66 @@ export class Instance {
|
|
|
2189
2194
|
return this.lookup(PathAttributeName);
|
|
2190
2195
|
}
|
|
2191
2196
|
|
|
2197
|
+
asSerializableObject(): object {
|
|
2198
|
+
const obj = {
|
|
2199
|
+
AL_INSTANCE: true,
|
|
2200
|
+
name: this.name,
|
|
2201
|
+
moduleName: this.moduleName,
|
|
2202
|
+
attributes: this.attributesAsObject(true),
|
|
2203
|
+
queryAttributes: this.queryAttributesAsObject(),
|
|
2204
|
+
queryAttributeValues: this.queryAttributeValuesAsObject(),
|
|
2205
|
+
};
|
|
2206
|
+
return obj;
|
|
2207
|
+
}
|
|
2208
|
+
|
|
2209
|
+
static FromSerializableObject(obj: any, record?: Record): Instance {
|
|
2210
|
+
if (obj.AL_INSTANCE == true) {
|
|
2211
|
+
const m = fetchModule(obj.moduleName);
|
|
2212
|
+
return new Instance(
|
|
2213
|
+
record || (m.getEntry(obj.name) as Record),
|
|
2214
|
+
obj.moduleName,
|
|
2215
|
+
obj.name,
|
|
2216
|
+
new Map(Object.entries(obj.attributes)),
|
|
2217
|
+
new Map(Object.entries(obj.queryAttributes)),
|
|
2218
|
+
new Map(Object.entries(obj.queryAttributeValues))
|
|
2219
|
+
);
|
|
2220
|
+
} else {
|
|
2221
|
+
throw new Error(`Cannot deserialize ${JSON.stringify(obj)} to an Instance`);
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2192
2225
|
asObject(): object {
|
|
2193
2226
|
const result: Map<string, object> = new Map<string, object>();
|
|
2194
|
-
result.set(this.name,
|
|
2227
|
+
result.set(this.name, this.attributesAsObject());
|
|
2195
2228
|
return Object.fromEntries(result);
|
|
2196
2229
|
}
|
|
2197
2230
|
|
|
2198
|
-
attributesAsObject(
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
})
|
|
2205
|
-
|
|
2206
|
-
|
|
2231
|
+
attributesAsObject(forSerialization: boolean = false): object {
|
|
2232
|
+
const attrs = newInstanceAttributes();
|
|
2233
|
+
this.attributes.forEach((v: any, k: string) => {
|
|
2234
|
+
if (v instanceof Instance) {
|
|
2235
|
+
const inst = v as Instance;
|
|
2236
|
+
attrs.set(k, forSerialization ? inst.asSerializableObject() : inst.asObject());
|
|
2237
|
+
} else if (v instanceof Object) {
|
|
2238
|
+
const obj = v instanceof Map ? Object.fromEntries(v) : v;
|
|
2239
|
+
attrs.set(k, obj);
|
|
2240
|
+
} else {
|
|
2241
|
+
attrs.set(k, v);
|
|
2242
|
+
}
|
|
2243
|
+
});
|
|
2244
|
+
return Object.fromEntries(attrs);
|
|
2245
|
+
}
|
|
2246
|
+
|
|
2247
|
+
attributesWithStringifiedObjects(): object {
|
|
2248
|
+
const attrs = newInstanceAttributes();
|
|
2249
|
+
this.attributes.forEach((v: any, k: string) => {
|
|
2250
|
+
if (v instanceof Object) {
|
|
2251
|
+
attrs.set(k, JSON.stringify(v instanceof Map ? Object.fromEntries(v) : v));
|
|
2252
|
+
} else {
|
|
2253
|
+
attrs.set(k, v);
|
|
2254
|
+
}
|
|
2255
|
+
});
|
|
2256
|
+
return Object.fromEntries(attrs);
|
|
2207
2257
|
}
|
|
2208
2258
|
|
|
2209
2259
|
queryAttributesAsObject(): object {
|
|
@@ -2414,7 +2464,7 @@ export function makeInstance(
|
|
|
2414
2464
|
throw new Error(`Invalid attribute ${key} specified for ${moduleName}/${entryName}`);
|
|
2415
2465
|
}
|
|
2416
2466
|
const spec: AttributeSpec = getAttributeSpec(schema, key);
|
|
2417
|
-
validateType(key, value, spec);
|
|
2467
|
+
if (value != null && value != undefined) validateType(key, value, spec);
|
|
2418
2468
|
});
|
|
2419
2469
|
}
|
|
2420
2470
|
if (!queryAttributes && !queryAll) {
|
|
@@ -31,8 +31,9 @@ entity ${AgentEntityName} {
|
|
|
31
31
|
type @enum("chat", "planner") @default("chat"),
|
|
32
32
|
runWorkflows Boolean @default(true),
|
|
33
33
|
instruction String @optional,
|
|
34
|
-
tools String @optional, // comma-separated
|
|
35
|
-
documents String @optional, // comma-separated
|
|
34
|
+
tools String @optional, // comma-separated list of tool names
|
|
35
|
+
documents String @optional, // comma-separated list of document names
|
|
36
|
+
channels String @optional, // comma-separated list of channel names
|
|
36
37
|
llm String
|
|
37
38
|
}
|
|
38
39
|
|
|
@@ -69,6 +70,7 @@ export class AgentInstance {
|
|
|
69
70
|
type: string = 'chat';
|
|
70
71
|
tools: string | undefined;
|
|
71
72
|
documents: string | undefined;
|
|
73
|
+
channels: string | undefined;
|
|
72
74
|
runWorkflows: boolean = true;
|
|
73
75
|
|
|
74
76
|
private constructor() {}
|
|
@@ -150,10 +152,19 @@ export class AgentInstance {
|
|
|
150
152
|
}
|
|
151
153
|
|
|
152
154
|
private toolsAsString(): string {
|
|
153
|
-
|
|
155
|
+
let finalTools: string | undefined = undefined;
|
|
156
|
+
if (this.tools) finalTools = this.tools;
|
|
157
|
+
if (this.channels) {
|
|
158
|
+
if (finalTools) {
|
|
159
|
+
finalTools = `${finalTools},${this.channels}`;
|
|
160
|
+
} else {
|
|
161
|
+
finalTools = this.channels;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (finalTools) {
|
|
154
165
|
const tooldefs = new Array<string>();
|
|
155
166
|
const slimModules = new Map<string, string[]>();
|
|
156
|
-
|
|
167
|
+
finalTools.split(',').forEach((n: string) => {
|
|
157
168
|
let moduleName: string | undefined;
|
|
158
169
|
let entryName: string | undefined;
|
|
159
170
|
if (isFqName(n)) {
|
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
import { default as ai } from './ai.js';
|
|
2
2
|
import { default as auth } from './auth.js';
|
|
3
3
|
import { DefaultModuleName, DefaultModules } from '../util.js';
|
|
4
|
-
import { Instance, isInstanceOfType } from '../module.js';
|
|
5
|
-
import {
|
|
4
|
+
import { Instance, isInstanceOfType, makeInstance, newInstanceAttributes } from '../module.js';
|
|
5
|
+
import {
|
|
6
|
+
Environment,
|
|
7
|
+
evaluate,
|
|
8
|
+
evaluateStatements,
|
|
9
|
+
parseAndEvaluateStatement,
|
|
10
|
+
} from '../interpreter.js';
|
|
6
11
|
import { logger } from '../logger.js';
|
|
12
|
+
import { Statement } from '../../language/generated/ast.js';
|
|
13
|
+
import { parseStatements } from '../../language/parser.js';
|
|
7
14
|
|
|
8
15
|
const CoreModuleDefinition = `module ${DefaultModuleName}
|
|
16
|
+
|
|
17
|
+
import "./modules/core.js" as Core
|
|
18
|
+
|
|
9
19
|
entity timer {
|
|
10
20
|
name String @id,
|
|
11
21
|
duration Int,
|
|
@@ -23,6 +33,26 @@ entity auditlog {
|
|
|
23
33
|
user String,
|
|
24
34
|
token String @optional
|
|
25
35
|
}
|
|
36
|
+
|
|
37
|
+
entity suspension {
|
|
38
|
+
id UUID @id,
|
|
39
|
+
continuation String[], // rest of the patterns to execute
|
|
40
|
+
env Any, // serialized environment-object
|
|
41
|
+
createdOn DateTime @default(now()),
|
|
42
|
+
createdBy String
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
workflow createSuspension {
|
|
46
|
+
{suspension
|
|
47
|
+
{id createSuspension.id
|
|
48
|
+
continuation createSuspension.continuation,
|
|
49
|
+
env createSuspension.env,
|
|
50
|
+
createdBy createSuspension.createdBy}}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
workflow restartSuspension {
|
|
54
|
+
await Core.restartSuspension(restartSuspension.id)
|
|
55
|
+
}
|
|
26
56
|
`;
|
|
27
57
|
export const CoreModules: string[] = [];
|
|
28
58
|
|
|
@@ -95,3 +125,80 @@ export async function addUpdateAudit(
|
|
|
95
125
|
) {
|
|
96
126
|
await addAudit(env, 'u', resource, previous_value);
|
|
97
127
|
}
|
|
128
|
+
|
|
129
|
+
export async function createSuspension(
|
|
130
|
+
suspId: string,
|
|
131
|
+
continuation: string[],
|
|
132
|
+
env: Environment
|
|
133
|
+
): Promise<string | undefined> {
|
|
134
|
+
const user = env.getActiveUser();
|
|
135
|
+
const newEnv = new Environment('susp', env).setInKernelMode(true);
|
|
136
|
+
const envObj = env.asSerializableObject();
|
|
137
|
+
const inst = makeInstance(
|
|
138
|
+
'agentlang',
|
|
139
|
+
'createSuspension',
|
|
140
|
+
newInstanceAttributes()
|
|
141
|
+
.set('id', suspId)
|
|
142
|
+
.set('continuation', continuation)
|
|
143
|
+
.set('env', envObj)
|
|
144
|
+
.set('createdBy', user)
|
|
145
|
+
);
|
|
146
|
+
const r: any = await evaluate(inst, undefined, newEnv);
|
|
147
|
+
if (!isInstanceOfType(r, 'agentlang/suspension')) {
|
|
148
|
+
logger.warn(`Failed to create suspension for user ${user}`);
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
return (r as Instance).lookup('id');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export type Suspension = {
|
|
155
|
+
continuation: Statement[];
|
|
156
|
+
env: Environment;
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
async function loadSuspension(suspId: string, env?: Environment): Promise<Suspension | undefined> {
|
|
160
|
+
const newEnv = new Environment('auditlog', env).setInKernelMode(true);
|
|
161
|
+
const r: any = await parseAndEvaluateStatement(
|
|
162
|
+
`{agentlang/suspension {id? "${suspId}"}}`,
|
|
163
|
+
undefined,
|
|
164
|
+
newEnv
|
|
165
|
+
);
|
|
166
|
+
if (r instanceof Array && r.length > 0) {
|
|
167
|
+
const inst: Instance = r[0];
|
|
168
|
+
const cont = inst.lookup('continuation');
|
|
169
|
+
const stmts: Statement[] = await parseStatements(cont);
|
|
170
|
+
const envStr = inst.lookup('env');
|
|
171
|
+
const suspEnv: Environment = Environment.FromSerializableObject(JSON.parse(envStr));
|
|
172
|
+
return {
|
|
173
|
+
continuation: stmts,
|
|
174
|
+
env: suspEnv,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
return undefined;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async function deleteSuspension(suspId: string, env?: Environment): Promise<any> {
|
|
181
|
+
try {
|
|
182
|
+
await parseAndEvaluateStatement(
|
|
183
|
+
`purge {agentlang/suspension {id? "${suspId}"}}`,
|
|
184
|
+
undefined,
|
|
185
|
+
env
|
|
186
|
+
);
|
|
187
|
+
return suspId;
|
|
188
|
+
} catch (err: any) {
|
|
189
|
+
logger.warn(`Failed to delete suspension ${suspId} - ${err}`);
|
|
190
|
+
return undefined;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export async function restartSuspension(suspId: string, env?: Environment): Promise<any> {
|
|
195
|
+
const susp = await loadSuspension(suspId, env);
|
|
196
|
+
if (susp) {
|
|
197
|
+
await evaluateStatements(susp.continuation, susp.env);
|
|
198
|
+
await deleteSuspension(suspId, env);
|
|
199
|
+
return susp.env.getLastResult();
|
|
200
|
+
} else {
|
|
201
|
+
logger.warn(`Suspension ${suspId} not found`);
|
|
202
|
+
return undefined;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { evaluate } from '../interpreter.js';
|
|
1
|
+
import { Environment, evaluate } from '../interpreter.js';
|
|
2
2
|
import { logger } from '../logger.js';
|
|
3
3
|
import {
|
|
4
4
|
Instance,
|
|
@@ -45,7 +45,7 @@ export function getSubscriptionEvent(resolverName: string): string | undefined {
|
|
|
45
45
|
|
|
46
46
|
export class Resolver {
|
|
47
47
|
protected authInfo: ResolverAuthInfo = DefaultAuthInfo;
|
|
48
|
-
protected
|
|
48
|
+
protected env: Environment | undefined;
|
|
49
49
|
protected name: string = 'default';
|
|
50
50
|
|
|
51
51
|
static Default = new Resolver();
|
|
@@ -59,13 +59,13 @@ export class Resolver {
|
|
|
59
59
|
return this;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
public
|
|
63
|
-
this.
|
|
62
|
+
public setEnvironment(env: Environment): Resolver {
|
|
63
|
+
this.env = env;
|
|
64
64
|
return this;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
public
|
|
68
|
-
return this.
|
|
67
|
+
public getEnvironment(): Environment | undefined {
|
|
68
|
+
return this.env;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
public getName(): string {
|
|
@@ -65,7 +65,7 @@ export class SqlDbResolver extends Resolver {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
private getDbContext(resourceFqName: string): DbContext {
|
|
68
|
-
const activeEnv: Environment = this.
|
|
68
|
+
const activeEnv: Environment = this.getEnvironment() as Environment;
|
|
69
69
|
if (!activeEnv) {
|
|
70
70
|
throw new Error('Active environment context is required by SqlDbResolver');
|
|
71
71
|
}
|
|
@@ -104,7 +104,7 @@ export class SqlDbResolver extends Resolver {
|
|
|
104
104
|
attrs.set(PathAttributeName, p);
|
|
105
105
|
}
|
|
106
106
|
const n: string = asTableName(inst.moduleName, inst.name);
|
|
107
|
-
const rowObj: object = inst.
|
|
107
|
+
const rowObj: object = inst.attributesWithStringifiedObjects();
|
|
108
108
|
const ctx = this.getDbContext(inst.getFqName());
|
|
109
109
|
await insertRow(n, rowObj, ctx, orUpdate);
|
|
110
110
|
if (inst.record.getFullTextSearchAttributes()) {
|