agentlang 0.7.9 → 0.7.11

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.
Files changed (131) hide show
  1. package/out/api/http.d.ts.map +1 -1
  2. package/out/api/http.js +8 -1
  3. package/out/api/http.js.map +1 -1
  4. package/out/cli/main.d.ts.map +1 -1
  5. package/out/cli/main.js +33 -2
  6. package/out/cli/main.js.map +1 -1
  7. package/out/extension/main.cjs +250 -250
  8. package/out/extension/main.cjs.map +2 -2
  9. package/out/language/agentlang-validator.d.ts +1 -2
  10. package/out/language/agentlang-validator.d.ts.map +1 -1
  11. package/out/language/agentlang-validator.js +0 -39
  12. package/out/language/agentlang-validator.js.map +1 -1
  13. package/out/language/generated/ast.d.ts +62 -11
  14. package/out/language/generated/ast.d.ts.map +1 -1
  15. package/out/language/generated/ast.js +75 -3
  16. package/out/language/generated/ast.js.map +1 -1
  17. package/out/language/generated/grammar.d.ts.map +1 -1
  18. package/out/language/generated/grammar.js +758 -239
  19. package/out/language/generated/grammar.js.map +1 -1
  20. package/out/language/main.cjs +1370 -824
  21. package/out/language/main.cjs.map +4 -4
  22. package/out/language/parser.d.ts +1 -0
  23. package/out/language/parser.d.ts.map +1 -1
  24. package/out/language/parser.js +44 -7
  25. package/out/language/parser.js.map +1 -1
  26. package/out/language/syntax.d.ts +1 -1
  27. package/out/language/syntax.d.ts.map +1 -1
  28. package/out/language/syntax.js +22 -13
  29. package/out/language/syntax.js.map +1 -1
  30. package/out/runtime/api.d.ts +2 -0
  31. package/out/runtime/api.d.ts.map +1 -1
  32. package/out/runtime/api.js +5 -0
  33. package/out/runtime/api.js.map +1 -1
  34. package/out/runtime/auth/cognito.d.ts.map +1 -1
  35. package/out/runtime/auth/cognito.js +4 -4
  36. package/out/runtime/auth/cognito.js.map +1 -1
  37. package/out/runtime/defs.d.ts +5 -0
  38. package/out/runtime/defs.d.ts.map +1 -1
  39. package/out/runtime/defs.js +16 -0
  40. package/out/runtime/defs.js.map +1 -1
  41. package/out/runtime/exec-graph.js +1 -1
  42. package/out/runtime/exec-graph.js.map +1 -1
  43. package/out/runtime/interpreter.d.ts +6 -1
  44. package/out/runtime/interpreter.d.ts.map +1 -1
  45. package/out/runtime/interpreter.js +144 -112
  46. package/out/runtime/interpreter.js.map +1 -1
  47. package/out/runtime/loader.d.ts +1 -1
  48. package/out/runtime/loader.d.ts.map +1 -1
  49. package/out/runtime/loader.js +74 -27
  50. package/out/runtime/loader.js.map +1 -1
  51. package/out/runtime/module.d.ts +41 -11
  52. package/out/runtime/module.d.ts.map +1 -1
  53. package/out/runtime/module.js +238 -50
  54. package/out/runtime/module.js.map +1 -1
  55. package/out/runtime/modules/ai.d.ts.map +1 -1
  56. package/out/runtime/modules/ai.js +13 -6
  57. package/out/runtime/modules/ai.js.map +1 -1
  58. package/out/runtime/modules/auth.d.ts +2 -1
  59. package/out/runtime/modules/auth.d.ts.map +1 -1
  60. package/out/runtime/modules/auth.js +93 -3
  61. package/out/runtime/modules/auth.js.map +1 -1
  62. package/out/runtime/modules/core.d.ts +7 -5
  63. package/out/runtime/modules/core.d.ts.map +1 -1
  64. package/out/runtime/modules/core.js +93 -16
  65. package/out/runtime/modules/core.js.map +1 -1
  66. package/out/runtime/monitor.d.ts.map +1 -1
  67. package/out/runtime/monitor.js +1 -0
  68. package/out/runtime/monitor.js.map +1 -1
  69. package/out/runtime/resolvers/interface.d.ts +6 -1
  70. package/out/runtime/resolvers/interface.d.ts.map +1 -1
  71. package/out/runtime/resolvers/interface.js +2 -2
  72. package/out/runtime/resolvers/interface.js.map +1 -1
  73. package/out/runtime/resolvers/sqldb/database.d.ts +19 -2
  74. package/out/runtime/resolvers/sqldb/database.d.ts.map +1 -1
  75. package/out/runtime/resolvers/sqldb/database.js +107 -21
  76. package/out/runtime/resolvers/sqldb/database.js.map +1 -1
  77. package/out/runtime/resolvers/sqldb/dbutil.d.ts +1 -0
  78. package/out/runtime/resolvers/sqldb/dbutil.d.ts.map +1 -1
  79. package/out/runtime/resolvers/sqldb/dbutil.js +25 -3
  80. package/out/runtime/resolvers/sqldb/dbutil.js.map +1 -1
  81. package/out/runtime/resolvers/sqldb/impl.d.ts +3 -2
  82. package/out/runtime/resolvers/sqldb/impl.d.ts.map +1 -1
  83. package/out/runtime/resolvers/sqldb/impl.js +80 -6
  84. package/out/runtime/resolvers/sqldb/impl.js.map +1 -1
  85. package/out/runtime/state.d.ts +58 -0
  86. package/out/runtime/state.d.ts.map +1 -1
  87. package/out/runtime/state.js +12 -0
  88. package/out/runtime/state.js.map +1 -1
  89. package/out/runtime/util.d.ts +1 -1
  90. package/out/runtime/util.d.ts.map +1 -1
  91. package/out/runtime/util.js +27 -13
  92. package/out/runtime/util.js.map +1 -1
  93. package/out/setupClassic.d.ts +98 -0
  94. package/out/setupClassic.d.ts.map +1 -0
  95. package/out/setupClassic.js +38 -0
  96. package/out/setupClassic.js.map +1 -0
  97. package/out/setupCommon.d.ts +2 -0
  98. package/out/setupCommon.d.ts.map +1 -0
  99. package/out/setupCommon.js +33 -0
  100. package/out/setupCommon.js.map +1 -0
  101. package/out/setupExtended.d.ts +40 -0
  102. package/out/setupExtended.d.ts.map +1 -0
  103. package/out/setupExtended.js +67 -0
  104. package/out/setupExtended.js.map +1 -0
  105. package/out/syntaxes/agentlang.monarch.js +1 -1
  106. package/out/syntaxes/agentlang.monarch.js.map +1 -1
  107. package/package.json +187 -185
  108. package/src/api/http.ts +8 -0
  109. package/src/cli/main.ts +38 -2
  110. package/src/language/agentlang-validator.ts +1 -51
  111. package/src/language/agentlang.langium +17 -4
  112. package/src/language/generated/ast.ts +147 -13
  113. package/src/language/generated/grammar.ts +758 -239
  114. package/src/language/parser.ts +43 -8
  115. package/src/language/syntax.ts +25 -12
  116. package/src/runtime/api.ts +8 -0
  117. package/src/runtime/defs.ts +8 -0
  118. package/src/runtime/interpreter.ts +104 -76
  119. package/src/runtime/loader.ts +75 -25
  120. package/src/runtime/module.ts +194 -32
  121. package/src/runtime/modules/ai.ts +10 -4
  122. package/src/runtime/modules/auth.ts +1 -0
  123. package/src/runtime/modules/core.ts +99 -23
  124. package/src/runtime/monitor.ts +1 -0
  125. package/src/runtime/resolvers/interface.ts +9 -2
  126. package/src/runtime/resolvers/sqldb/database.ts +68 -17
  127. package/src/runtime/resolvers/sqldb/dbutil.ts +28 -6
  128. package/src/runtime/resolvers/sqldb/impl.ts +86 -14
  129. package/src/runtime/state.ts +14 -0
  130. package/src/runtime/util.ts +25 -12
  131. package/src/syntaxes/agentlang.monarch.ts +1 -1
@@ -20,6 +20,8 @@ import {
20
20
  RbacSpecEntries,
21
21
  RbacOpr,
22
22
  WorkflowHeader,
23
+ FlowDefinition,
24
+ FlowEntry,
23
25
  } from '../language/generated/ast.js';
24
26
  import {
25
27
  Path,
@@ -75,7 +77,7 @@ import {
75
77
  removeAgentResponseSchema,
76
78
  removeAgentScenarios,
77
79
  } from './agents/common.js';
78
- import { Environment } from './interpreter.js';
80
+ import { AggregateFunctionCall, Environment } from './interpreter.js';
79
81
  import { isNode } from '../utils/fs-utils.js';
80
82
 
81
83
  export class ModuleEntry {
@@ -208,7 +210,7 @@ function attributePropertyValueToString(
208
210
  });
209
211
  return ss.join(',');
210
212
  } else if (propName == 'default') {
211
- if (isTextualType(attrType) && propValue != 'now()' && propValue != 'uuid()') {
213
+ if (isTextualType(attrType) && !defaultValueIsFunctionCall(propValue)) {
212
214
  return `"${propValue}"`;
213
215
  }
214
216
  } else if (propName == 'comment') {
@@ -433,6 +435,37 @@ export class Record extends ModuleEntry {
433
435
  return this;
434
436
  }
435
437
 
438
+ public getSecretAttributes(): Array<string> {
439
+ const result = new Array<string>();
440
+ this.schema.forEach((spec: AttributeSpec, n: string) => {
441
+ if (spec.properties?.get('secret') === true) {
442
+ result.push(n);
443
+ }
444
+ });
445
+ return result;
446
+ }
447
+
448
+ private static WriteOnlyAttributes = new Map<string, Array<string>>();
449
+
450
+ public getWriteOnlyAttributes(): Array<string> | undefined {
451
+ const fqn = this.getFqName();
452
+ const cachedResult = Record.WriteOnlyAttributes.get(fqn);
453
+ if (cachedResult !== undefined) {
454
+ if (cachedResult.length === 0) return undefined;
455
+ return cachedResult;
456
+ } else {
457
+ const result = new Array<string>();
458
+ this.schema.forEach((spec: AttributeSpec, n: string) => {
459
+ if (spec.properties?.get('writeonly') === true) {
460
+ result.push(n);
461
+ }
462
+ });
463
+ const finalResult = result.concat(this.getSecretAttributes());
464
+ Record.WriteOnlyAttributes.set(fqn, finalResult);
465
+ return finalResult;
466
+ }
467
+ }
468
+
436
469
  getCompositeUniqueAttributes(): Array<string> | undefined {
437
470
  return this.compositeUqAttributes;
438
471
  }
@@ -641,18 +674,27 @@ export class Record extends ModuleEntry {
641
674
  return s.concat('\n{', scms, '\n}\n');
642
675
  }
643
676
 
677
+ private userAttrsSchema: RecordSchema | undefined;
678
+
644
679
  getUserAttributes(): RecordSchema {
645
- const recSchema: RecordSchema = newRecordSchema();
646
- this.schema.forEach((attrSpec: AttributeSpec, n: string) => {
647
- if (!isSystemAttribute(attrSpec)) {
648
- recSchema.set(n, attrSpec);
649
- }
650
- });
651
- return recSchema;
680
+ if (this.userAttrsSchema === undefined) {
681
+ this.userAttrsSchema = newRecordSchema();
682
+ this.schema.forEach((attrSpec: AttributeSpec, n: string) => {
683
+ if (!isSystemAttribute(attrSpec)) {
684
+ this.userAttrsSchema?.set(n, attrSpec);
685
+ }
686
+ });
687
+ }
688
+ return this.userAttrsSchema;
652
689
  }
653
690
 
654
- getUserAttributeNames(): string[] {
655
- return [...this.getUserAttributes().keys()];
691
+ private userAttrNames: Set<string> | undefined;
692
+
693
+ getUserAttributeNames(): Set<string> {
694
+ if (this.userAttrNames === undefined) {
695
+ this.userAttrNames = new Set([...this.getUserAttributes().keys()]);
696
+ }
697
+ return this.userAttrNames;
656
698
  }
657
699
  }
658
700
 
@@ -1592,18 +1634,21 @@ export type FlowGraphNode = {
1592
1634
  next: string[];
1593
1635
  };
1594
1636
 
1637
+ function splitFlowSteps(flow: FlowDefinition): string[] {
1638
+ const steps = new Array<string>();
1639
+ flow.body?.entries.forEach((fe: FlowEntry) => {
1640
+ steps.push(fe.$cstNode?.text || '');
1641
+ });
1642
+ return steps;
1643
+ }
1644
+
1595
1645
  export class Flow extends ModuleEntry {
1596
1646
  flowSteps: string[];
1597
1647
 
1598
- constructor(name: string, moduleName: string, flow?: string) {
1648
+ constructor(name: string, moduleName: string, flow?: FlowDefinition) {
1599
1649
  super(name, moduleName);
1600
- this.flowSteps = new Array<string>();
1601
- flow?.split('\n').forEach((step: string) => {
1602
- const s = step.trim();
1603
- if (s.length > 0) {
1604
- this.flowSteps.push(s);
1605
- }
1606
- });
1650
+ if (flow) this.flowSteps = splitFlowSteps(flow);
1651
+ else this.flowSteps = new Array<string>();
1607
1652
  }
1608
1653
 
1609
1654
  getFlow(): string {
@@ -1629,10 +1674,11 @@ export class Flow extends ModuleEntry {
1629
1674
  return this.flowSteps.length;
1630
1675
  }
1631
1676
 
1632
- toGraph(): FlowGraphNode[] {
1677
+ async toGraph(): Promise<FlowGraphNode[]> {
1633
1678
  const result = new Array<FlowGraphNode>();
1634
- this.flowSteps.forEach((s: string) => {
1635
- const fp = FlowStepPattern.Parse(s);
1679
+ for (let i = 0; i < this.flowSteps.length; ++i) {
1680
+ const s = this.flowSteps[i];
1681
+ const fp = await FlowStepPattern.Parse(s);
1636
1682
  if (fp.condition) {
1637
1683
  const orig = result.find((v: FlowGraphNode) => {
1638
1684
  return v.label == fp.first;
@@ -1657,7 +1703,7 @@ export class Flow extends ModuleEntry {
1657
1703
  next: [fp.next],
1658
1704
  });
1659
1705
  }
1660
- });
1706
+ }
1661
1707
  return result;
1662
1708
  }
1663
1709
 
@@ -1801,6 +1847,11 @@ export class Retry extends ModuleEntry {
1801
1847
  };
1802
1848
  }
1803
1849
 
1850
+ setBackoffStrategy(s: BackoffStrategy): Retry {
1851
+ this.backoff.strategy = s;
1852
+ return this;
1853
+ }
1854
+
1804
1855
  setExponentialBackoff(): Retry {
1805
1856
  this.backoff.strategy = 'e';
1806
1857
  return this;
@@ -1835,6 +1886,17 @@ export class Retry extends ModuleEntry {
1835
1886
  return this;
1836
1887
  }
1837
1888
 
1889
+ setBackoffMagnitude(m: string): Retry {
1890
+ if (m[0] === 's') {
1891
+ this.backoff.magnitude = 's';
1892
+ } else if (m.startsWith('milli')) {
1893
+ this.backoff.magnitude = 'ms';
1894
+ } else {
1895
+ this.backoff.magnitude = 'm';
1896
+ }
1897
+ return this;
1898
+ }
1899
+
1838
1900
  setBackoffMagnitudeAsMilliseconds(): Retry {
1839
1901
  this.backoff.magnitude = 'ms';
1840
1902
  return this;
@@ -1995,9 +2057,15 @@ export function isEmptyWorkflow(wf: Workflow): boolean {
1995
2057
  return wf == EmptyWorkflow;
1996
2058
  }
1997
2059
 
2060
+ export type ModuleImportEntry = {
2061
+ path: string;
2062
+ name: string;
2063
+ };
2064
+
1998
2065
  export class Module {
1999
2066
  name: string;
2000
2067
  entries: ModuleEntry[];
2068
+ imports: ModuleImportEntry[] | undefined;
2001
2069
 
2002
2070
  constructor(name: string) {
2003
2071
  this.name = name;
@@ -2009,6 +2077,21 @@ export class Module {
2009
2077
  return entry;
2010
2078
  }
2011
2079
 
2080
+ addImport(entry: ModuleImportEntry): Module {
2081
+ if (this.imports === undefined) {
2082
+ this.imports = new Array<ModuleImportEntry>();
2083
+ }
2084
+ this.imports?.push(entry);
2085
+ return this;
2086
+ }
2087
+
2088
+ removeImportAt(index: number): Module {
2089
+ if (index >= 0) {
2090
+ this.imports?.splice(index, 1);
2091
+ }
2092
+ return this;
2093
+ }
2094
+
2012
2095
  getConfigEntity(): Entity | undefined {
2013
2096
  return this.getEntityEntries().find((e: Entity) => {
2014
2097
  return e.isConfigEntity();
@@ -2031,8 +2114,8 @@ export class Module {
2031
2114
  return this.removeEntry(Agent.EscapeName(agentName));
2032
2115
  }
2033
2116
 
2034
- addFlow(name: string, flowString?: string): Flow {
2035
- const flow: Flow = new Flow(Flow.asFlowName(name), this.name, flowString);
2117
+ addFlow(name: string, flowDef?: FlowDefinition): Flow {
2118
+ const flow: Flow = new Flow(Flow.asFlowName(name), this.name, flowDef);
2036
2119
  this.addEntry(flow);
2037
2120
  return flow;
2038
2121
  }
@@ -2434,6 +2517,14 @@ export class Module {
2434
2517
  return names;
2435
2518
  }
2436
2519
 
2520
+ getBetweenRelationshipNames(): string[] {
2521
+ const names: string[] = [];
2522
+ this.getRelationshipEntries().forEach((re: Relationship) => {
2523
+ if (re.isBetween()) names.push(re.name);
2524
+ });
2525
+ return names;
2526
+ }
2527
+
2437
2528
  isContainsRelationship(entryName: string): boolean {
2438
2529
  if (this.hasEntry(entryName)) {
2439
2530
  const entry: ModuleEntry = this.getEntry(entryName);
@@ -2450,6 +2541,17 @@ export class Module {
2450
2541
  return false;
2451
2542
  }
2452
2543
 
2544
+ private importsAsString(): string {
2545
+ if (this.imports !== undefined) {
2546
+ const ss = new Array<string>();
2547
+ this.imports.forEach((me: ModuleImportEntry) => {
2548
+ ss.push(`import "${me.path}" @as ${me.name}`);
2549
+ });
2550
+ return `\n${ss.join('\n')}\n`;
2551
+ }
2552
+ return '';
2553
+ }
2554
+
2453
2555
  toString(): string {
2454
2556
  const ss: Array<string> = [];
2455
2557
  this.entries.forEach((me: ModuleEntry) => {
@@ -2458,8 +2560,27 @@ export class Module {
2458
2560
  }
2459
2561
  ss.push(me.toString());
2460
2562
  });
2461
- return `module ${this.name}\n\n${ss.join('\n')}`;
2563
+ return `module ${this.name}\n${this.importsAsString()}\n${ss.join('\n')}`;
2564
+ }
2565
+ }
2566
+
2567
+ let GlobalRetries: Array<Retry> | undefined = undefined;
2568
+
2569
+ export function addGlobalRetry(r: Retry): Retry {
2570
+ if (GlobalRetries === undefined) {
2571
+ GlobalRetries = new Array<Retry>();
2572
+ }
2573
+ GlobalRetries?.push(r);
2574
+ return r;
2575
+ }
2576
+
2577
+ export function getGlobalRetry(name: string): Retry | undefined {
2578
+ if (GlobalRetries !== undefined) {
2579
+ return GlobalRetries.find((r: Retry) => {
2580
+ return r.name === name;
2581
+ });
2462
2582
  }
2583
+ return undefined;
2463
2584
  }
2464
2585
 
2465
2586
  declare global {
@@ -2587,6 +2708,8 @@ export const propertyNames = new Set([
2587
2708
  '@fk',
2588
2709
  '@ref',
2589
2710
  '@readonly',
2711
+ '@writeonly',
2712
+ '@secret',
2590
2713
  '@enum',
2591
2714
  '@oneof',
2592
2715
  '@comment',
@@ -2655,7 +2778,7 @@ export function defaultAttributes(schema: RecordSchema): Map<string, any> {
2655
2778
  export function passwordAttributes(schema: RecordSchema): Set<string> | undefined {
2656
2779
  let result: Set<string> | undefined = undefined;
2657
2780
  schema.forEach((v: AttributeSpec, k: string) => {
2658
- if (v.type == 'Password') {
2781
+ if (v.type == 'Password' || v.properties?.get('secret') === true) {
2659
2782
  if (result === undefined) {
2660
2783
  result = new Set<string>();
2661
2784
  }
@@ -3336,6 +3459,10 @@ export class Instance {
3336
3459
  queryAttributes: InstanceAttributes | undefined;
3337
3460
  queryAttributeValues: InstanceAttributes | undefined;
3338
3461
  relatedInstances: Map<string, Instance[]> | undefined;
3462
+ aggregates: Map<string, AggregateFunctionCall> | undefined;
3463
+ groupBy: string[] | undefined;
3464
+ orderBy: string[] | undefined;
3465
+ orderByDesc: boolean = false;
3339
3466
  private contextData: Map<string, any> | undefined;
3340
3467
  private ___id: string;
3341
3468
 
@@ -3432,6 +3559,22 @@ export class Instance {
3432
3559
  return this.lookup(PathAttributeName);
3433
3560
  }
3434
3561
 
3562
+ setAggregates(aggregates: Map<string, AggregateFunctionCall>): Instance {
3563
+ this.aggregates = aggregates;
3564
+ return this;
3565
+ }
3566
+
3567
+ setGroupBy(n: string[]): Instance {
3568
+ this.groupBy = n;
3569
+ return this;
3570
+ }
3571
+
3572
+ setOrderBy(n: string[], desc: boolean = false): Instance {
3573
+ this.orderBy = n;
3574
+ this.orderByDesc = desc;
3575
+ return this;
3576
+ }
3577
+
3435
3578
  asSerializableObject(): object {
3436
3579
  const obj: any = {
3437
3580
  AL_INSTANCE: true,
@@ -3519,6 +3662,15 @@ export class Instance {
3519
3662
  return Object.fromEntries(attrs);
3520
3663
  }
3521
3664
 
3665
+ userAttributesAsObject(forSerialization: boolean = false): object {
3666
+ const attrs = newInstanceAttributes();
3667
+ const userAttrNames = this.getAllUserAttributeNames();
3668
+ this.attributes.forEach((v: any, k: string) => {
3669
+ if (userAttrNames.has(k)) attrs.set(k, Instance.asSerializableValue(v, forSerialization));
3670
+ });
3671
+ return Object.fromEntries(attrs);
3672
+ }
3673
+
3522
3674
  static stringifyObjects(attributes: InstanceAttributes): object {
3523
3675
  const attrs = newInstanceAttributes();
3524
3676
  attributes.forEach((v: any, k: string) => {
@@ -3549,6 +3701,10 @@ export class Instance {
3549
3701
  return {};
3550
3702
  }
3551
3703
 
3704
+ getQueryValue(k: string): any {
3705
+ return this.queryAttributeValues?.get(k);
3706
+ }
3707
+
3552
3708
  addQuery(attrName: string, op: string = '=', attrVal: any = undefined) {
3553
3709
  if (this.queryAttributes === undefined) this.queryAttributes = newInstanceAttributes();
3554
3710
  this.queryAttributes.set(attrName, op);
@@ -3610,7 +3766,7 @@ export class Instance {
3610
3766
  return undefined;
3611
3767
  }
3612
3768
 
3613
- getAllUserAttributeNames(): string[] {
3769
+ getAllUserAttributeNames(): Set<string> {
3614
3770
  return this.record.getUserAttributeNames();
3615
3771
  }
3616
3772
 
@@ -3743,6 +3899,10 @@ export function findIdAttribute(inst: Instance): AttributeEntry | undefined {
3743
3899
  return undefined;
3744
3900
  }
3745
3901
 
3902
+ function defaultValueIsFunctionCall(dv: string): boolean {
3903
+ return dv.endsWith('()');
3904
+ }
3905
+
3746
3906
  function maybeSetDefaultAttributeValues(
3747
3907
  schema: RecordSchema,
3748
3908
  attributes: InstanceAttributes
@@ -3752,10 +3912,12 @@ function maybeSetDefaultAttributeValues(
3752
3912
  const cv = attributes.get(k);
3753
3913
  if (cv === undefined || cv === null) {
3754
3914
  if (isString(v)) {
3755
- if (v == 'uuid()') {
3756
- v = crypto.randomUUID();
3757
- } else if (v == 'now()') {
3758
- v = now();
3915
+ if (defaultValueIsFunctionCall(v)) {
3916
+ try {
3917
+ v = eval(v);
3918
+ } catch {
3919
+ v = (0, eval)(`globalThis.${v}`);
3920
+ }
3759
3921
  }
3760
3922
  }
3761
3923
  attributes.set(k, v);
@@ -20,6 +20,7 @@ import {
20
20
  Decision,
21
21
  fetchModule,
22
22
  getDecision,
23
+ getGlobalRetry,
23
24
  Instance,
24
25
  instanceToObject,
25
26
  isAgent,
@@ -198,11 +199,16 @@ export class AgentInstance {
198
199
  if (agent.retry) {
199
200
  let n = agent.retry;
200
201
  if (!isFqName(n)) {
201
- n = `${agent.moduleName}/${n}`;
202
+ agent.retryObj = getGlobalRetry(n);
203
+ if (agent.retryObj === undefined) {
204
+ n = `${agent.moduleName}/${n}`;
205
+ }
206
+ }
207
+ if (agent.retryObj === undefined) {
208
+ const parts = splitFqName(n);
209
+ const m = fetchModule(parts[0]);
210
+ agent.retryObj = m.getRetry(parts[1]);
202
211
  }
203
- const parts = splitFqName(n);
204
- const m = fetchModule(parts[0]);
205
- agent.retryObj = m.getRetry(parts[1]);
206
212
  }
207
213
  return agent;
208
214
  }
@@ -36,6 +36,7 @@ entity User {
36
36
  email Email @unique @indexed,
37
37
  firstName String,
38
38
  lastName String,
39
+ profilePicture String @optional,
39
40
  lastLoginTime DateTime @default(now()),
40
41
  status @enum("Active", "Invited", "Inactive") @default("Active"),
41
42
  @rbac [(allow: [read, delete, update, create], where: auth.user = this.id)],
@@ -8,6 +8,7 @@ import {
8
8
  isString,
9
9
  restoreSpecialChars,
10
10
  makeCoreModuleName,
11
+ nameToPath,
11
12
  } from '../util.js';
12
13
  import {
13
14
  fetchModule,
@@ -27,7 +28,7 @@ import {
27
28
  } from '../interpreter.js';
28
29
  import { logger } from '../logger.js';
29
30
  import { Statement } from '../../language/generated/ast.js';
30
- import { parseModule, parseStatements } from '../../language/parser.js';
31
+ import { objectToQueryPattern, parseModule, parseStatements } from '../../language/parser.js';
31
32
  import { GenericResolver, Resolver } from '../resolvers/interface.js';
32
33
  import {
33
34
  FlowSuspensionTag,
@@ -48,7 +49,8 @@ entity timer {
48
49
  duration Int,
49
50
  unit @enum("millisecond", "second", "minute", "hour") @default("second"),
50
51
  trigger String,
51
- status @enum("I", "C", "R") @default("I") // Inited, Cancelled, Running
52
+ repeat Boolean @default(true),
53
+ status @enum("I", "C", "R") @default("I") @indexed // Inited, Cancelled, Running
52
54
  }
53
55
 
54
56
  entity auditlog {
@@ -56,7 +58,7 @@ entity auditlog {
56
58
  action @enum("c", "d", "u"), // Create, Delete, Update
57
59
  resource String, // __path__
58
60
  timestamp DateTime @default(now()),
59
- previous_value Any @optional,
61
+ diff Any @optional,
60
62
  user String,
61
63
  token String @optional
62
64
  }
@@ -161,6 +163,14 @@ entity Migration {
161
163
  ups String @optional,
162
164
  downs String @optional
163
165
  }
166
+
167
+ @public event Query {
168
+ q Any
169
+ }
170
+
171
+ workflow Query {
172
+ await Core.doRawQuery(Query.q)
173
+ }
164
174
  `;
165
175
 
166
176
  export const CoreModules: string[] = [];
@@ -183,25 +193,94 @@ export function registerCoreModules() {
183
193
  });
184
194
  }
185
195
 
186
- export function setTimerRunning(timerInst: Instance) {
187
- timerInst.attributes.set('status', 'R');
196
+ function isTimerCancelled(inst: Instance): boolean {
197
+ return inst.lookup('status') === 'C';
188
198
  }
189
199
 
190
- export async function maybeCancelTimer(name: string, timer: NodeJS.Timeout, env: Environment) {
200
+ // If the timer is deleted or its status is set to 'C' (cancelled), then clear the associated timer.
201
+ async function maybeClearTimer(name: string, timer: NodeJS.Timeout, env: Environment) {
191
202
  await parseAndEvaluateStatement(`{agentlang/timer {name? "${name}"}}`, undefined, env).then(
192
203
  (result: any) => {
193
- if (result === null || (result instanceof Array && result.length == 0)) {
204
+ if (
205
+ result === null ||
206
+ (result instanceof Array && (result.length == 0 || isTimerCancelled(result[0])))
207
+ ) {
194
208
  clearInterval(timer);
195
209
  }
196
210
  }
197
211
  );
198
212
  }
199
213
 
214
+ export function triggerTimer(timerInst: Instance): Instance {
215
+ const dur = timerInst.lookup('duration');
216
+ const unit = timerInst.lookup('unit');
217
+ let millisecs = 0;
218
+ switch (unit) {
219
+ case 'millisecond': {
220
+ millisecs = dur;
221
+ break;
222
+ }
223
+ case 'second': {
224
+ millisecs = dur * 1000;
225
+ break;
226
+ }
227
+ case 'minute': {
228
+ millisecs = dur * 60 * 1000;
229
+ break;
230
+ }
231
+ case 'hour': {
232
+ millisecs = dur * 60 * 60 * 1000;
233
+ break;
234
+ }
235
+ }
236
+ const eventName = nameToPath(timerInst.lookup('trigger'));
237
+ const m = eventName.hasModule() ? eventName.getModuleName() : timerInst.moduleName;
238
+ const n = eventName.getEntryName();
239
+ const inst = makeInstance(m, n, newInstanceAttributes());
240
+ const name = timerInst.lookup('name');
241
+ const repeat = timerInst.lookup('repeat');
242
+ const timer = setInterval(async () => {
243
+ const env = new Environment();
244
+ try {
245
+ await evaluate(
246
+ inst,
247
+ (result: any) => logger.debug(`Timer ${name} ran with result ${result}`),
248
+ env
249
+ );
250
+ await env.commitAllTransactions();
251
+ if (!repeat) clearInterval(timer);
252
+ else await maybeClearTimer(name, timer, env);
253
+ } catch (reason: any) {
254
+ logger.error(`Timer ${name} raised error: ${reason}`);
255
+ }
256
+ }, millisecs);
257
+ timerInst.attributes.set('status', 'R');
258
+ return timerInst;
259
+ }
260
+
261
+ export async function saveTimerStatus(timerInst: Instance): Promise<boolean> {
262
+ const name = timerInst.lookup('name');
263
+ const status = timerInst.lookup('status');
264
+ const env = new Environment();
265
+ try {
266
+ await parseAndEvaluateStatement(`{agentlang/timer {name? "${name}", "status": "${status}"}}`);
267
+ await env.commitAllTransactions();
268
+ } catch (reason: any) {
269
+ logger.warn(`Failed to save status of timer ${name} - ${reason}`);
270
+ return false;
271
+ }
272
+ return true;
273
+ }
274
+
275
+ export async function lookupTimersWithRunningStatus(): Promise<Instance[]> {
276
+ return await parseAndEvaluateStatement(`{agentlang/timer {status? "R"}}`);
277
+ }
278
+
200
279
  async function addAudit(
201
280
  env: Environment,
202
281
  action: 'c' | 'd' | 'u',
203
282
  resource: string,
204
- previuos_value?: Instance
283
+ diff?: object
205
284
  ) {
206
285
  const user = env.getActiveUser();
207
286
  const token = env.getActiveToken();
@@ -211,7 +290,7 @@ async function addAudit(
211
290
  `{agentlang/auditlog {
212
291
  action "${action}",
213
292
  resource "${resource}",
214
- previous_value "${previuos_value ? escapeSpecialChars(JSON.stringify(previuos_value.asObject())) : ''}",
293
+ diff "${diff ? escapeSpecialChars(JSON.stringify(diff)) : ''}",
215
294
  user "${user}",
216
295
  token "${token ? token : ''}"
217
296
  }}`,
@@ -225,24 +304,16 @@ async function addAudit(
225
304
  }
226
305
  }
227
306
 
228
- export async function addCreateAudit(resource: string, env: Environment) {
229
- await addAudit(env, 'c', resource);
307
+ export async function addCreateAudit(resource: string, env: Environment, init: object) {
308
+ await addAudit(env, 'c', resource, init);
230
309
  }
231
310
 
232
- export async function addDeleteAudit(
233
- resource: string,
234
- previous_value: Instance | undefined,
235
- env: Environment
236
- ) {
237
- await addAudit(env, 'd', resource, previous_value);
311
+ export async function addDeleteAudit(resource: string, diff: object | undefined, env: Environment) {
312
+ await addAudit(env, 'd', resource, diff);
238
313
  }
239
314
 
240
- export async function addUpdateAudit(
241
- resource: string,
242
- previous_value: Instance | undefined,
243
- env: Environment
244
- ) {
245
- await addAudit(env, 'u', resource, previous_value);
315
+ export async function addUpdateAudit(resource: string, diff: object | undefined, env: Environment) {
316
+ await addAudit(env, 'u', resource, diff);
246
317
  }
247
318
 
248
319
  export async function createSuspension(
@@ -664,3 +735,8 @@ export function migrationDowns(inst: Instance): string[] | undefined {
664
735
  }
665
736
  return undefined;
666
737
  }
738
+
739
+ export async function doRawQuery(q: any): Promise<any> {
740
+ const qs = objectToQueryPattern(q);
741
+ return await parseAndEvaluateStatement(qs);
742
+ }
@@ -289,6 +289,7 @@ export class Monitor {
289
289
 
290
290
  decrement(): Monitor {
291
291
  if (this.parent !== undefined) {
292
+ this.parent.totalLatency += this.totalLatency;
292
293
  return this.parent;
293
294
  }
294
295
  return this;
@@ -33,6 +33,12 @@ export function getSubscriptionEvent(resolverName: string): string | undefined {
33
33
  return subscriptionEvents.get(resolverName);
34
34
  }
35
35
 
36
+ export type WhereClause = {
37
+ attrName: string;
38
+ op: string;
39
+ qval: any;
40
+ };
41
+
36
42
  export class Resolver {
37
43
  protected authInfo: ResolverAuthInfo = DefaultAuthInfo;
38
44
  protected env: Environment | undefined;
@@ -131,10 +137,11 @@ export class Resolver {
131
137
  joinInfo: JoinInfo[],
132
138
  intoSpec: Map<string, string>,
133
139
  distinct: boolean = false,
134
- rawJoinSpec?: JoinSpec
140
+ rawJoinSpec?: JoinSpec[],
141
+ whereClauses?: WhereClause[]
135
142
  ): Promise<any> {
136
143
  return this.notImpl(
137
- `queryByJoin(${inst}, ${joinInfo}, ${intoSpec}, ${distinct} ${rawJoinSpec})`
144
+ `queryByJoin(${inst}, ${joinInfo}, ${intoSpec}, ${distinct}, ${rawJoinSpec}, ${whereClauses})`
138
145
  );
139
146
  }
140
147