agentlang 0.10.1 → 0.10.2
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.d.ts.map +1 -1
- package/out/api/http.js +136 -0
- package/out/api/http.js.map +1 -1
- package/out/language/generated/ast.d.ts +27 -2
- package/out/language/generated/ast.d.ts.map +1 -1
- package/out/language/generated/ast.js +20 -0
- 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 +246 -206
- package/out/language/generated/grammar.js.map +1 -1
- package/out/language/main.cjs +263 -206
- package/out/language/main.cjs.map +2 -2
- package/out/language/parser.d.ts.map +1 -1
- package/out/language/parser.js +28 -2
- package/out/language/parser.js.map +1 -1
- package/out/language/syntax.d.ts +14 -0
- package/out/language/syntax.d.ts.map +1 -1
- package/out/language/syntax.js +60 -27
- package/out/language/syntax.js.map +1 -1
- package/out/runtime/api.d.ts +2 -0
- package/out/runtime/api.d.ts.map +1 -1
- package/out/runtime/api.js +3 -0
- package/out/runtime/api.js.map +1 -1
- package/out/runtime/datefns.d.ts +34 -0
- package/out/runtime/datefns.d.ts.map +1 -0
- package/out/runtime/datefns.js +82 -0
- package/out/runtime/datefns.js.map +1 -0
- package/out/runtime/exec-graph.d.ts.map +1 -1
- package/out/runtime/exec-graph.js +22 -3
- package/out/runtime/exec-graph.js.map +1 -1
- package/out/runtime/interpreter.d.ts +9 -0
- package/out/runtime/interpreter.d.ts.map +1 -1
- package/out/runtime/interpreter.js +71 -7
- package/out/runtime/interpreter.js.map +1 -1
- package/out/runtime/module.d.ts +8 -0
- package/out/runtime/module.d.ts.map +1 -1
- package/out/runtime/module.js +23 -0
- package/out/runtime/module.js.map +1 -1
- package/out/runtime/modules/ai.d.ts +7 -3
- package/out/runtime/modules/ai.d.ts.map +1 -1
- package/out/runtime/modules/ai.js +67 -21
- package/out/runtime/modules/ai.js.map +1 -1
- package/out/runtime/modules/core.d.ts.map +1 -1
- package/out/runtime/modules/core.js +5 -1
- package/out/runtime/modules/core.js.map +1 -1
- package/out/runtime/monitor.d.ts +6 -0
- package/out/runtime/monitor.d.ts.map +1 -1
- package/out/runtime/monitor.js +21 -1
- package/out/runtime/monitor.js.map +1 -1
- package/out/runtime/relgraph.d.ts.map +1 -1
- package/out/runtime/relgraph.js +7 -3
- package/out/runtime/relgraph.js.map +1 -1
- package/out/runtime/resolvers/interface.d.ts +3 -2
- package/out/runtime/resolvers/interface.d.ts.map +1 -1
- package/out/runtime/resolvers/interface.js +3 -2
- package/out/runtime/resolvers/interface.js.map +1 -1
- package/out/runtime/resolvers/sqldb/dbutil.d.ts.map +1 -1
- package/out/runtime/resolvers/sqldb/dbutil.js +17 -4
- package/out/runtime/resolvers/sqldb/dbutil.js.map +1 -1
- package/out/runtime/resolvers/sqldb/impl.d.ts +1 -1
- package/out/runtime/resolvers/sqldb/impl.d.ts.map +1 -1
- package/out/runtime/resolvers/sqldb/impl.js +17 -7
- package/out/runtime/resolvers/sqldb/impl.js.map +1 -1
- package/out/runtime/util.d.ts +3 -2
- package/out/runtime/util.d.ts.map +1 -1
- package/out/runtime/util.js +13 -2
- 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/out/test-harness.d.ts +36 -0
- package/out/test-harness.d.ts.map +1 -0
- package/out/test-harness.js +341 -0
- package/out/test-harness.js.map +1 -0
- package/package.json +4 -1
- package/src/api/http.ts +138 -0
- package/src/language/agentlang.langium +3 -1
- package/src/language/generated/ast.ts +32 -1
- package/src/language/generated/grammar.ts +246 -206
- package/src/language/parser.ts +33 -1
- package/src/language/syntax.ts +71 -24
- package/src/runtime/api.ts +5 -0
- package/src/runtime/datefns.ts +112 -0
- package/src/runtime/exec-graph.ts +23 -2
- package/src/runtime/interpreter.ts +82 -6
- package/src/runtime/module.ts +26 -0
- package/src/runtime/modules/ai.ts +78 -31
- package/src/runtime/modules/core.ts +5 -1
- package/src/runtime/monitor.ts +27 -1
- package/src/runtime/relgraph.ts +7 -3
- package/src/runtime/resolvers/interface.ts +4 -2
- package/src/runtime/resolvers/sqldb/dbutil.ts +20 -6
- package/src/runtime/resolvers/sqldb/impl.ts +17 -7
- package/src/runtime/util.ts +19 -2
- package/src/syntaxes/agentlang.monarch.ts +1 -1
- package/src/test-harness.ts +423 -0
package/src/language/parser.ts
CHANGED
|
@@ -36,9 +36,16 @@ import {
|
|
|
36
36
|
SetAttribute,
|
|
37
37
|
Statement,
|
|
38
38
|
WhereSpec,
|
|
39
|
+
WhereSpecClause,
|
|
39
40
|
WorkflowDefinition,
|
|
40
41
|
} from './generated/ast.js';
|
|
41
|
-
import {
|
|
42
|
+
import {
|
|
43
|
+
firstAliasSpec,
|
|
44
|
+
firstCatchSpec,
|
|
45
|
+
firstEmptySpec,
|
|
46
|
+
isString,
|
|
47
|
+
QuerySuffix,
|
|
48
|
+
} from '../runtime/util.js';
|
|
42
49
|
import {
|
|
43
50
|
BasePattern,
|
|
44
51
|
CrudPattern,
|
|
@@ -54,6 +61,7 @@ import {
|
|
|
54
61
|
NegExpressionPattern,
|
|
55
62
|
NotExpressionPattern,
|
|
56
63
|
ReturnPattern,
|
|
64
|
+
WhereSpecClausePattern,
|
|
57
65
|
} from './syntax.js';
|
|
58
66
|
|
|
59
67
|
let nextDocumentId = 1;
|
|
@@ -262,6 +270,10 @@ function introspectStatement(stmt: Statement): BasePattern {
|
|
|
262
270
|
r.addHandler(h.except, introspectStatement(h.stmt));
|
|
263
271
|
});
|
|
264
272
|
}
|
|
273
|
+
const emptySpec = firstEmptySpec(stmt);
|
|
274
|
+
if (emptySpec) {
|
|
275
|
+
r.setEmptyHandler(introspectStatement(emptySpec.stmt));
|
|
276
|
+
}
|
|
265
277
|
return r;
|
|
266
278
|
}
|
|
267
279
|
|
|
@@ -299,6 +311,14 @@ function introspectPattern(pat: Pattern): BasePattern {
|
|
|
299
311
|
function introspectInto(intoSpec: SelectIntoSpec, p: CrudPattern): CrudPattern {
|
|
300
312
|
intoSpec.entries.forEach((se: SelectIntoEntry) => {
|
|
301
313
|
if (se.attribute) p.addInto(se.alias, se.attribute);
|
|
314
|
+
else if (se.aggregate) {
|
|
315
|
+
const args = se.aggregate.args
|
|
316
|
+
.map((s: string) => {
|
|
317
|
+
return s;
|
|
318
|
+
})
|
|
319
|
+
.join(', ');
|
|
320
|
+
p.addInto(se.alias, `@${se.aggregate?.name}(${args})`);
|
|
321
|
+
}
|
|
302
322
|
});
|
|
303
323
|
return p;
|
|
304
324
|
}
|
|
@@ -379,6 +399,18 @@ function introspectQueryPattern(crudMap: CrudMap): CrudPattern {
|
|
|
379
399
|
};
|
|
380
400
|
cp.joins.push(jp);
|
|
381
401
|
});
|
|
402
|
+
if (opts.where?.clauses) {
|
|
403
|
+
cp.where = new Array<WhereSpecClausePattern>();
|
|
404
|
+
opts.where.clauses.forEach((wc: WhereSpecClause) => {
|
|
405
|
+
cp.where?.push({ lhs: wc.lhs, op: wc.op || '=', rhs: wc.rhs.$cstNode?.text || '' });
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
if (opts.groupByClause) {
|
|
409
|
+
cp.groupBy = opts.groupByClause.colNames;
|
|
410
|
+
}
|
|
411
|
+
if (opts.orderByClause) {
|
|
412
|
+
cp.orderBy = opts.orderByClause.colNames;
|
|
413
|
+
}
|
|
382
414
|
cp.isCreate = false;
|
|
383
415
|
cp.isQueryUpdate = false;
|
|
384
416
|
cp.isQuery = true;
|
package/src/language/syntax.ts
CHANGED
|
@@ -15,6 +15,7 @@ export class BasePattern {
|
|
|
15
15
|
alias: string | undefined;
|
|
16
16
|
aliases: string[] | undefined;
|
|
17
17
|
handlers: Map<string, BasePattern> | undefined;
|
|
18
|
+
emptyHandler: BasePattern | undefined;
|
|
18
19
|
|
|
19
20
|
setAlias(alias: string) {
|
|
20
21
|
this.alias = alias;
|
|
@@ -44,6 +45,11 @@ export class BasePattern {
|
|
|
44
45
|
this.handlers.set(k, handler);
|
|
45
46
|
}
|
|
46
47
|
|
|
48
|
+
setEmptyHandler(handler: BasePattern) {
|
|
49
|
+
this.emptyHandler = handler;
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
|
|
47
53
|
private aliasesAsString(): string | undefined {
|
|
48
54
|
if (this.alias) {
|
|
49
55
|
return ` @as ${this.alias}`;
|
|
@@ -54,24 +60,30 @@ export class BasePattern {
|
|
|
54
60
|
}
|
|
55
61
|
}
|
|
56
62
|
|
|
63
|
+
private emptyHandlerAsString(): string | undefined {
|
|
64
|
+
if (this.emptyHandler) {
|
|
65
|
+
return ` @empty ${this.emptyHandler.toString()}`;
|
|
66
|
+
}
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
|
|
57
70
|
private handlersAsString(): string | undefined {
|
|
58
|
-
if (this.handlers) {
|
|
59
|
-
let s = '{';
|
|
71
|
+
if (this.handlers && this.handlers.size > 0) {
|
|
72
|
+
let s = ' @catch {';
|
|
60
73
|
this.handlers.forEach((handler: BasePattern, k: string) => {
|
|
61
|
-
s = `${s}
|
|
74
|
+
s = `${s}${k} ${handler.toString()} `;
|
|
62
75
|
});
|
|
63
|
-
return s + '}';
|
|
64
|
-
} else {
|
|
65
|
-
return undefined;
|
|
76
|
+
return s.trimEnd() + '}';
|
|
66
77
|
}
|
|
78
|
+
return undefined;
|
|
67
79
|
}
|
|
80
|
+
|
|
68
81
|
hintsAsString(): string {
|
|
69
|
-
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
return `${a}\n${h}`;
|
|
82
|
+
// Order matters: @as, then @catch, then @empty (must be last because it's greedy in the grammar)
|
|
83
|
+
const a = this.aliasesAsString() ?? '';
|
|
84
|
+
const h = this.handlersAsString() ?? '';
|
|
85
|
+
const e = this.emptyHandlerAsString() ?? '';
|
|
86
|
+
return `${a}${h}${e}`;
|
|
75
87
|
}
|
|
76
88
|
|
|
77
89
|
toString(): string {
|
|
@@ -386,12 +398,21 @@ function joinPatternToString(jp: JoinPattern): string {
|
|
|
386
398
|
return `${jp.type} ${jp.targetEntity} {${jp.conditionLhs}${opr} ${jp.conditionRhs}}`;
|
|
387
399
|
}
|
|
388
400
|
|
|
401
|
+
export type WhereSpecClausePattern = {
|
|
402
|
+
lhs: string;
|
|
403
|
+
op: string;
|
|
404
|
+
rhs: string;
|
|
405
|
+
};
|
|
406
|
+
|
|
389
407
|
export class CrudPattern extends BasePattern {
|
|
390
408
|
recordName: string;
|
|
391
409
|
attributes: Array<AttributePattern>;
|
|
392
410
|
relationships: Map<string, CrudPattern[] | CrudPattern> | undefined;
|
|
393
411
|
joins: JoinPattern[];
|
|
394
412
|
into: Map<string, string> | undefined;
|
|
413
|
+
where: WhereSpecClausePattern[] | undefined;
|
|
414
|
+
groupBy: string[] | undefined;
|
|
415
|
+
orderBy: string[] | undefined;
|
|
395
416
|
isQuery: boolean = false;
|
|
396
417
|
isQueryUpdate: boolean = false;
|
|
397
418
|
isCreate: boolean = false;
|
|
@@ -521,15 +542,29 @@ export class CrudPattern extends BasePattern {
|
|
|
521
542
|
return escapeQueryName(this.recordName);
|
|
522
543
|
}
|
|
523
544
|
|
|
524
|
-
private intoAsString(): string
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
545
|
+
private intoAsString(): string {
|
|
546
|
+
const ss = new Array<string>();
|
|
547
|
+
this.into?.forEach((attr: string, alias: string) => {
|
|
548
|
+
ss.push(`${alias} ${attr}`);
|
|
549
|
+
});
|
|
550
|
+
return `@into { ${ss.join(',\n')} }`;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
private whereAsString(): string {
|
|
554
|
+
const ss = new Array<string>();
|
|
555
|
+
this.where?.forEach((wc: WhereSpecClausePattern) => {
|
|
556
|
+
if (wc.op == '=') ss.push(`${wc.lhs} ${wc.rhs}`);
|
|
557
|
+
else ss.push(`${wc.lhs} ${wc.op} ${wc.rhs}`);
|
|
558
|
+
});
|
|
559
|
+
return `@where {${ss.join(`,\n`)}}`;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
private groupByAsString(): string {
|
|
563
|
+
return `@groupBy(${this.groupBy?.join(', ')})`;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
private orderByAsString(): string {
|
|
567
|
+
return `@orderBy(${this.orderBy?.join(', ')})`;
|
|
533
568
|
}
|
|
534
569
|
|
|
535
570
|
override toString(): string {
|
|
@@ -542,10 +577,22 @@ export class CrudPattern extends BasePattern {
|
|
|
542
577
|
const js = this.joins.map(joinPatternToString);
|
|
543
578
|
s = s.concat(`,\n${js.join(',\n')}`);
|
|
544
579
|
}
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
580
|
+
if (this.into) {
|
|
581
|
+
const ins = this.intoAsString();
|
|
582
|
+
if (ins) {
|
|
583
|
+
s = s.concat(`,\n${ins}`);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
if (this.where) {
|
|
587
|
+
s = s.concat(`,\n${this.whereAsString()}`);
|
|
548
588
|
}
|
|
589
|
+
if (this.groupBy) {
|
|
590
|
+
s = s.concat(`,\n${this.groupByAsString()}`);
|
|
591
|
+
}
|
|
592
|
+
if (this.orderBy) {
|
|
593
|
+
s = s.concat(`,\n${this.orderByAsString()}`);
|
|
594
|
+
}
|
|
595
|
+
|
|
549
596
|
return s.concat('}', this.hintsAsString());
|
|
550
597
|
}
|
|
551
598
|
}
|
package/src/runtime/api.ts
CHANGED
|
@@ -5,9 +5,11 @@ import {
|
|
|
5
5
|
} from './module.js';
|
|
6
6
|
import { getLocalEnv as al_getLocalEnv, setLocalEnv as al_setLocalEnv } from './auth/defs.js';
|
|
7
7
|
import { now } from './util.js';
|
|
8
|
+
import { initDateFns } from './datefns.js';
|
|
8
9
|
|
|
9
10
|
declare global {
|
|
10
11
|
var agentlang: any | undefined;
|
|
12
|
+
var dateFns: ReturnType<typeof initDateFns> | undefined;
|
|
11
13
|
function getLocalEnv(k: string, defaultValue?: string): string | undefined;
|
|
12
14
|
function setLocalEnv(k: string, v: string): string;
|
|
13
15
|
function uuid(): string;
|
|
@@ -32,6 +34,9 @@ export function initGlobalApi() {
|
|
|
32
34
|
globalThis.getLocalEnv = al_getLocalEnv;
|
|
33
35
|
globalThis.setLocalEnv = al_setLocalEnv;
|
|
34
36
|
|
|
37
|
+
// Expose date-fns functions globally as dateFns.*
|
|
38
|
+
globalThis.dateFns = initDateFns();
|
|
39
|
+
|
|
35
40
|
ApiInited = true;
|
|
36
41
|
}
|
|
37
42
|
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import {
|
|
2
|
+
addDays as _addDays,
|
|
3
|
+
addWeeks as _addWeeks,
|
|
4
|
+
addMonths as _addMonths,
|
|
5
|
+
startOfWeek as _startOfWeek,
|
|
6
|
+
endOfWeek as _endOfWeek,
|
|
7
|
+
startOfMonth as _startOfMonth,
|
|
8
|
+
endOfMonth as _endOfMonth,
|
|
9
|
+
getISOWeek,
|
|
10
|
+
format,
|
|
11
|
+
parse,
|
|
12
|
+
differenceInDays,
|
|
13
|
+
differenceInWeeks,
|
|
14
|
+
} from 'date-fns';
|
|
15
|
+
import { formatInTimeZone } from 'date-fns-tz';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Parse a date string as local midnight to avoid timezone day-shift issues.
|
|
19
|
+
* date-fns operates in local time, so we must parse date-only strings
|
|
20
|
+
* (YYYY-MM-DD) as local midnight rather than UTC midnight.
|
|
21
|
+
*/
|
|
22
|
+
function toDate(dateStr: string): Date {
|
|
23
|
+
if (!dateStr.includes('T')) {
|
|
24
|
+
const [y, m, d] = dateStr.split('-').map(Number);
|
|
25
|
+
return new Date(y, m - 1, d);
|
|
26
|
+
}
|
|
27
|
+
return new Date(dateStr);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function toDateStr(d: Date): string {
|
|
31
|
+
return format(d, 'yyyy-MM-dd');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function addDays(dateStr: string, days: number): string {
|
|
35
|
+
return toDateStr(_addDays(toDate(dateStr), days));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function addWeeks(dateStr: string, weeks: number): string {
|
|
39
|
+
return toDateStr(_addWeeks(toDate(dateStr), weeks));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function addMonths(dateStr: string, months: number): string {
|
|
43
|
+
return toDateStr(_addMonths(toDate(dateStr), months));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function startOfWeek(dateStr: string): string {
|
|
47
|
+
return toDateStr(_startOfWeek(toDate(dateStr), { weekStartsOn: 1 }));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function endOfWeek(dateStr: string): string {
|
|
51
|
+
return toDateStr(_endOfWeek(toDate(dateStr), { weekStartsOn: 1 }));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function startOfMonth(dateStr: string): string {
|
|
55
|
+
return toDateStr(_startOfMonth(toDate(dateStr)));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function endOfMonth(dateStr: string): string {
|
|
59
|
+
return toDateStr(_endOfMonth(toDate(dateStr)));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function getWeek(dateStr: string): number {
|
|
63
|
+
return getISOWeek(toDate(dateStr));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function dayName(dateStr: string): string {
|
|
67
|
+
return format(toDate(dateStr), 'EEEE');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function formatDate(dateStr: string, fmt: string): string {
|
|
71
|
+
return format(toDate(dateStr), fmt);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function parseDate(str: string, fmt: string): string {
|
|
75
|
+
return toDateStr(parse(str, fmt, new Date()));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function diffInDays(dateStr1: string, dateStr2: string): number {
|
|
79
|
+
return differenceInDays(toDate(dateStr1), toDate(dateStr2));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function diffInWeeks(dateStr1: string, dateStr2: string): number {
|
|
83
|
+
return differenceInWeeks(toDate(dateStr1), toDate(dateStr2));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function today(): string {
|
|
87
|
+
return toDateStr(new Date());
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function toTimezone(dateStr: string, tz: string): string {
|
|
91
|
+
return formatInTimeZone(new Date(dateStr), tz, 'yyyy-MM-dd HH:mm:ssXXX');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function initDateFns() {
|
|
95
|
+
return {
|
|
96
|
+
addDays,
|
|
97
|
+
addWeeks,
|
|
98
|
+
addMonths,
|
|
99
|
+
startOfWeek,
|
|
100
|
+
endOfWeek,
|
|
101
|
+
startOfMonth,
|
|
102
|
+
endOfMonth,
|
|
103
|
+
getWeek,
|
|
104
|
+
dayName,
|
|
105
|
+
formatDate,
|
|
106
|
+
parseDate,
|
|
107
|
+
diffInDays,
|
|
108
|
+
diffInWeeks,
|
|
109
|
+
today,
|
|
110
|
+
toTimezone,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
@@ -304,8 +304,8 @@ export async function executeGraph(execGraph: ExecGraph, env: Environment): Prom
|
|
|
304
304
|
throw reason;
|
|
305
305
|
} finally {
|
|
306
306
|
if (monitoringEnabled) {
|
|
307
|
-
if (monitorIncr) env.decrementMonitor();
|
|
308
307
|
env.setMonitorEntryResult(env.getLastResult());
|
|
308
|
+
if (monitorIncr) env.decrementMonitor();
|
|
309
309
|
}
|
|
310
310
|
}
|
|
311
311
|
}
|
|
@@ -425,10 +425,28 @@ export async function executeEvent(
|
|
|
425
425
|
env.setActiveEvent(eventInstance);
|
|
426
426
|
await executeEventHelper(eventInstance, env);
|
|
427
427
|
} else if (isAgentEventInstance(eventInstance)) {
|
|
428
|
+
env.setActiveEvent(eventInstance);
|
|
429
|
+
if (isMonitoringEnabled()) {
|
|
430
|
+
env.appendEntryToMonitor(
|
|
431
|
+
`{${eventInstance.getFqName()} {message "${eventInstance.lookup('message')}"}}`
|
|
432
|
+
);
|
|
433
|
+
}
|
|
428
434
|
await handleAgentInvocation(eventInstance, env);
|
|
435
|
+
if (isMonitoringEnabled()) {
|
|
436
|
+
env.setMonitorEntryResult(env.getLastResult());
|
|
437
|
+
}
|
|
429
438
|
}
|
|
430
439
|
const r = env.getLastResult();
|
|
431
|
-
if (continuation)
|
|
440
|
+
if (continuation) {
|
|
441
|
+
if (env.getLastPattern() && isAgentEventInstance(eventInstance)) {
|
|
442
|
+
continuation({
|
|
443
|
+
result: r.map((res: any) => (res.attributes ? Object.fromEntries(res.attributes) : res)),
|
|
444
|
+
pattern: env.getLastPattern(),
|
|
445
|
+
});
|
|
446
|
+
} else {
|
|
447
|
+
continuation(r);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
432
450
|
return r;
|
|
433
451
|
} catch (err) {
|
|
434
452
|
if (env && env.hasHandlers()) {
|
|
@@ -490,6 +508,9 @@ export async function executeEventHelper(eventInstance: Instance, env?: Environm
|
|
|
490
508
|
);
|
|
491
509
|
}
|
|
492
510
|
await handleAgentInvocation(eventInstance, env);
|
|
511
|
+
if (isMonitoringEnabled()) {
|
|
512
|
+
env.setMonitorEntryResult(env.getLastResult());
|
|
513
|
+
}
|
|
493
514
|
}
|
|
494
515
|
if (isLocalEnv) {
|
|
495
516
|
await env.commitAllTransactions();
|
|
@@ -119,6 +119,7 @@ import { Monitor, MonitorEntry } from './monitor.js';
|
|
|
119
119
|
import { detailedDiff } from 'deep-object-diff';
|
|
120
120
|
import { callMcpTool, mcpClientNameFromToolEvent } from './mcpclient.js';
|
|
121
121
|
import { isNodeEnv } from '../utils/runtime.js';
|
|
122
|
+
import Handlebars from 'handlebars';
|
|
122
123
|
|
|
123
124
|
export type Result = any;
|
|
124
125
|
|
|
@@ -131,6 +132,7 @@ export function isEmptyResult(r: Result): boolean {
|
|
|
131
132
|
type BetweenRelInfo = {
|
|
132
133
|
relationship: Relationship;
|
|
133
134
|
connectedInstance: Instance;
|
|
135
|
+
connectedAlias?: string;
|
|
134
136
|
};
|
|
135
137
|
|
|
136
138
|
function mkEnvName(name: string | undefined, parent: Environment | undefined): string {
|
|
@@ -155,6 +157,7 @@ export class Environment extends Instance {
|
|
|
155
157
|
private activeUserSet: boolean = false;
|
|
156
158
|
private lastResult: Result;
|
|
157
159
|
private trashedResult: Result = undefined;
|
|
160
|
+
private lastPattern: string | undefined;
|
|
158
161
|
private returnFlag: boolean = false;
|
|
159
162
|
private parentPath: string | undefined;
|
|
160
163
|
private normalizedParentPath: string | undefined;
|
|
@@ -174,6 +177,7 @@ export class Environment extends Instance {
|
|
|
174
177
|
private agentChatId: string | undefined = undefined;
|
|
175
178
|
private monitor: Monitor | undefined = undefined;
|
|
176
179
|
private escalatedRole: string | undefined;
|
|
180
|
+
private activeChatId: string | undefined;
|
|
177
181
|
|
|
178
182
|
private activeUserData: any = undefined;
|
|
179
183
|
|
|
@@ -201,6 +205,7 @@ export class Environment extends Instance {
|
|
|
201
205
|
this.agentChatId = parent.agentChatId;
|
|
202
206
|
this.monitor = parent.monitor;
|
|
203
207
|
this.escalatedRole = parent.escalatedRole;
|
|
208
|
+
this.activeChatId = parent.activeChatId;
|
|
204
209
|
} else {
|
|
205
210
|
this.activeModule = DefaultModuleName;
|
|
206
211
|
this.activeResolvers = new Map<string, Resolver>();
|
|
@@ -327,6 +332,15 @@ export class Environment extends Instance {
|
|
|
327
332
|
return this.attributes.get(Environment.FlowContextTag);
|
|
328
333
|
}
|
|
329
334
|
|
|
335
|
+
setActiveChatId(chatId: string): Environment {
|
|
336
|
+
this.activeChatId = chatId;
|
|
337
|
+
return this;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
getActiveChatId(): string | undefined {
|
|
341
|
+
return this.activeChatId;
|
|
342
|
+
}
|
|
343
|
+
|
|
330
344
|
addToScratchPad(k: string, data: any): Environment {
|
|
331
345
|
if (this.scratchPad === undefined) {
|
|
332
346
|
this.scratchPad = {};
|
|
@@ -397,6 +411,11 @@ export class Environment extends Instance {
|
|
|
397
411
|
return this;
|
|
398
412
|
}
|
|
399
413
|
|
|
414
|
+
maybeRewriteTemplatePatterns(instruction: string, scratchPad?: any): string {
|
|
415
|
+
const templ = Handlebars.compile(this.rewriteTemplateMappings(instruction));
|
|
416
|
+
return templ(scratchPad);
|
|
417
|
+
}
|
|
418
|
+
|
|
400
419
|
static SuspensionUserData = '^';
|
|
401
420
|
|
|
402
421
|
bindSuspensionUserData(userData: string): Environment {
|
|
@@ -554,6 +573,15 @@ export class Environment extends Instance {
|
|
|
554
573
|
return this.lastResult;
|
|
555
574
|
}
|
|
556
575
|
|
|
576
|
+
setLastPattern(pattern: string | undefined): Environment {
|
|
577
|
+
this.lastPattern = pattern;
|
|
578
|
+
return this;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
getLastPattern(): string | undefined {
|
|
582
|
+
return this.lastPattern;
|
|
583
|
+
}
|
|
584
|
+
|
|
557
585
|
getActiveModuleName(): string {
|
|
558
586
|
return this.activeModule;
|
|
559
587
|
}
|
|
@@ -891,6 +919,13 @@ export class Environment extends Instance {
|
|
|
891
919
|
return this;
|
|
892
920
|
}
|
|
893
921
|
|
|
922
|
+
setMonitorEntryLlmTokenUsage(input: number, output: number, total: number): Environment {
|
|
923
|
+
if (this.monitor !== undefined) {
|
|
924
|
+
this.monitor.setEntryLlmTokenUsage(input, output, total);
|
|
925
|
+
}
|
|
926
|
+
return this;
|
|
927
|
+
}
|
|
928
|
+
|
|
894
929
|
incrementMonitor(): Environment {
|
|
895
930
|
if (this.monitor !== undefined) {
|
|
896
931
|
this.monitor = this.monitor.increment();
|
|
@@ -939,7 +974,13 @@ export let evaluate = async function (
|
|
|
939
974
|
} else if (isAgentEventInstance(eventInstance)) {
|
|
940
975
|
env = new Environment(eventInstance.name + '.env', activeEnv);
|
|
941
976
|
await handleAgentInvocation(eventInstance, env);
|
|
942
|
-
if (continuation)
|
|
977
|
+
if (continuation) {
|
|
978
|
+
if (env.getLastPattern()) {
|
|
979
|
+
continuation({ result: env.getLastResult(), pattern: env.getLastPattern() });
|
|
980
|
+
} else {
|
|
981
|
+
continuation(env.getLastResult());
|
|
982
|
+
}
|
|
983
|
+
}
|
|
943
984
|
} else if (isOpenApiEventInstance(eventInstance)) {
|
|
944
985
|
env = new Environment(eventInstance.name + '.env', activeEnv);
|
|
945
986
|
await handleOpenApiEvent(eventInstance, env);
|
|
@@ -1092,6 +1133,9 @@ export async function evaluateStatement(stmt: Statement, env: Environment): Prom
|
|
|
1092
1133
|
handlersPushed = env.pushHandlers(handlers);
|
|
1093
1134
|
}
|
|
1094
1135
|
await evaluatePattern(stmt.pattern, env);
|
|
1136
|
+
if (hasHints) {
|
|
1137
|
+
await maybeHandleEmpty(hints, env);
|
|
1138
|
+
}
|
|
1095
1139
|
if (hasHints) {
|
|
1096
1140
|
maybeBindStatementResultToAlias(hints, env);
|
|
1097
1141
|
}
|
|
@@ -1121,6 +1165,24 @@ async function maybeHandleNotFound(handlers: CatchHandlers | undefined, env: Env
|
|
|
1121
1165
|
}
|
|
1122
1166
|
}
|
|
1123
1167
|
|
|
1168
|
+
async function maybeHandleEmpty(hints: RuntimeHint[], env: Environment) {
|
|
1169
|
+
const lastResult: Result = env.getLastResult();
|
|
1170
|
+
if (
|
|
1171
|
+
lastResult === null ||
|
|
1172
|
+
lastResult === undefined ||
|
|
1173
|
+
(lastResult instanceof Array && lastResult.length == 0)
|
|
1174
|
+
) {
|
|
1175
|
+
for (const rh of hints) {
|
|
1176
|
+
if (rh.emptySpec) {
|
|
1177
|
+
const newEnv = new Environment('empty-env', env).unsetEventExecutor();
|
|
1178
|
+
await evaluateStatement(rh.emptySpec.stmt, newEnv);
|
|
1179
|
+
env.setLastResult(newEnv.getLastResult());
|
|
1180
|
+
break;
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1124
1186
|
async function maybeHandleError(
|
|
1125
1187
|
handlers: CatchHandlers | undefined,
|
|
1126
1188
|
reason: any,
|
|
@@ -1646,7 +1708,8 @@ async function evaluateCrudMap(crud: CrudMap, env: Environment): Promise<void> {
|
|
|
1646
1708
|
const insts: Instance[] = await res.queryConnectedInstances(
|
|
1647
1709
|
betRelInfo.relationship,
|
|
1648
1710
|
betRelInfo.connectedInstance,
|
|
1649
|
-
inst
|
|
1711
|
+
inst,
|
|
1712
|
+
betRelInfo.connectedAlias
|
|
1650
1713
|
);
|
|
1651
1714
|
env.setLastResult(insts);
|
|
1652
1715
|
} else {
|
|
@@ -1671,7 +1734,7 @@ async function evaluateCrudMap(crud: CrudMap, env: Environment): Promise<void> {
|
|
|
1671
1734
|
false,
|
|
1672
1735
|
true
|
|
1673
1736
|
);
|
|
1674
|
-
env.setLastResult(inst);
|
|
1737
|
+
env.setLastResult([inst]);
|
|
1675
1738
|
} else {
|
|
1676
1739
|
const insts: Instance[] = await res.queryInstances(inst, isQueryAll, distinct);
|
|
1677
1740
|
env.setLastResult(insts);
|
|
@@ -1698,7 +1761,12 @@ async function evaluateCrudMap(crud: CrudMap, env: Environment): Promise<void> {
|
|
|
1698
1761
|
await evaluatePattern(rel.pattern, newEnv);
|
|
1699
1762
|
lastRes[j].attachRelatedInstances(rel.name, newEnv.getLastResult());
|
|
1700
1763
|
} else if (isBetweenRelationship(rel.name, moduleName)) {
|
|
1701
|
-
|
|
1764
|
+
const connAlias = relEntry.isSelfReferencing() ? relEntry.node1.alias : undefined;
|
|
1765
|
+
newEnv.setBetweenRelInfo({
|
|
1766
|
+
relationship: relEntry,
|
|
1767
|
+
connectedInstance: lastRes[j],
|
|
1768
|
+
connectedAlias: connAlias,
|
|
1769
|
+
});
|
|
1702
1770
|
await evaluatePattern(rel.pattern, newEnv);
|
|
1703
1771
|
lastRes[j].attachRelatedInstances(rel.name, newEnv.getLastResult());
|
|
1704
1772
|
}
|
|
@@ -1734,7 +1802,7 @@ async function evaluateCrudMap(crud: CrudMap, env: Environment): Promise<void> {
|
|
|
1734
1802
|
await runPreUpdateEvents(lastRes, env);
|
|
1735
1803
|
const finalInst: Instance = await res.updateInstance(lastRes, attrs);
|
|
1736
1804
|
await runPostUpdateEvents(finalInst, lastRes, env);
|
|
1737
|
-
env.setLastResult(finalInst);
|
|
1805
|
+
env.setLastResult([finalInst]);
|
|
1738
1806
|
}
|
|
1739
1807
|
}
|
|
1740
1808
|
}
|
|
@@ -2035,6 +2103,11 @@ async function agentInvoke(agent: AgentInstance, msg: string, env: Environment):
|
|
|
2035
2103
|
while (true) {
|
|
2036
2104
|
try {
|
|
2037
2105
|
let rs: string = result ? normalizeGeneratedCode(result) : '';
|
|
2106
|
+
if (agent.tools) {
|
|
2107
|
+
env.setLastPattern(rs);
|
|
2108
|
+
} else {
|
|
2109
|
+
env.setLastPattern(undefined);
|
|
2110
|
+
}
|
|
2038
2111
|
let isWf = rs.startsWith('workflow');
|
|
2039
2112
|
if (isWf && !agent.runWorkflows) {
|
|
2040
2113
|
await parseWorkflow(rs);
|
|
@@ -2128,6 +2201,10 @@ export async function handleAgentInvocation(
|
|
|
2128
2201
|
env: Environment
|
|
2129
2202
|
): Promise<void> {
|
|
2130
2203
|
const agent: AgentInstance = await findAgentByName(agentEventInst.name, env);
|
|
2204
|
+
const chatId = agentEventInst.lookup('chatId');
|
|
2205
|
+
if (chatId) {
|
|
2206
|
+
env.setActiveChatId(chatId);
|
|
2207
|
+
}
|
|
2131
2208
|
const origMsg: any =
|
|
2132
2209
|
agentEventInst.lookup('message') || JSON.stringify(agentEventInst.asObject());
|
|
2133
2210
|
const msg: string = isString(origMsg) ? origMsg : maybeInstanceAsString(origMsg);
|
|
@@ -2137,7 +2214,6 @@ export async function handleAgentInvocation(
|
|
|
2137
2214
|
} else {
|
|
2138
2215
|
const mode = agentEventInst.lookup('mode');
|
|
2139
2216
|
let activeEnv = env;
|
|
2140
|
-
const chatId = agentEventInst.lookup('chatId');
|
|
2141
2217
|
if (chatId !== undefined) {
|
|
2142
2218
|
activeEnv.setAgentChatId(chatId);
|
|
2143
2219
|
}
|
package/src/runtime/module.ts
CHANGED
|
@@ -1409,6 +1409,10 @@ export class Relationship extends Record {
|
|
|
1409
1409
|
return this.relType == RelType.BETWEEN;
|
|
1410
1410
|
}
|
|
1411
1411
|
|
|
1412
|
+
isSelfReferencing(): boolean {
|
|
1413
|
+
return this.node1.path.asFqName() === this.node2.path.asFqName();
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1412
1416
|
parentNode(): RelationshipNode {
|
|
1413
1417
|
return this.node1;
|
|
1414
1418
|
}
|
|
@@ -1502,6 +1506,28 @@ export class Relationship extends Record {
|
|
|
1502
1506
|
}
|
|
1503
1507
|
}
|
|
1504
1508
|
|
|
1509
|
+
/**
|
|
1510
|
+
* For self-referencing relationships, resolve the alias for the connected instance
|
|
1511
|
+
* based on an explicit connectedAlias. Falls back to fqName-based lookup for
|
|
1512
|
+
* non-self-referencing relationships.
|
|
1513
|
+
*/
|
|
1514
|
+
getAliasForConnected(inst: Instance, connectedAlias?: string): string {
|
|
1515
|
+
if (connectedAlias && this.isSelfReferencing()) {
|
|
1516
|
+
return connectedAlias;
|
|
1517
|
+
}
|
|
1518
|
+
return this.getAliasFor(inst);
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
getInverseAliasForConnected(inst: Instance, connectedAlias?: string): string {
|
|
1522
|
+
if (connectedAlias && this.isSelfReferencing()) {
|
|
1523
|
+
if (connectedAlias === this.node1.alias) {
|
|
1524
|
+
return this.node2.alias;
|
|
1525
|
+
}
|
|
1526
|
+
return this.node1.alias;
|
|
1527
|
+
}
|
|
1528
|
+
return this.getInverseAliasFor(inst);
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1505
1531
|
isParent(inst: Instance): boolean {
|
|
1506
1532
|
return inst.getFqName() == this.node1.path.asFqName();
|
|
1507
1533
|
}
|