agentlang 0.0.13 → 0.0.14

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 (64) hide show
  1. package/out/cli/docs.d.ts +2 -0
  2. package/out/cli/docs.d.ts.map +1 -0
  3. package/out/cli/docs.js +236 -0
  4. package/out/cli/docs.js.map +1 -0
  5. package/out/cli/main.d.ts.map +1 -1
  6. package/out/cli/main.js +5 -0
  7. package/out/cli/main.js.map +1 -1
  8. package/out/cli/openapi-docs.yml +695 -0
  9. package/out/index.d.ts +19 -0
  10. package/out/index.d.ts.map +1 -0
  11. package/out/index.js +25 -0
  12. package/out/index.js.map +1 -0
  13. package/out/language/generated/ast.d.ts +23 -12
  14. package/out/language/generated/ast.d.ts.map +1 -1
  15. package/out/language/generated/ast.js +18 -2
  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 +231 -122
  19. package/out/language/generated/grammar.js.map +1 -1
  20. package/out/language/main.cjs +243 -124
  21. package/out/language/main.cjs.map +2 -2
  22. package/out/runtime/agents/common.d.ts +1 -1
  23. package/out/runtime/agents/common.d.ts.map +1 -1
  24. package/out/runtime/agents/common.js +32 -9
  25. package/out/runtime/agents/common.js.map +1 -1
  26. package/out/runtime/integrations.d.ts +3 -0
  27. package/out/runtime/integrations.d.ts.map +1 -0
  28. package/out/runtime/integrations.js +72 -0
  29. package/out/runtime/integrations.js.map +1 -0
  30. package/out/runtime/interpreter.d.ts.map +1 -1
  31. package/out/runtime/interpreter.js +73 -32
  32. package/out/runtime/interpreter.js.map +1 -1
  33. package/out/runtime/jsmodules.js +1 -1
  34. package/out/runtime/loader.js +2 -2
  35. package/out/runtime/loader.js.map +1 -1
  36. package/out/runtime/module.d.ts +2 -0
  37. package/out/runtime/module.d.ts.map +1 -1
  38. package/out/runtime/module.js +13 -2
  39. package/out/runtime/module.js.map +1 -1
  40. package/out/runtime/resolvers/sqldb/database.js +1 -1
  41. package/out/runtime/resolvers/sqldb/database.js.map +1 -1
  42. package/out/runtime/resolvers/sqldb/dbutil.d.ts.map +1 -1
  43. package/out/runtime/resolvers/sqldb/dbutil.js +3 -2
  44. package/out/runtime/resolvers/sqldb/dbutil.js.map +1 -1
  45. package/out/runtime/state.d.ts +28 -0
  46. package/out/runtime/state.d.ts.map +1 -1
  47. package/out/runtime/state.js +8 -0
  48. package/out/runtime/state.js.map +1 -1
  49. package/out/syntaxes/agentlang.monarch.js +1 -1
  50. package/out/syntaxes/agentlang.monarch.js.map +1 -1
  51. package/package.json +3 -3
  52. package/src/cli/main.ts +10 -0
  53. package/src/language/agentlang.langium +14 -10
  54. package/src/language/generated/ast.ts +43 -13
  55. package/src/language/generated/grammar.ts +231 -122
  56. package/src/runtime/agents/common.ts +32 -9
  57. package/src/runtime/integrations.ts +92 -0
  58. package/src/runtime/interpreter.ts +97 -35
  59. package/src/runtime/loader.ts +2 -2
  60. package/src/runtime/module.ts +15 -2
  61. package/src/runtime/resolvers/sqldb/database.ts +1 -1
  62. package/src/runtime/resolvers/sqldb/dbutil.ts +3 -2
  63. package/src/runtime/state.ts +8 -0
  64. package/src/syntaxes/agentlang.monarch.ts +1 -1
@@ -1,6 +1,6 @@
1
1
  export const PlannerInstructions = `Agentlang is a very-high-level declarative language that makes it easy to define business applications as 'models'.
2
2
  The model of a business application consists of entity definitions and workflows defined in "modules".
3
- A module will be encoded in a syntax inspired by JavaScript and JSON. Example of a simple module definition is,
3
+ A module is be encoded in a syntax inspired by JavaScript and JSON. Example of a simple module follows:
4
4
 
5
5
  module Erp
6
6
 
@@ -12,9 +12,10 @@ entity Employee {
12
12
  email Email @indexed
13
13
  }
14
14
 
15
- The Empoyee entity is part of the "Erp" module and it has four attributes: employeeId, firstName, lastName, salary and email. The employeeId uniquely identifies an
16
- Employee and it's automatically filled-in by the system by calling the "uuid()" function. (In the place of the keyword 'entity', the keyword 'record' may also be used.
17
- The difference between an entity and a record is that, instances of an entity is persisted to the database, instances of records are not).
15
+ The Empoyee entity is part of the "Erp" module and it has four attributes: 'employeeId', 'firstName', 'lastName', 'salary' and 'email'.
16
+ The 'employeeId' attribute uniquely identifies an instance of the Employee entity and it's automatically filled-in by the system by calling the "uuid()" function.
17
+ In the place of the keyword 'entity', the keyword 'record' may also be used. The difference between an entity and a record is that,
18
+ instances of an entity is persisted to the database, instances of records are not.
18
19
 
19
20
  This is an example of a record:
20
21
 
@@ -25,7 +26,8 @@ record EmailMessage {
25
26
  body String
26
27
  }
27
28
 
28
- Workflows contains JSON "patterns" that perform CRUD operations on entities. For example, here's is a workflow that creates a new instance of the Employee entity:
29
+ Another major construct in Agentlang is the 'workflow'. Workflows contains JSON "patterns" that perform CRUD operations on entities.
30
+ For example, here's is a workflow that creates a new instance of the Employee entity:
29
31
 
30
32
  workflow CreateEmployee {
31
33
  {Erp/Employee {firstName CreateEmployee.firstName,
@@ -49,7 +51,7 @@ A workflow attached to an event is invoked by creating an instance of the event,
49
51
 
50
52
  {Erp/CreateEmployee {firstName "Sam", lastName "K", salary 1400, email "samk@acme.com"}}
51
53
 
52
- This means a workflow can be invoked from another workflow, simply by adding the event-creation as a pattern.
54
+ This means a workflow can be invoked from another workflow, simply by having the event-creation pattern.
53
55
 
54
56
  Other than the create-pattern for entities and events, some of the most useful patterns (related to entities) that can appear in a workflow are:
55
57
  1. Query - e.g: '{Erp/Employee {employeeId? "56392e13-0d9a-42f7-b556-0d7cd9468a24"}}'. The attributes by which the query happens must end with a '?' character.
@@ -58,7 +60,7 @@ Other than the create-pattern for entities and events, some of the most useful p
58
60
  with the given employeeId.
59
61
  3. Upsert - e.g: '{Erp/Employee {employeeId "56392e13-0d9a-42f7-b556-0d7cd9468a24", firstName "Joe"}, @upsert}'. The 'upsert' pattern will create a new
60
62
  instance, if the instance does not already exist.
61
- 4. Delete - e.g: delete '{Erp/Employee {employeeId? "56392e13-0d9a-42f7-b556-0d7cd9468a24"}}'
63
+ 4. Delete - e.g: 'delete {Erp/Employee {employeeId? "56392e13-0d9a-42f7-b556-0d7cd9468a24"}}'
62
64
 
63
65
  The default query operator is '=' (equals). So an expression like 'employeeId? "56392e13-0d9a-42f7-b556-0d7cd9468a24"' means,
64
66
  'where employeeId equals "56392e13-0d9a-42f7-b556-0d7cd9468a24"'. Other comparison operators has to be specified explicitly, as in
@@ -89,6 +91,19 @@ workflow IncrementSalary {
89
91
 
90
92
  Note the value passed to the 'salary' attribute - it's an arithmetic expression. All normal arithmetic expressions are supported by workflow patterns.
91
93
 
94
+ Another example of the 'if' pattern:
95
+
96
+ workflow validateLicense {
97
+ {checkLicenseNumber {number validateLicense.number}} @as response;
98
+ if (response = "ok") {
99
+ {license {number? validateLicense.number, status "active"}}
100
+ } else {
101
+ {license {number? validateLicense.number, status "canceled"}}
102
+ }
103
+ }
104
+
105
+ Also note the use of the '@as' keyword - this binds the result of a pattern to an 'alias'.
106
+
92
107
  A successful query pattern will return an array of instances. The 'for' pattern can be used to iterate over an array. An example follows:
93
108
 
94
109
  workflow NotifyEmployees {
@@ -98,8 +113,7 @@ workflow NotifyEmployees {
98
113
  }
99
114
  }
100
115
 
101
- Also note the use of the '@as' keyword - this binds the result of a pattern to an 'alias'. Here the result of the query is bound to the
102
- alias named 'employees'. Any pattern can have an alias, including 'if' and 'for'. An alias can be used to refer to the attributes of the instance,
116
+ Here the result of the query is bound to the alias named 'employees'. Any pattern can have an alias, including 'if' and 'for'. An alias can be used to refer to the attributes of the instance,
103
117
  via the dot(.) notation. Aliases can also be used to destructure a query result - here's an example:
104
118
 
105
119
  workflow FindFirstTwoEmployees {
@@ -134,6 +148,15 @@ A fix for the reference-error is shown below:
134
148
  {Employee {id? 101}} @as employee;
135
149
  {SendEmail {to employee.email, body "hello"}}
136
150
 
151
+ A pattern may execute asynchronously and its eventual result can be handled by patterns provided in the '@then' clause. An example is shown below:
152
+
153
+ {sendChatMessage {to "amy", "text" "hello"}} @as response @then {
154
+ {saveResponse {from "amy", "text" response}}
155
+ }
156
+
157
+ If you are instructed that a particular event will be called asynchronously, always provide the patterns that follows in its '@then' clause. You must add the
158
+ '@then' clause only if an event's documentation or instruction explicitly requires to do so.
159
+
137
160
  Entities in a module can be connected together in relationships. There are two types of relationships - 'contains' and 'between'.
138
161
  'Contains' relationship is for hierarchical data, as in a Library entity containing Books. 'Between' relationship is for graph-like data,
139
162
  like two Profiles in a social media app is connected as friends. A 'between' relationship can be one of the following three types - 'one_one' (one-to-one),
@@ -0,0 +1,92 @@
1
+ import { Instance } from './module.js';
2
+ import { isString } from './util.js';
3
+
4
+ const Integrations = new Map<string, Instance>();
5
+
6
+ const IntegManagerModel = 'integmanager.core';
7
+
8
+ export async function prepareIntegrations(
9
+ integManagerHost: string,
10
+ username: string | undefined,
11
+ password: string | undefined,
12
+ integConfigObj: object
13
+ ) {
14
+ const integConfig = new Map(Object.entries(integConfigObj));
15
+ const standardHeaders = await loginToIntegManager(integManagerHost, username, password);
16
+ const keys = [...integConfig.keys()];
17
+ for (let i = 0; i < keys.length; ++i) {
18
+ const configName = keys[i];
19
+ const configPath = integConfig.get(configName);
20
+ if (configPath) {
21
+ const apiUrl = mkApiUrl(integManagerHost, configPath);
22
+ const response = await fetch(apiUrl, {
23
+ method: 'GET',
24
+ headers: standardHeaders,
25
+ });
26
+
27
+ if (!response.ok) {
28
+ throw new Error(
29
+ `Failed to fetch integration for ${configPath}, HTTP error! status: ${response.status} ${response.text} ${response.statusText}`
30
+ );
31
+ }
32
+
33
+ const data = await response.json();
34
+ if (data.length > 0) {
35
+ const inst: any = data[0].config;
36
+ if (inst.type == 'custom' && isString(inst.parameter)) {
37
+ inst.parameter = new Map(Object.entries(JSON.parse(inst.parameter)));
38
+ }
39
+ Integrations.set(configName, inst);
40
+ } else {
41
+ throw new Error(`Integration not found for ${configPath}`);
42
+ }
43
+ }
44
+ }
45
+ }
46
+
47
+ async function loginToIntegManager(
48
+ host: string,
49
+ username?: string,
50
+ password?: string
51
+ ): Promise<any> {
52
+ const defaultHdr = { 'Content-Type': 'application/json' };
53
+ if (username && password && username.length > 0) {
54
+ const apiUrl = `${host}/agentlang_auth/login`;
55
+ const data = { email: username, password: password };
56
+ const response = await fetch(apiUrl, {
57
+ method: 'POST',
58
+ headers: defaultHdr,
59
+ body: JSON.stringify(data),
60
+ });
61
+
62
+ if (!response.ok) {
63
+ throw new Error(
64
+ `Failed to login to integration-manager. HTTP error! status: ${response.status}`
65
+ );
66
+ }
67
+
68
+ const responseData = await response.json();
69
+ return {
70
+ Authorization: `Bearer ${responseData.id_token}`,
71
+ 'Content-Type': 'application/json',
72
+ };
73
+ } else {
74
+ return defaultHdr;
75
+ }
76
+ }
77
+
78
+ function mkApiUrl(integManagerHost: string, configPath: string): string {
79
+ const parts = configPath.split('/');
80
+ const integId = parts[0];
81
+ const configId = parts[1];
82
+ return `${integManagerHost}/${IntegManagerModel}/integration/${integId}/integrationConfig/config/${configId}`;
83
+ }
84
+
85
+ export function getIntegrationConfig(name: string, configName: string): any {
86
+ const config: any = Integrations.get(name);
87
+ if (config) {
88
+ return config.parameter.get(configName);
89
+ } else {
90
+ return undefined;
91
+ }
92
+ }
@@ -13,6 +13,7 @@ import {
13
13
  isLiteral,
14
14
  isNegExpr,
15
15
  isNotExpr,
16
+ isReturn,
16
17
  Literal,
17
18
  MapKey,
18
19
  MapLiteral,
@@ -607,27 +608,28 @@ function statemtentString(stmt: Statement): string {
607
608
  }
608
609
  }
609
610
 
611
+ async function saveSuspension(cont: Statement[], env: Environment) {
612
+ if (cont.length > 0) {
613
+ const suspId = await createSuspension(
614
+ env.getSuspensionId(),
615
+ cont.map((stmt: Statement) => {
616
+ return statemtentString(stmt);
617
+ }),
618
+ env
619
+ );
620
+ env.setLastResult({ suspension: suspId || 'null' });
621
+ }
622
+ }
623
+
610
624
  export async function evaluateStatements(
611
625
  stmts: Statement[],
612
626
  env: Environment,
613
627
  continuation?: Function
614
628
  ) {
615
629
  for (let i = 0; i < stmts.length; ++i) {
616
- await evaluateStatement(stmts[i], env);
617
- if (env.isSuspended()) {
618
- const cont = stmts.slice(i + 1, stmts.length);
619
- if (cont.length > 0) {
620
- const suspId = await createSuspension(
621
- env.getSuspensionId(),
622
- cont.map((stmt: Statement) => {
623
- return statemtentString(stmt);
624
- }),
625
- env
626
- );
627
- env.setLastResult({ suspension: suspId || 'null' });
628
- break;
629
- }
630
- } else if (env.isMarkedForReturn()) {
630
+ const stmt = stmts[i];
631
+ await evaluateStatement(stmt, env);
632
+ if (env.isMarkedForReturn()) {
631
633
  break;
632
634
  }
633
635
  }
@@ -636,10 +638,44 @@ export async function evaluateStatements(
636
638
  }
637
639
  }
638
640
 
641
+ async function evaluateAsyncPattern(
642
+ pat: Pattern,
643
+ thenStmts: Statement[],
644
+ handlers: CatchHandlers | undefined,
645
+ hints: RuntimeHint[],
646
+ env: Environment
647
+ ): Promise<void> {
648
+ try {
649
+ await evaluatePattern(pat, env);
650
+ maybeBindStatementResultToAlias(hints, env);
651
+ if (env.isSuspended()) {
652
+ await saveSuspension(thenStmts, env);
653
+ } else {
654
+ await evaluateStatements(thenStmts, env);
655
+ }
656
+ } catch (reason: any) {
657
+ await maybeHandleError(handlers, reason, env);
658
+ }
659
+ }
660
+
639
661
  async function evaluateStatement(stmt: Statement, env: Environment): Promise<void> {
640
662
  const hints = stmt.hints;
641
663
  const hasHints = hints && hints.length > 0;
664
+ const thenStmts: Statement[] | undefined = hasHints ? maybeFindThenStatements(hints) : undefined;
642
665
  const handlers: CatchHandlers | undefined = hasHints ? maybeFindHandlers(hints) : undefined;
666
+ if (thenStmts) {
667
+ evaluateAsyncPattern(
668
+ stmt.pattern,
669
+ thenStmts,
670
+ handlers,
671
+ hints,
672
+ new Environment(env.name + 'async', env)
673
+ );
674
+ if (isReturn(stmt.pattern)) {
675
+ env.markForReturn();
676
+ }
677
+ return;
678
+ }
643
679
  let handlersPushed = false;
644
680
  try {
645
681
  if (handlers) {
@@ -649,24 +685,9 @@ async function evaluateStatement(stmt: Statement, env: Environment): Promise<voi
649
685
  if (hasHints) {
650
686
  maybeBindStatementResultToAlias(hints, env);
651
687
  }
652
- const lastResult: Result = env.getLastResult();
653
- if (
654
- lastResult == null ||
655
- lastResult == undefined ||
656
- (lastResult instanceof Array && lastResult.length == 0)
657
- ) {
658
- const onNotFound = handlers ? handlers.get('not_found') : undefined;
659
- if (onNotFound) {
660
- await evaluateStatement(onNotFound, env);
661
- }
662
- }
688
+ await maybeHandleNotFound(handlers, env);
663
689
  } catch (reason: any) {
664
- const handler = handlers ? handlers.get('error') : undefined;
665
- if (handler) {
666
- await evaluateStatement(handler, env);
667
- } else {
668
- throw reason;
669
- }
690
+ await maybeHandleError(handlers, reason, env);
670
691
  } finally {
671
692
  if (handlersPushed && env.hasHandlers()) {
672
693
  env.popHandlers();
@@ -674,6 +695,33 @@ async function evaluateStatement(stmt: Statement, env: Environment): Promise<voi
674
695
  }
675
696
  }
676
697
 
698
+ async function maybeHandleNotFound(handlers: CatchHandlers | undefined, env: Environment) {
699
+ const lastResult: Result = env.getLastResult();
700
+ if (
701
+ lastResult == null ||
702
+ lastResult == undefined ||
703
+ (lastResult instanceof Array && lastResult.length == 0)
704
+ ) {
705
+ const onNotFound = handlers ? handlers.get('not_found') : undefined;
706
+ if (onNotFound) {
707
+ await evaluateStatement(onNotFound, env);
708
+ }
709
+ }
710
+ }
711
+
712
+ async function maybeHandleError(
713
+ handlers: CatchHandlers | undefined,
714
+ reason: any,
715
+ env: Environment
716
+ ) {
717
+ const handler = handlers ? handlers.get('error') : undefined;
718
+ if (handler) {
719
+ await evaluateStatement(handler, env);
720
+ } else {
721
+ throw reason;
722
+ }
723
+ }
724
+
677
725
  function maybeBindStatementResultToAlias(hints: RuntimeHint[], env: Environment) {
678
726
  for (let i = 0; i < hints.length; ++i) {
679
727
  const rh = hints[i];
@@ -720,6 +768,16 @@ function maybeFindHandlers(hints: RuntimeHint[]): Map<string, Statement> | undef
720
768
  return undefined;
721
769
  }
722
770
 
771
+ function maybeFindThenStatements(hints: RuntimeHint[]): Statement[] | undefined {
772
+ for (let i = 0; i < hints.length; ++i) {
773
+ const rh = hints[i];
774
+ if (rh.thenSpec) {
775
+ return rh.thenSpec.statements;
776
+ }
777
+ }
778
+ return undefined;
779
+ }
780
+
723
781
  export async function parseAndEvaluateStatement(
724
782
  stmtString: string,
725
783
  activeUserId?: string,
@@ -1237,9 +1295,11 @@ async function walkJoinQueryPattern(
1237
1295
  async function handleAgentInvocation(agentEventInst: Instance, env: Environment): Promise<void> {
1238
1296
  const agent: AgentInstance = await findAgentByName(agentEventInst.name, env);
1239
1297
  await agent.invoke(agentEventInst.lookup('message'), env);
1240
- const result: string | undefined = cleanupAgentResponse(env.getLastResult());
1298
+ const r: string | undefined = env.getLastResult();
1299
+ const isPlanner = agent.isPlanner();
1300
+ const result: string | undefined = isPlanner ? cleanupAgentResponse(r) : r;
1241
1301
  if (result) {
1242
- if (agent.isPlanner()) {
1302
+ if (isPlanner) {
1243
1303
  logger.debug(`Agent ${agent.name} generated pattern: ${result}`);
1244
1304
  try {
1245
1305
  let rs = result.trim();
@@ -1310,11 +1370,13 @@ async function evaluateForEach(forEach: ForEach, env: Environment): Promise<void
1310
1370
  const src: Result = env.getLastResult();
1311
1371
  if (src instanceof Array && src.length > 0) {
1312
1372
  const loopEnv: Environment = Environment.from(env);
1373
+ const finalResult = new Array<any>();
1313
1374
  for (let i = 0; i < src.length; ++i) {
1314
1375
  loopEnv.bind(loopVar, src[i]);
1315
1376
  await evaluateStatements(forEach.statements, loopEnv);
1377
+ finalResult.push(loopEnv.getLastResult());
1316
1378
  }
1317
- env.setLastResult(loopEnv.getLastResult());
1379
+ env.setLastResult(finalResult);
1318
1380
  } else {
1319
1381
  env.setLastResult(EmptyResult);
1320
1382
  }
@@ -421,7 +421,7 @@ async function addAgentDefinition(def: AgentDefinition, moduleName: string) {
421
421
  v = apdef.value.array.vals
422
422
  .map((stmt: Statement) => {
423
423
  if (stmt.pattern.expr && isLiteral(stmt.pattern.expr)) {
424
- const s = stmt.pattern.expr.str || stmt.pattern.expr.id;
424
+ const s = stmt.pattern.expr.str || stmt.pattern.expr.id || stmt.pattern.expr.ref;
425
425
  if (s == undefined) {
426
426
  throw new Error(
427
427
  `Only arrays of string-literals or identifiers should be passed to agent ${name}`
@@ -434,7 +434,7 @@ async function addAgentDefinition(def: AgentDefinition, moduleName: string) {
434
434
  })
435
435
  .join(',');
436
436
  } else {
437
- v = apdef.value.str || apdef.value.id || apdef.value.num;
437
+ v = apdef.value.str || apdef.value.id || apdef.value.ref || apdef.value.num;
438
438
  if (v == undefined) {
439
439
  v = apdef.value.bool;
440
440
  }
@@ -2206,14 +2206,27 @@ export class Instance {
2206
2206
  return obj;
2207
2207
  }
2208
2208
 
2209
+ static isSerializableObject(obj: any): boolean {
2210
+ return obj instanceof Object && obj.AL_INSTANCE == true;
2211
+ }
2212
+
2213
+ static DeserializeAttributes(attrs: InstanceAttributes): InstanceAttributes {
2214
+ attrs.forEach((v: any, k: string) => {
2215
+ if (Instance.isSerializableObject(v)) {
2216
+ attrs.set(k, Instance.FromSerializableObject(v));
2217
+ }
2218
+ });
2219
+ return attrs;
2220
+ }
2221
+
2209
2222
  static FromSerializableObject(obj: any, record?: Record): Instance {
2210
- if (obj.AL_INSTANCE == true) {
2223
+ if (Instance.isSerializableObject(obj)) {
2211
2224
  const m = fetchModule(obj.moduleName);
2212
2225
  return new Instance(
2213
2226
  record || (m.getEntry(obj.name) as Record),
2214
2227
  obj.moduleName,
2215
2228
  obj.name,
2216
- new Map(Object.entries(obj.attributes)),
2229
+ Instance.DeserializeAttributes(new Map(Object.entries(obj.attributes))),
2217
2230
  new Map(Object.entries(obj.queryAttributes)),
2218
2231
  new Map(Object.entries(obj.queryAttributeValues))
2219
2232
  );
@@ -239,7 +239,7 @@ export async function resetDefaultDatabase() {
239
239
  }
240
240
 
241
241
  function ownersTable(tableName: string): string {
242
- return (tableName + OwnersSuffix).toLowerCase();
242
+ return (tableName.replace('.', '_') + OwnersSuffix).toLowerCase();
243
243
  }
244
244
 
245
245
  async function insertRowsHelper(
@@ -31,13 +31,14 @@ export type TableSchema = {
31
31
  };
32
32
 
33
33
  export function asTableReference(moduleName: string, ref: string): string {
34
+ const modName = moduleName.replace('.', '_')
34
35
  if (ref.indexOf('.') > 0) {
35
36
  const parts = ref.split('.')
36
- const r = `${moduleName}_${parts[0]}`.toLowerCase()
37
+ const r = `${modName}_${parts[0]}`.toLowerCase()
37
38
  const colref = parts.slice(1).join('.')
38
39
  return `"${r}"."${colref}"`;
39
40
  } else {
40
- return `${moduleName}_${ref}`.toLowerCase()
41
+ return `${modName}_${ref}`.toLowerCase()
41
42
  }
42
43
  }
43
44
 
@@ -33,6 +33,14 @@ export const ConfigSchema = z.object({
33
33
  }),
34
34
  ])
35
35
  .optional(),
36
+ integrations: z
37
+ .object({
38
+ host: z.string(),
39
+ username: z.string().optional(),
40
+ password: z.string().optional(),
41
+ connections: z.record(z.string(), z.string()),
42
+ })
43
+ .optional(),
36
44
  graphql: z
37
45
  .object({
38
46
  enabled: z.boolean().default(false),
@@ -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','@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','@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
  '*','+',',','-','.','/',':',';','<','<=','<>','=','>','>=','?','@'