agentlang 0.0.4 → 0.0.6

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 (87) hide show
  1. package/out/api/http.js +27 -19
  2. package/out/api/http.js.map +1 -1
  3. package/out/language/generated/ast.d.ts +27 -10
  4. package/out/language/generated/ast.d.ts.map +1 -1
  5. package/out/language/generated/ast.js +27 -2
  6. package/out/language/generated/ast.js.map +1 -1
  7. package/out/language/generated/grammar.d.ts.map +1 -1
  8. package/out/language/generated/grammar.js +213 -111
  9. package/out/language/generated/grammar.js.map +1 -1
  10. package/out/language/main.cjs +234 -113
  11. package/out/language/main.cjs.map +2 -2
  12. package/out/language/parser.d.ts.map +1 -1
  13. package/out/language/parser.js +21 -5
  14. package/out/language/parser.js.map +1 -1
  15. package/out/language/syntax.d.ts +8 -2
  16. package/out/language/syntax.d.ts.map +1 -1
  17. package/out/language/syntax.js +42 -2
  18. package/out/language/syntax.js.map +1 -1
  19. package/out/runtime/agents/common.d.ts +1 -1
  20. package/out/runtime/agents/common.d.ts.map +1 -1
  21. package/out/runtime/agents/common.js +48 -0
  22. package/out/runtime/agents/common.js.map +1 -1
  23. package/out/runtime/agents/impl/openai.js +1 -1
  24. package/out/runtime/agents/impl/openai.js.map +1 -1
  25. package/out/runtime/auth/cognito.d.ts +2 -0
  26. package/out/runtime/auth/cognito.d.ts.map +1 -1
  27. package/out/runtime/auth/cognito.js +115 -15
  28. package/out/runtime/auth/cognito.js.map +1 -1
  29. package/out/runtime/auth/interface.d.ts +2 -0
  30. package/out/runtime/auth/interface.d.ts.map +1 -1
  31. package/out/runtime/interpreter.d.ts.map +1 -1
  32. package/out/runtime/interpreter.js +64 -16
  33. package/out/runtime/interpreter.js.map +1 -1
  34. package/out/runtime/jsmodules.d.ts +6 -0
  35. package/out/runtime/jsmodules.d.ts.map +1 -0
  36. package/out/runtime/jsmodules.js +138 -0
  37. package/out/runtime/jsmodules.js.map +1 -0
  38. package/out/runtime/loader.d.ts.map +1 -1
  39. package/out/runtime/loader.js +32 -16
  40. package/out/runtime/loader.js.map +1 -1
  41. package/out/runtime/module.d.ts +15 -1
  42. package/out/runtime/module.d.ts.map +1 -1
  43. package/out/runtime/module.js +110 -17
  44. package/out/runtime/module.js.map +1 -1
  45. package/out/runtime/modules/ai.d.ts +1 -0
  46. package/out/runtime/modules/ai.d.ts.map +1 -1
  47. package/out/runtime/modules/ai.js +20 -11
  48. package/out/runtime/modules/ai.js.map +1 -1
  49. package/out/runtime/modules/auth.d.ts +7 -3
  50. package/out/runtime/modules/auth.d.ts.map +1 -1
  51. package/out/runtime/modules/auth.js +142 -10
  52. package/out/runtime/modules/auth.js.map +1 -1
  53. package/out/runtime/resolvers/interface.d.ts +0 -1
  54. package/out/runtime/resolvers/interface.d.ts.map +1 -1
  55. package/out/runtime/resolvers/interface.js.map +1 -1
  56. package/out/runtime/resolvers/sqldb/database.d.ts +4 -2
  57. package/out/runtime/resolvers/sqldb/database.d.ts.map +1 -1
  58. package/out/runtime/resolvers/sqldb/database.js +43 -4
  59. package/out/runtime/resolvers/sqldb/database.js.map +1 -1
  60. package/out/runtime/resolvers/sqldb/impl.d.ts.map +1 -1
  61. package/out/runtime/resolvers/sqldb/impl.js +16 -6
  62. package/out/runtime/resolvers/sqldb/impl.js.map +1 -1
  63. package/out/runtime/util.d.ts +1 -4
  64. package/out/runtime/util.d.ts.map +1 -1
  65. package/out/runtime/util.js +11 -78
  66. package/out/runtime/util.js.map +1 -1
  67. package/package.json +1 -1
  68. package/src/api/http.ts +26 -17
  69. package/src/language/agentlang.langium +8 -5
  70. package/src/language/generated/ast.ts +56 -12
  71. package/src/language/generated/grammar.ts +213 -111
  72. package/src/language/parser.ts +24 -5
  73. package/src/language/syntax.ts +50 -5
  74. package/src/runtime/agents/common.ts +48 -0
  75. package/src/runtime/agents/impl/openai.ts +1 -1
  76. package/src/runtime/auth/cognito.ts +152 -22
  77. package/src/runtime/auth/interface.ts +7 -0
  78. package/src/runtime/interpreter.ts +63 -18
  79. package/src/runtime/jsmodules.ts +123 -0
  80. package/src/runtime/loader.ts +31 -17
  81. package/src/runtime/module.ts +127 -18
  82. package/src/runtime/modules/ai.ts +22 -14
  83. package/src/runtime/modules/auth.ts +169 -10
  84. package/src/runtime/resolvers/interface.ts +0 -1
  85. package/src/runtime/resolvers/sqldb/database.ts +55 -4
  86. package/src/runtime/resolvers/sqldb/impl.ts +16 -10
  87. package/src/runtime/util.ts +12 -70
@@ -8,6 +8,7 @@ import {
8
8
  Group,
9
9
  Handler,
10
10
  If,
11
+ isExpr,
11
12
  isGroup,
12
13
  isLiteral,
13
14
  isNegExpr,
@@ -21,6 +22,8 @@ import {
21
22
  Pattern,
22
23
  PrimExpr,
23
24
  RelationshipPattern,
25
+ SelectIntoEntry,
26
+ SelectIntoSpec,
24
27
  SetAttribute,
25
28
  Statement,
26
29
  WorkflowDefinition,
@@ -91,7 +94,7 @@ export async function parseWorkflow(workflowDef: string): Promise<WorkflowDefini
91
94
  if (isWorkflowDefinition(mod.defs[0])) {
92
95
  return mod.defs[0] as WorkflowDefinition;
93
96
  } else {
94
- throw new Error(`Failed to generated workflow from ${workflowDef}`);
97
+ throw new Error(`Failed to generate workflow from ${workflowDef}`);
95
98
  }
96
99
  }
97
100
 
@@ -172,8 +175,11 @@ function introspectPattern(pat: Pattern): BasePattern {
172
175
  } else {
173
176
  r = introspectCreatePattern(pat.crudMap);
174
177
  }
175
- } else if (pat.literal) {
176
- r = introspectLiteral(pat.literal);
178
+ if (pat.crudMap.into) {
179
+ r = introspectInto(pat.crudMap.into, r as CrudPattern);
180
+ }
181
+ } else if (pat.expr) {
182
+ r = introspectExpression(pat.expr);
177
183
  } else if (pat.forEach) {
178
184
  r = introspectForEach(pat.forEach);
179
185
  } else if (pat.if) {
@@ -187,6 +193,13 @@ function introspectPattern(pat: Pattern): BasePattern {
187
193
  }
188
194
  }
189
195
 
196
+ function introspectInto(intoSpec: SelectIntoSpec, p: CrudPattern): CrudPattern {
197
+ intoSpec.entries.forEach((se: SelectIntoEntry) => {
198
+ p.addInto(se.alias, se.attribute);
199
+ });
200
+ return p;
201
+ }
202
+
190
203
  function isQueryPattern(pat: Pattern): boolean {
191
204
  if (pat.crudMap) {
192
205
  const crudMap: CrudMap = pat.crudMap;
@@ -250,6 +263,7 @@ function introspectQueryPattern(crudMap: CrudMap): CrudPattern {
250
263
  crudMap.relationships.forEach((rp: RelationshipPattern) => {
251
264
  cp.addRelationship(rp.name, introspectPattern(rp.pattern) as CrudPattern | CrudPattern[]);
252
265
  });
266
+ cp.isCreate = false;
253
267
  cp.isQuery = true;
254
268
  return cp;
255
269
  }
@@ -259,6 +273,7 @@ function introspectQueryPattern(crudMap: CrudMap): CrudPattern {
259
273
  function introspectCreatePattern(crudMap: CrudMap): CrudPattern {
260
274
  if (crudMap) {
261
275
  const cp: CrudPattern = new CrudPattern(crudMap.name);
276
+ cp.isCreate = false;
262
277
  crudMap.body?.attributes.forEach((sa: SetAttribute) => {
263
278
  if (!cp.isQueryUpdate && sa.name.endsWith(QuerySuffix)) {
264
279
  cp.isQueryUpdate = true;
@@ -290,8 +305,12 @@ function introspectLiteral(lit: Literal): BasePattern {
290
305
  } else if (lit.fnCall) {
291
306
  return new FunctionCallPattern(
292
307
  lit.fnCall.name,
293
- lit.fnCall.args.map((v: Literal) => {
294
- return introspectLiteral(v);
308
+ lit.fnCall.args.map((v: Literal | Expr) => {
309
+ if (isExpr(v)) {
310
+ return introspectExpression(v);
311
+ } else {
312
+ return introspectLiteral(v);
313
+ }
295
314
  })
296
315
  );
297
316
  } else if (lit.array) {
@@ -344,6 +344,7 @@ export class CrudPattern extends BasePattern {
344
344
  recordName: string;
345
345
  attributes: Array<AttributePattern>;
346
346
  relationships: Map<string, CrudPattern[] | CrudPattern> | undefined;
347
+ into: Map<string, string> | undefined;
347
348
  isQuery: boolean = false;
348
349
  isQueryUpdate: boolean = false;
349
350
  isCreate: boolean = false;
@@ -359,7 +360,7 @@ export class CrudPattern extends BasePattern {
359
360
  }
360
361
  }
361
362
 
362
- addAttribute(n: string, p: BasePattern, op?: string) {
363
+ addAttribute(n: string, p: BasePattern, op?: string): CrudPattern {
363
364
  this.attributes.push({ name: n, op: op, value: p });
364
365
  if (this.recordName.endsWith('?')) {
365
366
  this.recordName = this.recordName.substring(0, this.recordName.length - 1);
@@ -368,7 +369,7 @@ export class CrudPattern extends BasePattern {
368
369
  return this;
369
370
  }
370
371
 
371
- removeAttribute(n: string) {
372
+ removeAttribute(n: string): CrudPattern {
372
373
  const idx: number = this.attributes.findIndex((ap: AttributePattern) => {
373
374
  return n == ap.name;
374
375
  });
@@ -379,6 +380,34 @@ export class CrudPattern extends BasePattern {
379
380
  return this;
380
381
  }
381
382
 
383
+ addInto(alias: string, attr: string): CrudPattern {
384
+ if (this.into == undefined) {
385
+ this.into = new Map();
386
+ }
387
+ this.into.set(alias, attr);
388
+ return this;
389
+ }
390
+
391
+ removeInto(alias: string): CrudPattern {
392
+ if (this.into) {
393
+ this.into.delete(alias);
394
+ }
395
+ return this;
396
+ }
397
+
398
+ resetInto(into?: Map<string, string>): CrudPattern {
399
+ this.into = into;
400
+ return this;
401
+ }
402
+
403
+ hasInto(): boolean {
404
+ if (this.into && this.into.size > 0) {
405
+ return true;
406
+ } else {
407
+ return false;
408
+ }
409
+ }
410
+
382
411
  private flagType() {
383
412
  let hasq = false;
384
413
  let hasc = false;
@@ -421,7 +450,7 @@ export class CrudPattern extends BasePattern {
421
450
  return `{${s}}`;
422
451
  }
423
452
 
424
- private relationshipsAsString(): string {
453
+ private relationshipsAsString(): string | undefined {
425
454
  if (this.relationships != undefined) {
426
455
  const result: Array<string> = [];
427
456
  this.relationships.forEach((p: CrudPattern | CrudPattern[], n: string) => {
@@ -430,7 +459,7 @@ export class CrudPattern extends BasePattern {
430
459
  });
431
460
  return result.join(',');
432
461
  } else {
433
- return '';
462
+ return undefined;
434
463
  }
435
464
  }
436
465
 
@@ -438,12 +467,27 @@ export class CrudPattern extends BasePattern {
438
467
  return escapeQueryName(this.recordName);
439
468
  }
440
469
 
470
+ private intoAsString(): string | undefined {
471
+ if (this.into) {
472
+ const ss = new Array<string>();
473
+ this.into.forEach((attr: string, alias: string) => {
474
+ ss.push(`${alias} ${attr}`);
475
+ });
476
+ return `into { ${ss.join(',\n')} }`;
477
+ }
478
+ return undefined;
479
+ }
480
+
441
481
  override toString(): string {
442
482
  let s = `{${this.recordName} ${this.attributesAsString()}`;
443
483
  const rs = this.relationshipsAsString();
444
- if (rs.length > 0) {
484
+ if (rs) {
445
485
  s = s.concat(`,${rs}`);
446
486
  }
487
+ const ins = this.intoAsString();
488
+ if (ins) {
489
+ s = s.concat(`,${ins}`);
490
+ }
447
491
  return s.concat('}', this.hintsAsString());
448
492
  }
449
493
  }
@@ -603,6 +647,7 @@ export function newCreatePattern(recName: string): CrudPattern {
603
647
  export function newQueryPattern(recName: string, forQueryUpdate: boolean = false): CrudPattern {
604
648
  recName = recName.charAt(recName.length - 1) == '?' ? recName : recName + '?';
605
649
  const cp: CrudPattern = new CrudPattern(recName);
650
+ cp.isCreate = false;
606
651
  if (forQueryUpdate) {
607
652
  cp.isQueryUpdate = true;
608
653
  } else {
@@ -15,6 +15,16 @@ entity Employee {
15
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
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
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).
18
+
19
+ This is an example of a record:
20
+
21
+ record EmailMessage {
22
+ to Email,
23
+ from Email,
24
+ subject String,
25
+ body String
26
+ }
27
+
18
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:
19
29
 
20
30
  workflow CreateEmployee {
@@ -113,6 +123,17 @@ for emp in employees {
113
123
  {Erp/SendMail {email emp.email, body "You are selected for an increment!"}}
114
124
  } as emails
115
125
 
126
+ Make sure all references based on a preceding pattern is based either on an actual alias or the name of the workflow. For example, the following sequence of patterns
127
+ are invalid, because the alias 'employee' is not defined:
128
+
129
+ {Employee {id? 101}};
130
+ {SendEmail {to employee.email, body "hello"}}
131
+
132
+ A fix for the reference-error is shown below:
133
+
134
+ {Employee {id? 101}} as employee;
135
+ {SendEmail {to employee.email, body "hello"}}
136
+
116
137
  Entities in a module can be connected together in relationships. There are two types of relationships - 'contains' and 'between'.
117
138
  'Contains' relationship is for hierarchical data, as in a Library entity containing Books. 'Between' relationship is for graph-like data,
118
139
  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),
@@ -172,6 +193,33 @@ workflow GetEmployeeTaskAssignments {
172
193
  Erp/EmployeeTaskAssignment {Erp/TaskAssignment? {}}}
173
194
  }
174
195
 
196
+ A general rule regarding generating workflows - as much as possible, do not include references to the workflow event in the patterns. Try to
197
+ fill-in values from the available context. For example, if your instruction is "create a workflow to send an email to employee 101 with this message -
198
+ 'please call me as soon as possible'", the best workflow to return is:
199
+
200
+ workflow sendEmail {
201
+ {employee {id? 101}} as emp;
202
+ {email {to emp.email body "please call me as soon as possible"}}
203
+ }
204
+
205
+ because all the information needed is available in the context. If the instruction is "create a workflow to send an email by employee-id with this message -
206
+ 'please call me as soon as possible'", then you can return:
207
+
208
+ workflow sendEmail {
209
+ {employee {id? sendEmail.employeeId}} as emp;
210
+ {email {to emp.email body "please call me as soon as possible"}}
211
+ }
212
+
213
+ The point is use the immediate context to fill-in values in generated patterns, as much as possible.
214
+
215
+ Also generate a workflow only if required explicitly by the user or the contextual information is incomplete. Otherwise, just return an array of patterns.
216
+ As an example, if the user request is "send an email to employee 101 with this message - 'please call me as soon as possible'", you must return:
217
+
218
+ [{employee {id? 101}} as emp;
219
+ {email {to emp.email, body "please call me as soon as possible"}}]
220
+
221
+ Note that each pattern in the array is separated by a ; and not a comma(,).
222
+
175
223
  Now consider the following module definition and generate appropriate patterns in response to the user instructions. You must return only valid patterns or workflows,
176
224
  no other descriptive text or comments are needed.
177
225
  `;
@@ -6,7 +6,7 @@ export class OpenAIProvider implements AgentServiceProvider {
6
6
  private model: ChatOpenAI;
7
7
 
8
8
  constructor(config?: Map<string, any>) {
9
- let modelName = 'gpt-4';
9
+ let modelName = 'gpt-4.1-2025-04-14';
10
10
  if (config) {
11
11
  modelName = config.get('model') || modelName;
12
12
  }
@@ -6,14 +6,7 @@ import {
6
6
  SignUpCallback,
7
7
  UserInfo,
8
8
  } from './interface.js';
9
- import {
10
- ensureUser,
11
- ensureUserSession,
12
- findUser,
13
- findUserByEmail,
14
- findUserSession,
15
- removeSession,
16
- } from '../modules/auth.js';
9
+ import { ensureUser, ensureUserSession, findUser, findUserByEmail } from '../modules/auth.js';
17
10
  import { logger } from '../logger.js';
18
11
  import { sleepMilliseconds } from '../util.js';
19
12
  import { Instance } from '../module.js';
@@ -36,9 +29,14 @@ let fromEnv: any = undefined;
36
29
  let CognitoIdentityProviderClient: any = undefined;
37
30
  let SignUpCommand: any = undefined;
38
31
  let AdminGetUserCommand: any = undefined;
32
+ let InitiateAuthCommand: any = undefined;
39
33
  let AuthenticationDetails: any = undefined;
40
34
  let CognitoUser: any = undefined;
41
35
  let CognitoUserPool: any = undefined;
36
+ let CognitoUserSession: any = undefined;
37
+ let CognitoIdToken: any = undefined;
38
+ let CognitoAccessToken: any = undefined;
39
+ let CognitoRefreshToken: any = undefined;
42
40
 
43
41
  if (isNodeEnv) {
44
42
  const cp = await import('@aws-sdk/credential-providers');
@@ -48,11 +46,16 @@ if (isNodeEnv) {
48
46
  CognitoIdentityProviderClient = cip.CognitoIdentityProviderClient;
49
47
  SignUpCommand = cip.SignUpCommand;
50
48
  AdminGetUserCommand = cip.AdminGetUserCommand;
49
+ InitiateAuthCommand = cip.InitiateAuthCommand;
51
50
 
52
51
  const ci = await import('amazon-cognito-identity-js');
53
52
  AuthenticationDetails = ci.AuthenticationDetails;
54
53
  CognitoUser = ci.CognitoUser;
55
54
  CognitoUserPool = ci.CognitoUserPool;
55
+ CognitoUserSession = ci.CognitoUserSession;
56
+ CognitoIdToken = ci.CognitoIdToken;
57
+ CognitoAccessToken = ci.CognitoAccessToken;
58
+ CognitoRefreshToken = ci.CognitoRefreshToken;
56
59
  }
57
60
 
58
61
  const defaultConfig = isNodeEnv
@@ -441,7 +444,13 @@ export class CognitoAuth implements AgentlangAuth {
441
444
  const idToken = result.getIdToken().getJwtToken();
442
445
  const accessToken = result.getAccessToken().getJwtToken();
443
446
  const refreshToken = result.getRefreshToken().getToken();
444
- const localSess: Instance = await ensureUserSession(userid, idToken, env);
447
+ const localSess: Instance = await ensureUserSession(
448
+ userid,
449
+ idToken,
450
+ accessToken,
451
+ refreshToken,
452
+ env
453
+ );
445
454
  const sessInfo: SessionInfo = {
446
455
  sessionId: localSess.lookup('id'),
447
456
  userId: userid,
@@ -513,7 +522,13 @@ export class CognitoAuth implements AgentlangAuth {
513
522
  const idToken = result.getIdToken().getJwtToken();
514
523
  const accessToken = result.getAccessToken().getJwtToken();
515
524
  const refreshToken = result.getRefreshToken().getToken();
516
- const localSess: Instance = await ensureUserSession(userid, idToken, env);
525
+ const localSess: Instance = await ensureUserSession(
526
+ userid,
527
+ idToken,
528
+ accessToken,
529
+ refreshToken,
530
+ env
531
+ );
517
532
  const sessInfo: SessionInfo = {
518
533
  sessionId: localSess.lookup('id'),
519
534
  userId: userid,
@@ -540,25 +555,33 @@ export class CognitoAuth implements AgentlangAuth {
540
555
  return;
541
556
  }
542
557
  const user = new CognitoUser({
543
- Username: localUser.email,
558
+ Username: localUser.lookup('email'),
544
559
  Pool: this.fetchUserPool(),
545
560
  });
561
+
546
562
  let done = false;
547
563
  let logoutError: any;
548
- user.signOut(() => {
549
- done = true;
564
+
565
+ const session = new CognitoUserSession({
566
+ IdToken: new CognitoIdToken({ IdToken: sessionInfo.idToken }),
567
+ AccessToken: new CognitoAccessToken({ AccessToken: sessionInfo.accessToken }),
568
+ RefreshToken: new CognitoRefreshToken({ RefreshToken: sessionInfo.refreshToken }),
550
569
  });
551
- // Add error handling for signOut
552
- user.signOut((err: any) => {
553
- if (err) {
570
+ user.setSignInUserSession(session);
571
+ user.globalSignOut({
572
+ onSuccess: function () {
573
+ done = true;
574
+ },
575
+ onFailure: function (err: any) {
576
+ done = true;
554
577
  logger.error(`Cognito signOut error for user ${sessionInfo.userId}:`, {
555
578
  errorName: err.name,
556
579
  errorMessage: sanitizeErrorMessage(err.message),
557
580
  });
558
581
  logoutError = err;
559
- }
560
- done = true;
582
+ },
561
583
  });
584
+
562
585
  while (!done) {
563
586
  await sleepMilliseconds(100);
564
587
  }
@@ -568,10 +591,6 @@ export class CognitoAuth implements AgentlangAuth {
568
591
  );
569
592
  // Continue with local session cleanup even if Cognito logout fails
570
593
  }
571
- const sess = await findUserSession(localUser.id, env);
572
- if (sess) {
573
- await removeSession(sess.id, env);
574
- }
575
594
  logger.debug(`Successfully logged out user ${sessionInfo.userId}`);
576
595
  if (cb) cb(true);
577
596
  } catch (err: any) {
@@ -581,6 +600,50 @@ export class CognitoAuth implements AgentlangAuth {
581
600
  }
582
601
  }
583
602
 
603
+ async changePassword(
604
+ sessionInfo: SessionInfo,
605
+ newPassword: string,
606
+ oldPassword: string,
607
+ env: Environment
608
+ ): Promise<boolean> {
609
+ const localUser = await findUser(sessionInfo.userId, env);
610
+ if (!localUser) {
611
+ logger.warn(`User ${sessionInfo.userId} not found for password-change`);
612
+ return false;
613
+ }
614
+ const email = localUser.lookup('email');
615
+ const user = new CognitoUser({
616
+ Username: email,
617
+ Pool: this.fetchUserPool(),
618
+ });
619
+ const session = new CognitoUserSession({
620
+ IdToken: new CognitoIdToken({ IdToken: sessionInfo.idToken }),
621
+ AccessToken: new CognitoAccessToken({ AccessToken: sessionInfo.accessToken }),
622
+ RefreshToken: new CognitoRefreshToken({ RefreshToken: sessionInfo.refreshToken }),
623
+ });
624
+ user.setSignInUserSession(session);
625
+ let done = false;
626
+ let cpErr: any = undefined;
627
+ user.changePassword(oldPassword, newPassword, (err: any, _: any) => {
628
+ if (err) {
629
+ done = true;
630
+ cpErr = err;
631
+ } else {
632
+ done = true;
633
+ }
634
+ });
635
+
636
+ while (!done) {
637
+ await sleepMilliseconds(100);
638
+ }
639
+
640
+ if (cpErr) {
641
+ logger.warn(`Failed to change the password for ${email} - ${cpErr.message}`);
642
+ return false;
643
+ }
644
+ return true;
645
+ }
646
+
584
647
  private fetchUserPool() {
585
648
  if (this.userPool) {
586
649
  return this.userPool;
@@ -753,4 +816,71 @@ export class CognitoAuth implements AgentlangAuth {
753
816
  };
754
817
  }
755
818
  }
819
+
820
+ async refreshToken(refreshTokenString: string, env: Environment): Promise<SessionInfo> {
821
+ try {
822
+ // Use InitiateAuth with REFRESH_TOKEN_AUTH flow
823
+ const client = new CognitoIdentityProviderClient({
824
+ region: process.env.AWS_REGION || 'us-west-2',
825
+ credentials: fromEnv(),
826
+ });
827
+
828
+ const command = new InitiateAuthCommand({
829
+ AuthFlow: 'REFRESH_TOKEN_AUTH',
830
+ ClientId: this.fetchClientId(),
831
+ AuthParameters: {
832
+ REFRESH_TOKEN: refreshTokenString,
833
+ },
834
+ });
835
+
836
+ const response = await client.send(command);
837
+
838
+ if (!response.AuthenticationResult) {
839
+ throw new UnauthorisedError('Token refresh failed');
840
+ }
841
+
842
+ const newIdToken = response.AuthenticationResult.IdToken!;
843
+ const newAccessToken = response.AuthenticationResult.AccessToken!;
844
+ const newRefreshToken = response.AuthenticationResult.RefreshToken || refreshTokenString;
845
+
846
+ // Extract user info from the new ID token
847
+ const idTokenPayload = JSON.parse(atob(newIdToken.split('.')[1]));
848
+ const userEmail = idTokenPayload.email;
849
+
850
+ // Find or create local user
851
+ let localUser = await findUserByEmail(userEmail, env);
852
+ if (!localUser) {
853
+ localUser = await ensureUser(userEmail, '', '', env);
854
+ }
855
+ const userId = localUser.lookup('id');
856
+
857
+ // Update local session
858
+ const updatedSession = await ensureUserSession(
859
+ userId,
860
+ newIdToken,
861
+ newAccessToken,
862
+ newRefreshToken,
863
+ env
864
+ );
865
+
866
+ const sessInfo: SessionInfo = {
867
+ sessionId: updatedSession.lookup('id'),
868
+ userId: userId,
869
+ authToken: newIdToken,
870
+ idToken: newIdToken,
871
+ accessToken: newAccessToken,
872
+ refreshToken: newRefreshToken,
873
+ systemSesionInfo: response.AuthenticationResult,
874
+ };
875
+
876
+ return sessInfo;
877
+ } catch (err: any) {
878
+ logger.error(`Refresh token operation failed: ${err.message}`);
879
+ if (err.name === 'NotAuthorizedException') {
880
+ throw new UnauthorisedError('Invalid or expired refresh token');
881
+ }
882
+ handleCognitoError(err, 'refreshToken');
883
+ throw err; // This line won't be reached due to handleCognitoError throwing
884
+ }
885
+ }
756
886
  }
@@ -33,4 +33,11 @@ export interface AgentlangAuth {
33
33
  verifyToken(token: string, env?: Environment): any;
34
34
  getUser(userId: string, env: Environment): Promise<UserInfo>;
35
35
  getUserByEmail(email: string, env: Environment): Promise<UserInfo>;
36
+ changePassword(
37
+ sessionInfo: SessionInfo,
38
+ newPassword: string,
39
+ oldPassword: string,
40
+ env: Environment
41
+ ): Promise<boolean>;
42
+ refreshToken(refreshToken: string, env: Environment): Promise<SessionInfo>;
36
43
  }
@@ -54,7 +54,6 @@ import {
54
54
  escapeFqName,
55
55
  escapeQueryName,
56
56
  fqNameFromPath,
57
- invokeModuleFn,
58
57
  isFqName,
59
58
  isPath,
60
59
  isString,
@@ -78,6 +77,7 @@ import {
78
77
  maybeCancelTimer,
79
78
  setTimerRunning,
80
79
  } from './modules/core.js';
80
+ import { invokeModuleFn } from './jsmodules.js';
81
81
 
82
82
  export type Result = any;
83
83
 
@@ -590,8 +590,8 @@ export async function parseAndEvaluateStatement(
590
590
  }
591
591
 
592
592
  async function evaluatePattern(pat: Pattern, env: Environment): Promise<void> {
593
- if (pat.literal) {
594
- await evaluateLiteral(pat.literal, env);
593
+ if (pat.expr) {
594
+ await evaluateExpression(pat.expr, env);
595
595
  } else if (pat.crudMap) {
596
596
  await evaluateCrudMap(pat.crudMap, env);
597
597
  } else if (pat.forEach) {
@@ -1047,21 +1047,61 @@ async function walkJoinQueryPattern(
1047
1047
  async function handleAgentInvocation(agentEventInst: Instance, env: Environment): Promise<void> {
1048
1048
  const agent: AgentInstance = await findAgentByName(agentEventInst.name, env);
1049
1049
  await agent.invoke(agentEventInst.lookup('message'), env);
1050
- const result: string = env.getLastResult();
1051
- if (agent.isPlanner()) {
1052
- logger.debug(`Agent ${agent.name} generated pattern: ${result}`);
1053
- try {
1054
- if (result.trimStart().startsWith('workflow')) {
1055
- await parseWorkflow(result);
1056
- return;
1057
- } else {
1058
- env.setLastResult(await parseAndEvaluateStatement(result, undefined, env));
1050
+ const result: string | undefined = cleanupAgentResponse(env.getLastResult());
1051
+ if (result) {
1052
+ if (agent.isPlanner()) {
1053
+ logger.debug(`Agent ${agent.name} generated pattern: ${result}`);
1054
+ try {
1055
+ let rs = result.trim();
1056
+ if (rs.startsWith('[')) {
1057
+ const stmts = rs.substring(1, rs.length - 1);
1058
+ rs = `workflow T {${stmts}}`;
1059
+ }
1060
+ if (rs.startsWith('workflow')) {
1061
+ const wf = await parseWorkflow(rs);
1062
+ if (agent.runWorkflows) {
1063
+ await evaluateStatements(wf.statements, env);
1064
+ }
1065
+ } else {
1066
+ env.setLastResult(await parseAndEvaluateStatement(rs, undefined, env));
1067
+ }
1068
+ } catch (err: any) {
1069
+ logger.error(
1070
+ `Failed to evaluate pattern generated by agent ${agent.name} - ${result}, ${err}`
1071
+ );
1059
1072
  }
1060
- } catch (err: any) {
1061
- logger.error(
1062
- `Failed to evaluate pattern generated by agent ${agent.name} - ${result}, ${err}`
1063
- );
1064
1073
  }
1074
+ } else {
1075
+ logger.warn(`Agent ${agent.name} failed to generate a response`);
1076
+ }
1077
+ }
1078
+
1079
+ function cleanupAgentResponse(response: string | undefined): string | undefined {
1080
+ if (response) {
1081
+ const resp = response.trim();
1082
+ if (resp.startsWith('[') && resp.endsWith(']')) {
1083
+ return resp;
1084
+ }
1085
+ const parts = resp.split('\n');
1086
+ const validated = parts.filter((s: string) => {
1087
+ const stmt = s.trim();
1088
+ const r =
1089
+ stmt.startsWith('{') ||
1090
+ stmt.startsWith('}') ||
1091
+ stmt.startsWith('if') ||
1092
+ stmt.startsWith('for') ||
1093
+ stmt.startsWith('delete') ||
1094
+ stmt.startsWith('workflow');
1095
+ if (!r) {
1096
+ const i = stmt.indexOf('(');
1097
+ return i > 0 && stmt.indexOf(')') > i;
1098
+ } else {
1099
+ return r;
1100
+ }
1101
+ });
1102
+ return validated.join('\n');
1103
+ } else {
1104
+ return response;
1065
1105
  }
1066
1106
  }
1067
1107
 
@@ -1263,7 +1303,12 @@ async function applyFn(fnCall: FnCall, env: Environment, isAsync: boolean): Prom
1263
1303
  if (fnCall.args != undefined) {
1264
1304
  args = new Array<Result>();
1265
1305
  for (let i = 0; i < fnCall.args.length; ++i) {
1266
- await evaluateLiteral(fnCall.args[i], env);
1306
+ const arg = fnCall.args[i];
1307
+ if (isLiteral(arg)) {
1308
+ await evaluateLiteral(arg, env);
1309
+ } else {
1310
+ await evaluateExpression(arg, env);
1311
+ }
1267
1312
  args.push(env.getLastResult());
1268
1313
  }
1269
1314
  args.push(env);
@@ -1287,7 +1332,7 @@ async function realizeMap(mapLiteral: MapLiteral, env: Environment): Promise<voi
1287
1332
  for (let i = 0; i < mapLiteral.entries.length; ++i) {
1288
1333
  const entry = mapLiteral.entries[i];
1289
1334
  const k = getMapKey(entry.key);
1290
- await evaluateLiteral(entry.value, env);
1335
+ await evaluateExpression(entry.value, env);
1291
1336
  result.set(k, env.getLastResult());
1292
1337
  }
1293
1338
  env.setLastResult(Object.fromEntries(result.entries()));