agentlang 0.0.37 → 0.0.50

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 (78) hide show
  1. package/out/api/http.d.ts +1 -1
  2. package/out/api/http.d.ts.map +1 -1
  3. package/out/api/http.js +9 -3
  4. package/out/api/http.js.map +1 -1
  5. package/out/cli/main.js +2 -2
  6. package/out/cli/main.js.map +1 -1
  7. package/out/language/generated/ast.d.ts +57 -21
  8. package/out/language/generated/ast.d.ts.map +1 -1
  9. package/out/language/generated/ast.js +80 -26
  10. package/out/language/generated/ast.js.map +1 -1
  11. package/out/language/generated/grammar.d.ts.map +1 -1
  12. package/out/language/generated/grammar.js +337 -115
  13. package/out/language/generated/grammar.js.map +1 -1
  14. package/out/language/main.cjs +398 -135
  15. package/out/language/main.cjs.map +2 -2
  16. package/out/runtime/agents/common.d.ts +2 -1
  17. package/out/runtime/agents/common.d.ts.map +1 -1
  18. package/out/runtime/agents/common.js +49 -1
  19. package/out/runtime/agents/common.js.map +1 -1
  20. package/out/runtime/agents/registry.js +3 -1
  21. package/out/runtime/agents/registry.js.map +1 -1
  22. package/out/runtime/auth/cognito.d.ts.map +1 -1
  23. package/out/runtime/auth/cognito.js +28 -8
  24. package/out/runtime/auth/cognito.js.map +1 -1
  25. package/out/runtime/auth/interface.d.ts +2 -0
  26. package/out/runtime/auth/interface.d.ts.map +1 -1
  27. package/out/runtime/defs.d.ts +1 -0
  28. package/out/runtime/defs.d.ts.map +1 -1
  29. package/out/runtime/defs.js +1 -0
  30. package/out/runtime/defs.js.map +1 -1
  31. package/out/runtime/interpreter.d.ts +5 -0
  32. package/out/runtime/interpreter.d.ts.map +1 -1
  33. package/out/runtime/interpreter.js +77 -8
  34. package/out/runtime/interpreter.js.map +1 -1
  35. package/out/runtime/loader.d.ts.map +1 -1
  36. package/out/runtime/loader.js +89 -37
  37. package/out/runtime/loader.js.map +1 -1
  38. package/out/runtime/module.d.ts +1 -1
  39. package/out/runtime/module.d.ts.map +1 -1
  40. package/out/runtime/module.js +10 -3
  41. package/out/runtime/module.js.map +1 -1
  42. package/out/runtime/modules/ai.d.ts +13 -0
  43. package/out/runtime/modules/ai.d.ts.map +1 -1
  44. package/out/runtime/modules/ai.js +80 -9
  45. package/out/runtime/modules/ai.js.map +1 -1
  46. package/out/runtime/modules/auth.d.ts +1 -0
  47. package/out/runtime/modules/auth.d.ts.map +1 -1
  48. package/out/runtime/modules/auth.js +18 -0
  49. package/out/runtime/modules/auth.js.map +1 -1
  50. package/out/runtime/modules/core.d.ts +1 -0
  51. package/out/runtime/modules/core.d.ts.map +1 -1
  52. package/out/runtime/modules/core.js +15 -5
  53. package/out/runtime/modules/core.js.map +1 -1
  54. package/out/runtime/state.d.ts +5 -0
  55. package/out/runtime/state.d.ts.map +1 -1
  56. package/out/runtime/state.js +2 -0
  57. package/out/runtime/state.js.map +1 -1
  58. package/out/syntaxes/agentlang.monarch.js +3 -3
  59. package/out/syntaxes/agentlang.monarch.js.map +1 -1
  60. package/package.json +2 -2
  61. package/src/api/http.ts +8 -3
  62. package/src/cli/main.ts +1 -1
  63. package/src/language/agentlang.langium +12 -4
  64. package/src/language/generated/ast.ts +144 -49
  65. package/src/language/generated/grammar.ts +337 -115
  66. package/src/runtime/agents/common.ts +50 -1
  67. package/src/runtime/agents/registry.ts +3 -3
  68. package/src/runtime/auth/cognito.ts +30 -8
  69. package/src/runtime/auth/interface.ts +2 -0
  70. package/src/runtime/defs.ts +1 -0
  71. package/src/runtime/interpreter.ts +122 -8
  72. package/src/runtime/loader.ts +98 -37
  73. package/src/runtime/module.ts +13 -3
  74. package/src/runtime/modules/ai.ts +102 -11
  75. package/src/runtime/modules/auth.ts +28 -0
  76. package/src/runtime/modules/core.ts +16 -4
  77. package/src/runtime/state.ts +2 -0
  78. package/src/syntaxes/agentlang.monarch.ts +3 -3
@@ -250,7 +250,7 @@ workflow sendEmail {
250
250
  {email {to emp.email body "please call me as soon as possible"}}
251
251
  }
252
252
 
253
- The point is use the immediate context to fill-in values in generated patterns, as much as possible.
253
+ The point is, use the immediate context to fill-in values in generated patterns, as much as possible.
254
254
 
255
255
  Also generate a workflow only if required explicitly by the user or the contextual information is incomplete. Otherwise, just return an array of patterns.
256
256
  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:
@@ -263,3 +263,52 @@ You MUST separate each pattern in the array with a semi-colon (;) and never use
263
263
  Now consider the following module definition and generate appropriate patterns in response to the user instructions. You must return only valid patterns or workflows,
264
264
  no other descriptive text or comments are needed.
265
265
  `;
266
+
267
+ export const FlowExecInstructions = `The following is the textual representation of a flowchart.
268
+
269
+ checkOrder --> "ProductA" acceptOrder
270
+ checkOrder --> "ProductB" acceptOrder
271
+ checkOrder --> "ProductC" rejectOrder
272
+ acceptOrder --> sendPaymentLinkToCustomer
273
+ rejectOrder --> sendRejectionEmailToCustomer
274
+
275
+ Along with this flowchart, you'll be passed a "context", which contain the steps in the flowchart that was executed so far, along with
276
+ their results. Based on the context, you need to return the name of the step that needs to execute next. If you have reached the end
277
+ of the chart, return 'DONE'.
278
+
279
+ At the beginning of the execution, the context will contain only the order information, say something like:
280
+
281
+ OrderNo: 101, Item: "ProductB", customerEmail: "manager@acme.com"
282
+
283
+ This means you have to return 'checkOrder' as the next step (i.e you move the root node of the flowchart).
284
+ After the step checkOrder executes, you'll be passed the following context:
285
+
286
+ orderNo: 101, Item: "ProductB", customerEmail: "manager@acme.com"
287
+ checkOrder --> "ProductB"
288
+
289
+ Now you can infer from the context that if the result of checkOrder is either "ProductA" or "ProductB", you must move to the step 'acceptOrder'.
290
+ So you return 'acceptOrder'. After this, you'll return the updated context as:
291
+
292
+ OrderNo: 101, Item: "ProductB", customerEmail: "manager@acme.com"
293
+ checkOrder --> "ProductB"
294
+ acceptOrder --> {orderNo: 101, customerEmail: "manager@acme.com", acceptedOn: "2025-07-01"}
295
+
296
+ You see that 'acceptOrder' has produced the result '{orderNo: 101, customerEmail: "manager@acme.com", acceptedOn: "2025-07-01"}' - but from the flowchart you know that, whatever the result of 'acceptOrder',
297
+ you have to move to the 'sendPaymentLinkToCustomer' step and so you return 'sendPaymentLinkToCustomer'.
298
+
299
+ The next context you'll see will be:
300
+
301
+ OrderNo: 101, Item: "ProductB", customerEmail: "manager@acme.com"
302
+ checkOrder --> "ProductB"
303
+ acceptOrder --> {orderNo: 101, customerEmail: "manager@acme.com", acceptedOn: "2025-07-01"}
304
+ sendPaymentLinkToCustomer --> "manager@acme.com"
305
+
306
+ The 'sendPaymentLinkToCustomer' has returned the customer email. You look at the flowchart and detect that, whatever the return value of
307
+ 'sendPaymentLinkToCustomer' there is nothing else to do. So you return 'DONE'.
308
+
309
+ Generally a flowchart has the following two types of entries:
310
+ 1. a --> b, meaning after step 'a' do step 'b'.
311
+ 2. a --> "x" b - this means if 'a' returns the string "x", then do step 'b'.
312
+ If you detect that you have reached the end of the chart, return 'DONE'. Otherwise, return only the name of the next step. Never return
313
+ any additional description, direction or comments.
314
+ `;
@@ -18,9 +18,9 @@ export function provider(service: string) {
18
18
  p = Providers.get(availableService);
19
19
  if (p) return p;
20
20
  }
21
- throw new Error(
22
- `${service} provider requested but ${service.toUpperCase()}_API_KEY not found. Available providers: ${getAvailableProviders().join(', ') || 'none'}`
23
- );
21
+ const errorMessage = `${service} provider requested but ${service.toUpperCase()}_API_KEY not found. Available providers: ${getAvailableProviders().join(', ') || 'none'}`;
22
+ console.error(errorMessage);
23
+ throw new Error(errorMessage);
24
24
  }
25
25
  } else {
26
26
  throw new Error(`No provider found for ${service}`);
@@ -378,9 +378,11 @@ export class CognitoAuth implements AgentlangAuth {
378
378
 
379
379
  if (response.$metadata.httpStatusCode == 200) {
380
380
  logger.info(`Signup successful for user: ${username}`);
381
- const user = await ensureUser(username, '', '', env);
381
+ const user = await ensureUser(username, firstName, lastName, env);
382
382
  const userInfo: UserInfo = {
383
383
  username: username,
384
+ firstName: firstName,
385
+ lastName: lastName,
384
386
  id: user.id,
385
387
  systemUserInfo: response.UserSub,
386
388
  };
@@ -538,15 +540,19 @@ export class CognitoAuth implements AgentlangAuth {
538
540
  }
539
541
  if (result) {
540
542
  // After successful Cognito authentication, create/update local records
541
- let localUser = await findUserByEmail(username, env);
542
- if (!localUser) {
543
- localUser = await ensureUser(username, '', '', env);
544
- }
545
- const userid = localUser.lookup('id');
546
543
  const idtok = result.getIdToken();
547
544
  const idToken = idtok.getJwtToken();
548
545
  const idTokenPayload = idtok.decodePayload();
546
+
547
+ const firstName = idTokenPayload['given_name'] || idTokenPayload['name'] || '';
548
+ const lastName = idTokenPayload['family_name'] || '';
549
549
  const userGroups = idTokenPayload['cognito:groups'];
550
+
551
+ let localUser = await findUserByEmail(username, env);
552
+ if (!localUser) {
553
+ localUser = await ensureUser(username, firstName, lastName, env);
554
+ }
555
+ const userid = localUser.lookup('id');
550
556
  if (userGroups) {
551
557
  await ensureUserRoles(userid, userGroups, env);
552
558
  }
@@ -802,6 +808,8 @@ export class CognitoAuth implements AgentlangAuth {
802
808
  }
803
809
 
804
810
  const userEmail = localUser.lookup('email');
811
+ const firstName = localUser.lookup('firstName');
812
+ const lastName = localUser.lookup('lastName');
805
813
 
806
814
  // Check if Cognito is configured
807
815
  const cognitoConfigured = process.env.COGNITO_USER_POOL_ID && process.env.COGNITO_CLIENT_ID;
@@ -825,6 +833,8 @@ export class CognitoAuth implements AgentlangAuth {
825
833
  return {
826
834
  id: userId,
827
835
  username: userEmail,
836
+ firstName: firstName,
837
+ lastName: lastName,
828
838
  systemUserInfo: {
829
839
  localUser: localUser,
830
840
  cognitoData: {
@@ -847,6 +857,8 @@ export class CognitoAuth implements AgentlangAuth {
847
857
  return {
848
858
  id: userId,
849
859
  username: userEmail,
860
+ firstName: firstName,
861
+ lastName: lastName,
850
862
  systemUserInfo: localUser,
851
863
  };
852
864
  }
@@ -855,6 +867,8 @@ export class CognitoAuth implements AgentlangAuth {
855
867
  return {
856
868
  id: userId,
857
869
  username: userEmail || userId,
870
+ firstName: firstName,
871
+ lastName: lastName,
858
872
  systemUserInfo: localUser,
859
873
  };
860
874
  }
@@ -867,6 +881,8 @@ export class CognitoAuth implements AgentlangAuth {
867
881
  }
868
882
 
869
883
  const userId = localUser.lookup('id');
884
+ const firstName = localUser.lookup('firstName');
885
+ const lastName = localUser.lookup('lastName');
870
886
 
871
887
  // Check if Cognito is configured
872
888
  const cognitoConfigured = process.env.COGNITO_USER_POOL_ID && process.env.COGNITO_CLIENT_ID;
@@ -876,11 +892,11 @@ export class CognitoAuth implements AgentlangAuth {
876
892
  // Get additional user details from Cognito
877
893
  const client = new CognitoIdentityProviderClient({
878
894
  region: process.env.AWS_REGION || 'us-west-2',
879
- credentials: fromEnv(),
880
895
  });
881
896
 
882
897
  const command = new AdminGetUserCommand({
883
898
  UserPoolId: this.fetchUserPoolId(),
899
+ ClientId: this.fetchClientId(),
884
900
  Username: email,
885
901
  });
886
902
 
@@ -890,6 +906,8 @@ export class CognitoAuth implements AgentlangAuth {
890
906
  return {
891
907
  id: userId,
892
908
  username: email,
909
+ firstName: firstName,
910
+ lastName: lastName,
893
911
  systemUserInfo: {
894
912
  localUser: localUser,
895
913
  cognitoData: {
@@ -904,7 +922,7 @@ export class CognitoAuth implements AgentlangAuth {
904
922
  },
905
923
  };
906
924
  } catch (err: any) {
907
- logger.warn(`Failed to get Cognito user info for email ${email}, using local data only:`, {
925
+ console.log(`Failed to get Cognito user info for email ${email}, using local data only:`, {
908
926
  errorName: err.name,
909
927
  errorMessage: sanitizeErrorMessage(err.message),
910
928
  });
@@ -912,6 +930,8 @@ export class CognitoAuth implements AgentlangAuth {
912
930
  return {
913
931
  id: userId,
914
932
  username: email,
933
+ firstName: firstName,
934
+ lastName: lastName,
915
935
  systemUserInfo: localUser,
916
936
  };
917
937
  }
@@ -920,6 +940,8 @@ export class CognitoAuth implements AgentlangAuth {
920
940
  return {
921
941
  id: userId,
922
942
  username: email,
943
+ firstName: firstName,
944
+ lastName: lastName,
923
945
  systemUserInfo: localUser,
924
946
  };
925
947
  }
@@ -3,6 +3,8 @@ import { Environment } from '../interpreter.js';
3
3
  export type UserInfo = {
4
4
  id: string; // a UUID
5
5
  username: string;
6
+ firstName: string;
7
+ lastName: string;
6
8
  systemUserInfo?: any;
7
9
  };
8
10
 
@@ -89,3 +89,4 @@ export function setSubscriptionFn(f: Function) {
89
89
  }
90
90
 
91
91
  export const ForceReadPermFlag = 'f-r-f';
92
+ export const FlowSuspensionTag = `--`;
@@ -70,9 +70,22 @@ import {
70
70
  import { getResolver, getResolverNameForPath } from './resolvers/registry.js';
71
71
  import { parseStatement, parseWorkflow } from '../language/parser.js';
72
72
  import { ActiveSessionInfo, AdminSession, AdminUserId } from './auth/defs.js';
73
- import { AgentInstance, AgentEntityName, AgentFqName, findAgentByName } from './modules/ai.js';
73
+ import {
74
+ AgentInstance,
75
+ AgentEntityName,
76
+ AgentFqName,
77
+ findAgentByName,
78
+ FlowSpec,
79
+ getAgentFlow,
80
+ FlowStep,
81
+ } from './modules/ai.js';
74
82
  import { logger } from './logger.js';
75
- import { ParentAttributeName, PathAttributeName, PathAttributeNameQuery } from './defs.js';
83
+ import {
84
+ FlowSuspensionTag,
85
+ ParentAttributeName,
86
+ PathAttributeName,
87
+ PathAttributeNameQuery,
88
+ } from './defs.js';
76
89
  import {
77
90
  addCreateAudit,
78
91
  addDeleteAudit,
@@ -238,6 +251,22 @@ export class Environment extends Instance {
238
251
  return this;
239
252
  }
240
253
 
254
+ private static FlowContextTag = 'flow-context';
255
+
256
+ setFlowContext(s: string): Environment {
257
+ this.attributes.set(Environment.FlowContextTag, s);
258
+ return this;
259
+ }
260
+
261
+ resetFlowContext(): Environment {
262
+ this.attributes.set(Environment.FlowContextTag, undefined);
263
+ return this;
264
+ }
265
+
266
+ getFlowContext(): string | undefined {
267
+ return this.attributes.get(Environment.FlowContextTag);
268
+ }
269
+
241
270
  static SuspensionUserData = '^';
242
271
 
243
272
  bindSuspensionUserData(userData: string): Environment {
@@ -1093,7 +1122,7 @@ async function evaluateCrudMap(crud: CrudMap, env: Environment): Promise<void> {
1093
1122
  await runPostCreateEvents(inst, env);
1094
1123
  }
1095
1124
  if (r && entryName == AgentEntityName) {
1096
- defineAgentEvent(env.getActiveModuleName(), r.lookup('name'));
1125
+ defineAgentEvent(env.getActiveModuleName(), r.lookup('name'), r.lookup('instruction'));
1097
1126
  }
1098
1127
  env.setLastResult(r);
1099
1128
  const betRelInfo: BetweenRelInfo | undefined = env.getBetweenRelInfo();
@@ -1365,10 +1394,9 @@ async function walkJoinQueryPattern(
1365
1394
 
1366
1395
  const MAX_PLANNER_RETRIES = 3;
1367
1396
 
1368
- async function handleAgentInvocation(agentEventInst: Instance, env: Environment): Promise<void> {
1369
- const agent: AgentInstance = await findAgentByName(agentEventInst.name, env);
1370
- const origMsg: any = agentEventInst.lookup('message');
1371
- const msg: string = isString(origMsg) ? origMsg : agentInputAsString(origMsg);
1397
+ async function agentInvoke(agent: AgentInstance, msg: string, env: Environment): Promise<void> {
1398
+ const flowContext = env.getFlowContext();
1399
+ msg = flowContext ? `context: ${flowContext}\n${msg}` : msg;
1372
1400
  await agent.invoke(msg, env);
1373
1401
  const r: string | undefined = env.getLastResult();
1374
1402
  const isPlanner = agent.isPlanner();
@@ -1420,7 +1448,93 @@ async function handleAgentInvocation(agentEventInst: Instance, env: Environment)
1420
1448
  await pushToAgent(agent.output, env.getLastResult(), env);
1421
1449
  }
1422
1450
  } else {
1423
- logger.warn(`Agent ${agent.name} failed to generate a response`);
1451
+ throw new Error(`Agent ${agent.name} failed to generate a response`);
1452
+ }
1453
+ }
1454
+
1455
+ async function handleAgentInvocation(agentEventInst: Instance, env: Environment): Promise<void> {
1456
+ const agent: AgentInstance = await findAgentByName(agentEventInst.name, env);
1457
+ const origMsg: any = agentEventInst.lookup('message');
1458
+ const msg: string = isString(origMsg) ? origMsg : agentInputAsString(origMsg);
1459
+ const flow = getAgentFlow(agent.name);
1460
+ if (flow) {
1461
+ await handleAgentInvocationWithFlow(agent, flow, msg, env);
1462
+ } else {
1463
+ await agentInvoke(agent, msg, env).catch((reason: any) => {
1464
+ logger.warn(reason);
1465
+ });
1466
+ }
1467
+ }
1468
+
1469
+ async function handleAgentInvocationWithFlow(
1470
+ rootAgent: AgentInstance,
1471
+ flow: FlowSpec,
1472
+ msg: string,
1473
+ env: Environment
1474
+ ): Promise<void> {
1475
+ await iterateOnFlow(flow, rootAgent, msg, env);
1476
+ }
1477
+
1478
+ async function saveFlowSuspension(
1479
+ agent: AgentInstance,
1480
+ context: string,
1481
+ step: FlowStep,
1482
+ env: Environment
1483
+ ): Promise<void> {
1484
+ const suspId = await createSuspension(
1485
+ env.getSuspensionId(),
1486
+ [FlowSuspensionTag, agent.name, step, context],
1487
+ env
1488
+ );
1489
+ env.setLastResult({ suspension: suspId || 'null' });
1490
+ }
1491
+
1492
+ export async function restartFlow(
1493
+ flowContext: string[],
1494
+ userData: string,
1495
+ env: Environment
1496
+ ): Promise<void> {
1497
+ const [_, agentName, step, ctx] = flowContext;
1498
+ const flow = getAgentFlow(agentName);
1499
+ if (flow) {
1500
+ const rootAgent = await findAgentByName(agentName, env);
1501
+ const newCtx = `${ctx}\n${step} --> ${userData}\n`;
1502
+ await iterateOnFlow(flow, rootAgent, newCtx, env);
1503
+ }
1504
+ }
1505
+
1506
+ const MaxFlowSteps = 25;
1507
+
1508
+ async function iterateOnFlow(
1509
+ flow: FlowSpec,
1510
+ rootAgent: AgentInstance,
1511
+ msg: string,
1512
+ env: Environment
1513
+ ): Promise<void> {
1514
+ rootAgent.disableSession();
1515
+ const s = `Now consider the following flowchart and context:\n${flow}\n\n${msg}`;
1516
+ await agentInvoke(rootAgent, s, env);
1517
+ let step = env.getLastResult();
1518
+ let context = msg;
1519
+ let stepc = 0;
1520
+ while (step != 'DONE') {
1521
+ if (stepc > MaxFlowSteps) {
1522
+ throw new Error(`Flow execution exceeded maximum steps limit`);
1523
+ }
1524
+ ++stepc;
1525
+ const agent = AgentInstance.FromFlowStep(step, rootAgent);
1526
+ agent.disableSession();
1527
+ env.setFlowContext(context);
1528
+ await agentInvoke(agent, '', env);
1529
+ env.resetFlowContext();
1530
+ if (env.isSuspended()) {
1531
+ await saveFlowSuspension(rootAgent, context, step, env);
1532
+ return;
1533
+ }
1534
+ const r = env.getLastResult();
1535
+ context = `${context}\n${step} --> ${agentInputAsString(r)}\n`;
1536
+ await agentInvoke(rootAgent, `${s}\n${context}`, env);
1537
+ step = env.getLastResult();
1424
1538
  }
1425
1539
  }
1426
1540
 
@@ -22,8 +22,13 @@ import {
22
22
  isResolverDefinition,
23
23
  ResolverDefinition,
24
24
  ResolverMethodSpec,
25
- AgentPropertyDef,
25
+ GenericPropertyDef,
26
26
  isLiteral,
27
+ ArrayLiteral,
28
+ MapEntry,
29
+ Expr,
30
+ FlowDefinition,
31
+ isFlowDefinition,
27
32
  } from '../language/generated/ast.js';
28
33
  import {
29
34
  addEntity,
@@ -47,6 +52,7 @@ import {
47
52
  import {
48
53
  escapeSpecialChars,
49
54
  findRbacSchema,
55
+ isFqName,
50
56
  isString,
51
57
  makeFqName,
52
58
  maybeExtends,
@@ -61,7 +67,13 @@ import { maybeGetValidationErrors, parse, parseModule, parseWorkflow } from '../
61
67
  import { logger } from './logger.js';
62
68
  import { Environment, evaluateStatements, GlobalEnvironment } from './interpreter.js';
63
69
  import { createPermission, createRole } from './modules/auth.js';
64
- import { AgentEntityName, CoreAIModuleName, LlmEntityName } from './modules/ai.js';
70
+ import {
71
+ AgentEntityName,
72
+ CoreAIModuleName,
73
+ LlmEntityName,
74
+ registerAgentFlow,
75
+ registerFlow,
76
+ } from './modules/ai.js';
65
77
  import { GenericResolver, GenericResolverMethods } from './resolvers/interface.js';
66
78
  import { registerResolver, setResolver } from './resolvers/registry.js';
67
79
  import { Config, ConfigSchema, setAppConfig } from './state.js';
@@ -288,6 +300,7 @@ export async function loadCoreModules() {
288
300
 
289
301
  async function loadModule(fileName: string, fsOptions?: any, callback?: Function): Promise<Module> {
290
302
  // Initialize filesystem if not already done
303
+ console.log(`loading ${fileName}`);
291
304
  const fs = await getFileSystem(fsOptions);
292
305
 
293
306
  const fsAdapter = getFsAdapter(fs);
@@ -455,45 +468,53 @@ async function addAgentDefinition(def: AgentDefinition, moduleName: string) {
455
468
  const attrsStrs = new Array<string>();
456
469
  attrsStrs.push(`name "${name}"`);
457
470
  const attrs = newInstanceAttributes();
458
- def.body?.attributes.forEach((apdef: AgentPropertyDef) => {
459
- let v: any = undefined;
460
- if (apdef.value.array) {
461
- v = apdef.value.array.vals
462
- .map((stmt: Statement) => {
463
- if (stmt.pattern.expr && isLiteral(stmt.pattern.expr)) {
464
- const s = stmt.pattern.expr.str || stmt.pattern.expr.id || stmt.pattern.expr.ref;
465
- if (s == undefined) {
466
- throw new Error(
467
- `Only arrays of string-literals or identifiers should be passed to agent ${name}`
468
- );
469
- }
470
- return s;
471
- } else {
472
- throw new Error(`Invalid value in array passed to agent ${name}`);
473
- }
474
- })
475
- .join(',');
471
+ attrsStrs.push(`moduleName "${moduleName}"`);
472
+ attrs.set('moduleName', moduleName);
473
+ def.body?.attributes.forEach((apdef: GenericPropertyDef) => {
474
+ if (apdef.name == 'flows') {
475
+ let fnames: string | undefined = undefined;
476
+ if (apdef.value.array) {
477
+ fnames = processAgentArray(apdef.value.array, name);
478
+ } else {
479
+ fnames = apdef.value.id || apdef.value.str;
480
+ }
481
+ if (fnames) {
482
+ fnames.split(',').forEach((n: string) => {
483
+ n = n.trim();
484
+ const fqn = isFqName(n) ? n : `${moduleName}/${n}`;
485
+ registerAgentFlow(name, fqn);
486
+ });
487
+ attrsStrs.push(`type "flow-exec"`);
488
+ attrs.set('type', 'flow-exec');
489
+ } else {
490
+ throw new Error(`Invalid flows list in agent ${name}`);
491
+ }
476
492
  } else {
477
- v = apdef.value.str || apdef.value.id || apdef.value.ref || apdef.value.num;
493
+ let v: any = undefined;
494
+ if (apdef.value.array) {
495
+ v = processAgentArray(apdef.value.array, name);
496
+ } else {
497
+ v = apdef.value.str || apdef.value.id || apdef.value.ref || apdef.value.num;
498
+ if (v == undefined) {
499
+ v = apdef.value.bool;
500
+ }
501
+ }
478
502
  if (v == undefined) {
479
- v = apdef.value.bool;
503
+ throw new Error(`Cannot initialize agent ${name}, only literals can be set for attributes`);
480
504
  }
505
+ if (llmName == undefined && apdef.name == 'llm') {
506
+ llmName = v;
507
+ hasUserLlm = true;
508
+ }
509
+ const ov = v;
510
+ if (apdef.value.id || apdef.value.ref || apdef.value.array) {
511
+ v = `"${v}"`;
512
+ } else if (apdef.value.str) {
513
+ v = `"${escapeSpecialChars(v)}"`;
514
+ }
515
+ attrsStrs.push(`${apdef.name} ${v}`);
516
+ attrs.set(apdef.name, ov);
481
517
  }
482
- if (v == undefined) {
483
- throw new Error(`Cannot initialize agent ${name}, only literals can be set for attributes`);
484
- }
485
- if (llmName == undefined && apdef.name == 'llm') {
486
- llmName = v;
487
- hasUserLlm = true;
488
- }
489
- const ov = v;
490
- if (apdef.value.id || apdef.value.ref || apdef.value.array) {
491
- v = `"${v}"`;
492
- } else if (apdef.value.str) {
493
- v = `"${escapeSpecialChars(v)}"`;
494
- }
495
- attrsStrs.push(`${apdef.name} ${v}`);
496
- attrs.set(apdef.name, ov);
497
518
  });
498
519
  if (!attrs.has('llm')) {
499
520
  llmName = `${name}_llm`;
@@ -513,6 +534,45 @@ async function addAgentDefinition(def: AgentDefinition, moduleName: string) {
513
534
  addAgent(def.name, attrs, moduleName);
514
535
  }
515
536
 
537
+ function processAgentArray(array: ArrayLiteral, attrName: string): string {
538
+ return array.vals
539
+ .map((stmt: Statement) => {
540
+ const expr = stmt.pattern.expr;
541
+ return processAgentArrayValue(expr, attrName);
542
+ })
543
+ .join(',');
544
+ }
545
+
546
+ function processAgentArrayValue(expr: Expr | undefined, attrName: string): string {
547
+ if (expr && isLiteral(expr)) {
548
+ const s = expr.str || expr.id || expr.ref || expr.bool;
549
+ if (s != undefined) {
550
+ return s;
551
+ }
552
+ if (expr.array) {
553
+ return processAgentArray(expr.array, attrName);
554
+ } else if (expr.map) {
555
+ const m = new Array<string>();
556
+ expr.map.entries.forEach((me: MapEntry) => {
557
+ m.push(
558
+ `${me.key.str || me.key.num || me.key.bool || ''}: ${processAgentArrayValue(me.value, attrName)}`
559
+ );
560
+ });
561
+ return `{${m.join(',')}}`;
562
+ } else {
563
+ throw new Error(`Type not supprted in agent-arrays - ${attrName}`);
564
+ }
565
+ } else {
566
+ throw new Error(`Invalid value in array passed to agent ${attrName}`);
567
+ }
568
+ }
569
+
570
+ function addFlowDefinition(def: FlowDefinition, moduleName: string) {
571
+ if (def.body && def.$cstNode) {
572
+ registerFlow(`${moduleName}/${def.name}`, def.$cstNode.text);
573
+ }
574
+ }
575
+
516
576
  function addResolverDefinition(def: ResolverDefinition, moduleName: string) {
517
577
  const resolverName = `${moduleName}/${def.name}`;
518
578
  const paths = def.paths;
@@ -571,6 +631,7 @@ export async function addFromDef(def: Definition, moduleName: string) {
571
631
  else if (isAgentDefinition(def)) await addAgentDefinition(def, moduleName);
572
632
  else if (isStandaloneStatement(def)) addStandaloneStatement(def.stmt, moduleName);
573
633
  else if (isResolverDefinition(def)) addResolverDefinition(def, moduleName);
634
+ else if (isFlowDefinition(def)) addFlowDefinition(def, moduleName);
574
635
  }
575
636
 
576
637
  export async function parseAndIntern(code: string, moduleName?: string) {
@@ -850,8 +850,10 @@ export class Agent extends Record {
850
850
  override toString(): string {
851
851
  const attrs = new Array<string>();
852
852
  this.attributes.forEach((value: any, key: string) => {
853
- const v = isString(value) ? `"${value}"` : value;
854
- attrs.push(` ${key} ${v}`);
853
+ if (key != 'moduleName') {
854
+ const v = isString(value) ? `"${value}"` : value;
855
+ attrs.push(` ${key} ${v}`);
856
+ }
855
857
  });
856
858
  return `agent ${Agent.NormalizeName(this.name)}
857
859
  {
@@ -2848,14 +2850,22 @@ export function assertInstance(obj: any) {
2848
2850
 
2849
2851
  const IsAgentEventMeta = 'is-agent-event';
2850
2852
  const EventAgentName = 'event-agent-name';
2853
+ const DocumentationMetaTag = 'documentation';
2851
2854
 
2852
- export function defineAgentEvent(moduleName: string, agentName: string) {
2855
+ export function defineAgentEvent(moduleName: string, agentName: string, instruction?: string) {
2853
2856
  const module = fetchModule(moduleName);
2854
2857
  const event: Record = new Event(agentName, moduleName);
2855
2858
  event.addAttribute('message', { type: 'Any' });
2856
2859
  event.addAttribute('chatId', { type: 'String' });
2857
2860
  event.addMeta(IsAgentEventMeta, 'y');
2858
2861
  event.addMeta(EventAgentName, agentName);
2862
+ if (instruction) {
2863
+ event.addMeta(
2864
+ DocumentationMetaTag,
2865
+ `This event will trigger an agent which has the instruction - "${instruction}".
2866
+ So make sure to pass all relevant information in the 'message' attribute of this event.`
2867
+ );
2868
+ }
2859
2869
  module.addEntry(event);
2860
2870
  }
2861
2871