agentlang 0.0.40 → 0.0.51

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 (80) hide show
  1. package/out/extension/main.cjs +250 -250
  2. package/out/extension/main.cjs.map +2 -2
  3. package/out/language/generated/ast.d.ts +57 -21
  4. package/out/language/generated/ast.d.ts.map +1 -1
  5. package/out/language/generated/ast.js +80 -26
  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 +337 -115
  9. package/out/language/generated/grammar.js.map +1 -1
  10. package/out/language/main.cjs +900 -637
  11. package/out/language/main.cjs.map +3 -3
  12. package/out/language/syntax.d.ts +7 -0
  13. package/out/language/syntax.d.ts.map +1 -1
  14. package/out/language/syntax.js +16 -0
  15. package/out/language/syntax.js.map +1 -1
  16. package/out/runtime/agents/common.d.ts +9 -1
  17. package/out/runtime/agents/common.d.ts.map +1 -1
  18. package/out/runtime/agents/common.js +83 -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.js +1 -1
  23. package/out/runtime/defs.d.ts +1 -0
  24. package/out/runtime/defs.d.ts.map +1 -1
  25. package/out/runtime/defs.js +1 -0
  26. package/out/runtime/defs.js.map +1 -1
  27. package/out/runtime/interpreter.d.ts +5 -0
  28. package/out/runtime/interpreter.d.ts.map +1 -1
  29. package/out/runtime/interpreter.js +81 -9
  30. package/out/runtime/interpreter.js.map +1 -1
  31. package/out/runtime/loader.d.ts.map +1 -1
  32. package/out/runtime/loader.js +111 -40
  33. package/out/runtime/loader.js.map +1 -1
  34. package/out/runtime/module.d.ts +24 -2
  35. package/out/runtime/module.d.ts.map +1 -1
  36. package/out/runtime/module.js +103 -12
  37. package/out/runtime/module.js.map +1 -1
  38. package/out/runtime/modules/ai.d.ts +9 -0
  39. package/out/runtime/modules/ai.d.ts.map +1 -1
  40. package/out/runtime/modules/ai.js +50 -9
  41. package/out/runtime/modules/ai.js.map +1 -1
  42. package/out/runtime/modules/auth.d.ts.map +1 -1
  43. package/out/runtime/modules/auth.js.map +1 -1
  44. package/out/runtime/modules/core.d.ts +1 -0
  45. package/out/runtime/modules/core.d.ts.map +1 -1
  46. package/out/runtime/modules/core.js +15 -5
  47. package/out/runtime/modules/core.js.map +1 -1
  48. package/out/runtime/resolvers/authinfo.d.ts +8 -0
  49. package/out/runtime/resolvers/authinfo.d.ts.map +1 -0
  50. package/out/runtime/resolvers/authinfo.js +14 -0
  51. package/out/runtime/resolvers/authinfo.js.map +1 -0
  52. package/out/runtime/resolvers/interface.d.ts +1 -7
  53. package/out/runtime/resolvers/interface.d.ts.map +1 -1
  54. package/out/runtime/resolvers/interface.js +3 -16
  55. package/out/runtime/resolvers/interface.js.map +1 -1
  56. package/out/runtime/resolvers/sqldb/database.d.ts +3 -1
  57. package/out/runtime/resolvers/sqldb/database.d.ts.map +1 -1
  58. package/out/runtime/resolvers/sqldb/database.js +72 -3
  59. package/out/runtime/resolvers/sqldb/database.js.map +1 -1
  60. package/out/syntaxes/agentlang.monarch.js +3 -3
  61. package/out/syntaxes/agentlang.monarch.js.map +1 -1
  62. package/package.json +156 -153
  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/language/syntax.ts +21 -0
  67. package/src/runtime/agents/common.ts +91 -1
  68. package/src/runtime/agents/registry.ts +3 -3
  69. package/src/runtime/auth/cognito.ts +3 -3
  70. package/src/runtime/defs.ts +1 -0
  71. package/src/runtime/interpreter.ts +117 -8
  72. package/src/runtime/loader.ts +113 -39
  73. package/src/runtime/module.ts +123 -13
  74. package/src/runtime/modules/ai.ts +67 -11
  75. package/src/runtime/modules/auth.ts +6 -1
  76. package/src/runtime/modules/core.ts +16 -4
  77. package/src/runtime/resolvers/authinfo.ts +14 -0
  78. package/src/runtime/resolvers/interface.ts +2 -19
  79. package/src/runtime/resolvers/sqldb/database.ts +76 -3
  80. package/src/syntaxes/agentlang.monarch.ts +3 -3
@@ -715,3 +715,24 @@ function patternsToString(body: BasePattern[], sep = ';\n'): string {
715
715
  })
716
716
  .join(sep);
717
717
  }
718
+
719
+ export class FlowStepPattern extends BasePattern {
720
+ first: string;
721
+ next: string;
722
+ condition?: string;
723
+
724
+ constructor(first: string, next: string, condition?: string) {
725
+ super();
726
+ this.first = first;
727
+ this.next = next;
728
+ this.condition = condition;
729
+ }
730
+
731
+ override toString(): string {
732
+ if (this.condition) {
733
+ return `${this.first} --> ${this.condition} ${this.next}`;
734
+ } else {
735
+ return `${this.first} --> ${this.next}`;
736
+ }
737
+ }
738
+ }
@@ -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,93 @@ 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
+ `;
315
+
316
+ export type FlowSpec = string;
317
+ export type FlowStep = string;
318
+
319
+ const AgentFlows = new Map<string, string[]>();
320
+ const FlowRegistry = new Map<string, FlowSpec>();
321
+
322
+ export function registerFlow(name: string, flow: FlowSpec): string {
323
+ FlowRegistry.set(name, flow);
324
+ return name;
325
+ }
326
+
327
+ export function getFlow(name: string): FlowSpec | undefined {
328
+ return FlowRegistry.get(name);
329
+ }
330
+
331
+ export function registerAgentFlow(agentName: string, flowSpecName: string): string {
332
+ let currentFlows = AgentFlows.get(agentName);
333
+ if (currentFlows) {
334
+ currentFlows.push(flowSpecName);
335
+ } else {
336
+ currentFlows = new Array<string>();
337
+ currentFlows.push(flowSpecName);
338
+ }
339
+ AgentFlows.set(agentName, currentFlows);
340
+ return agentName;
341
+ }
342
+
343
+ // Return the first flow registered with the agent.
344
+ export function getAgentFlow(agentName: string): FlowSpec | undefined {
345
+ const currentFlows = AgentFlows.get(agentName);
346
+ if (currentFlows) {
347
+ return getFlow(currentFlows[0]);
348
+ } else {
349
+ return undefined;
350
+ }
351
+ }
352
+
353
+ export function getAllAgentFlows(agentName: string): FlowSpec[] | undefined {
354
+ return AgentFlows.get(agentName);
355
+ }
@@ -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}`);
@@ -543,11 +543,11 @@ export class CognitoAuth implements AgentlangAuth {
543
543
  const idtok = result.getIdToken();
544
544
  const idToken = idtok.getJwtToken();
545
545
  const idTokenPayload = idtok.decodePayload();
546
-
546
+
547
547
  const firstName = idTokenPayload['given_name'] || idTokenPayload['name'] || '';
548
548
  const lastName = idTokenPayload['family_name'] || '';
549
549
  const userGroups = idTokenPayload['cognito:groups'];
550
-
550
+
551
551
  let localUser = await findUserByEmail(username, env);
552
552
  if (!localUser) {
553
553
  localUser = await ensureUser(username, firstName, lastName, env);
@@ -891,7 +891,7 @@ export class CognitoAuth implements AgentlangAuth {
891
891
  try {
892
892
  // Get additional user details from Cognito
893
893
  const client = new CognitoIdentityProviderClient({
894
- region: process.env.AWS_REGION || 'us-west-2'
894
+ region: process.env.AWS_REGION || 'us-west-2',
895
895
  });
896
896
 
897
897
  const command = new AdminGetUserCommand({
@@ -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 = `--`;
@@ -47,7 +47,8 @@ import {
47
47
  Relationship,
48
48
  Workflow,
49
49
  } from './module.js';
50
- import { JoinInfo, Resolver, ResolverAuthInfo } from './resolvers/interface.js';
50
+ import { JoinInfo, Resolver } from './resolvers/interface.js';
51
+ import { ResolverAuthInfo } from './resolvers/authinfo.js';
51
52
  import { SqlDbResolver } from './resolvers/sqldb/impl.js';
52
53
  import {
53
54
  CrudType,
@@ -72,7 +73,12 @@ import { parseStatement, parseWorkflow } from '../language/parser.js';
72
73
  import { ActiveSessionInfo, AdminSession, AdminUserId } from './auth/defs.js';
73
74
  import { AgentInstance, AgentEntityName, AgentFqName, findAgentByName } from './modules/ai.js';
74
75
  import { logger } from './logger.js';
75
- import { ParentAttributeName, PathAttributeName, PathAttributeNameQuery } from './defs.js';
76
+ import {
77
+ FlowSuspensionTag,
78
+ ParentAttributeName,
79
+ PathAttributeName,
80
+ PathAttributeNameQuery,
81
+ } from './defs.js';
76
82
  import {
77
83
  addCreateAudit,
78
84
  addDeleteAudit,
@@ -84,6 +90,7 @@ import {
84
90
  import { invokeModuleFn } from './jsmodules.js';
85
91
  import { invokeOpenApiEvent, isOpenApiEventInstance } from './openapi.js';
86
92
  import { fetchDoc } from './docs.js';
93
+ import { FlowSpec, FlowStep, getAgentFlow } from './agents/common.js';
87
94
 
88
95
  export type Result = any;
89
96
 
@@ -156,6 +163,7 @@ export class Environment extends Instance {
156
163
  this.activeResolvers = new Map<string, Resolver>();
157
164
  this.activeTransactions = new Map<string, string>();
158
165
  this.activeCatchHandlers = new Array<CatchHandlers>();
166
+ this.attributes.set('process', process);
159
167
  }
160
168
  }
161
169
 
@@ -238,6 +246,22 @@ export class Environment extends Instance {
238
246
  return this;
239
247
  }
240
248
 
249
+ private static FlowContextTag = 'flow-context';
250
+
251
+ setFlowContext(s: string): Environment {
252
+ this.attributes.set(Environment.FlowContextTag, s);
253
+ return this;
254
+ }
255
+
256
+ resetFlowContext(): Environment {
257
+ this.attributes.set(Environment.FlowContextTag, undefined);
258
+ return this;
259
+ }
260
+
261
+ getFlowContext(): string | undefined {
262
+ return this.attributes.get(Environment.FlowContextTag);
263
+ }
264
+
241
265
  static SuspensionUserData = '^';
242
266
 
243
267
  bindSuspensionUserData(userData: string): Environment {
@@ -1093,7 +1117,7 @@ async function evaluateCrudMap(crud: CrudMap, env: Environment): Promise<void> {
1093
1117
  await runPostCreateEvents(inst, env);
1094
1118
  }
1095
1119
  if (r && entryName == AgentEntityName) {
1096
- defineAgentEvent(env.getActiveModuleName(), r.lookup('name'));
1120
+ defineAgentEvent(env.getActiveModuleName(), r.lookup('name'), r.lookup('instruction'));
1097
1121
  }
1098
1122
  env.setLastResult(r);
1099
1123
  const betRelInfo: BetweenRelInfo | undefined = env.getBetweenRelInfo();
@@ -1365,10 +1389,9 @@ async function walkJoinQueryPattern(
1365
1389
 
1366
1390
  const MAX_PLANNER_RETRIES = 3;
1367
1391
 
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);
1392
+ async function agentInvoke(agent: AgentInstance, msg: string, env: Environment): Promise<void> {
1393
+ const flowContext = env.getFlowContext();
1394
+ msg = flowContext ? `context: ${flowContext}\n${msg}` : msg;
1372
1395
  await agent.invoke(msg, env);
1373
1396
  const r: string | undefined = env.getLastResult();
1374
1397
  const isPlanner = agent.isPlanner();
@@ -1420,7 +1443,93 @@ async function handleAgentInvocation(agentEventInst: Instance, env: Environment)
1420
1443
  await pushToAgent(agent.output, env.getLastResult(), env);
1421
1444
  }
1422
1445
  } else {
1423
- logger.warn(`Agent ${agent.name} failed to generate a response`);
1446
+ throw new Error(`Agent ${agent.name} failed to generate a response`);
1447
+ }
1448
+ }
1449
+
1450
+ async function handleAgentInvocation(agentEventInst: Instance, env: Environment): Promise<void> {
1451
+ const agent: AgentInstance = await findAgentByName(agentEventInst.name, env);
1452
+ const origMsg: any = agentEventInst.lookup('message');
1453
+ const msg: string = isString(origMsg) ? origMsg : agentInputAsString(origMsg);
1454
+ const flow = getAgentFlow(agent.name);
1455
+ if (flow) {
1456
+ await handleAgentInvocationWithFlow(agent, flow, msg, env);
1457
+ } else {
1458
+ await agentInvoke(agent, msg, env).catch((reason: any) => {
1459
+ logger.warn(reason);
1460
+ });
1461
+ }
1462
+ }
1463
+
1464
+ async function handleAgentInvocationWithFlow(
1465
+ rootAgent: AgentInstance,
1466
+ flow: FlowSpec,
1467
+ msg: string,
1468
+ env: Environment
1469
+ ): Promise<void> {
1470
+ await iterateOnFlow(flow, rootAgent, msg, env);
1471
+ }
1472
+
1473
+ async function saveFlowSuspension(
1474
+ agent: AgentInstance,
1475
+ context: string,
1476
+ step: FlowStep,
1477
+ env: Environment
1478
+ ): Promise<void> {
1479
+ const suspId = await createSuspension(
1480
+ env.getSuspensionId(),
1481
+ [FlowSuspensionTag, agent.name, step, context],
1482
+ env
1483
+ );
1484
+ env.setLastResult({ suspension: suspId || 'null' });
1485
+ }
1486
+
1487
+ export async function restartFlow(
1488
+ flowContext: string[],
1489
+ userData: string,
1490
+ env: Environment
1491
+ ): Promise<void> {
1492
+ const [_, agentName, step, ctx] = flowContext;
1493
+ const flow = getAgentFlow(agentName);
1494
+ if (flow) {
1495
+ const rootAgent = await findAgentByName(agentName, env);
1496
+ const newCtx = `${ctx}\n${step} --> ${userData}\n`;
1497
+ await iterateOnFlow(flow, rootAgent, newCtx, env);
1498
+ }
1499
+ }
1500
+
1501
+ const MaxFlowSteps = 25;
1502
+
1503
+ async function iterateOnFlow(
1504
+ flow: FlowSpec,
1505
+ rootAgent: AgentInstance,
1506
+ msg: string,
1507
+ env: Environment
1508
+ ): Promise<void> {
1509
+ rootAgent.disableSession();
1510
+ const s = `Now consider the following flowchart and context:\n${flow}\n\n${msg}`;
1511
+ await agentInvoke(rootAgent, s, env);
1512
+ let step = env.getLastResult();
1513
+ let context = msg;
1514
+ let stepc = 0;
1515
+ while (step != 'DONE') {
1516
+ if (stepc > MaxFlowSteps) {
1517
+ throw new Error(`Flow execution exceeded maximum steps limit`);
1518
+ }
1519
+ ++stepc;
1520
+ const agent = AgentInstance.FromFlowStep(step, rootAgent);
1521
+ agent.disableSession();
1522
+ env.setFlowContext(context);
1523
+ await agentInvoke(agent, '', env);
1524
+ env.resetFlowContext();
1525
+ if (env.isSuspended()) {
1526
+ await saveFlowSuspension(rootAgent, context, step, env);
1527
+ return;
1528
+ }
1529
+ const r = env.getLastResult();
1530
+ context = `${context}\n${step} --> ${agentInputAsString(r)}\n`;
1531
+ await agentInvoke(rootAgent, `${s}\n${context}`, env);
1532
+ step = env.getLastResult();
1424
1533
  }
1425
1534
  }
1426
1535
 
@@ -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,
@@ -43,10 +48,12 @@ import {
43
48
  removeModule,
44
49
  newInstanceAttributes,
45
50
  addAgent,
51
+ fetchModule,
46
52
  } from './module.js';
47
53
  import {
48
54
  escapeSpecialChars,
49
55
  findRbacSchema,
56
+ isFqName,
50
57
  isString,
51
58
  makeFqName,
52
59
  maybeExtends,
@@ -69,6 +76,7 @@ import { getModuleFn, importModule } from './jsmodules.js';
69
76
  import { SetSubscription } from './defs.js';
70
77
  import { ExtendedFileSystem } from '../utils/fs/interfaces.js';
71
78
  import z from 'zod';
79
+ import { registerAgentFlow, registerFlow } from './agents/common.js';
72
80
 
73
81
  export async function extractDocument(
74
82
  fileName: string,
@@ -288,6 +296,7 @@ export async function loadCoreModules() {
288
296
 
289
297
  async function loadModule(fileName: string, fsOptions?: any, callback?: Function): Promise<Module> {
290
298
  // Initialize filesystem if not already done
299
+ console.log(`loading ${fileName}`);
291
300
  const fs = await getFileSystem(fsOptions);
292
301
 
293
302
  const fsAdapter = getFsAdapter(fs);
@@ -418,7 +427,7 @@ export function addWorkflowFromDef(def: WorkflowDefinition, moduleName: string):
418
427
 
419
428
  const StandaloneStatements = new Map<string, Statement[]>();
420
429
 
421
- function addStandaloneStatement(stmt: Statement, moduleName: string) {
430
+ function addStandaloneStatement(stmt: Statement, moduleName: string, userDefined = true) {
422
431
  let stmts: Array<Statement> | undefined = StandaloneStatements.get(moduleName);
423
432
  if (stmts == undefined) {
424
433
  stmts = new Array<Statement>();
@@ -427,6 +436,10 @@ function addStandaloneStatement(stmt: Statement, moduleName: string) {
427
436
  if (!StandaloneStatements.has(moduleName)) {
428
437
  StandaloneStatements.set(moduleName, stmts);
429
438
  }
439
+ if (userDefined) {
440
+ const m = fetchModule(moduleName);
441
+ m.addStandaloneStatement(stmt);
442
+ }
430
443
  }
431
444
 
432
445
  export async function runStandaloneStatements() {
@@ -455,45 +468,55 @@ 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
+ attrsStrs.push(`flows "${fnames}"`);
490
+ attrs.set('flows', fnames);
491
+ } else {
492
+ throw new Error(`Invalid flows list in agent ${name}`);
493
+ }
476
494
  } else {
477
- v = apdef.value.str || apdef.value.id || apdef.value.ref || apdef.value.num;
495
+ let v: any = undefined;
496
+ if (apdef.value.array) {
497
+ v = processAgentArray(apdef.value.array, name);
498
+ } else {
499
+ v = apdef.value.str || apdef.value.id || apdef.value.ref || apdef.value.num;
500
+ if (v == undefined) {
501
+ v = apdef.value.bool;
502
+ }
503
+ }
478
504
  if (v == undefined) {
479
- v = apdef.value.bool;
505
+ throw new Error(`Cannot initialize agent ${name}, only literals can be set for attributes`);
480
506
  }
507
+ if (llmName == undefined && apdef.name == 'llm') {
508
+ llmName = v;
509
+ hasUserLlm = true;
510
+ }
511
+ const ov = v;
512
+ if (apdef.value.id || apdef.value.ref || apdef.value.array) {
513
+ v = `"${v}"`;
514
+ } else if (apdef.value.str) {
515
+ v = `"${escapeSpecialChars(v)}"`;
516
+ }
517
+ attrsStrs.push(`${apdef.name} ${v}`);
518
+ attrs.set(apdef.name, ov);
481
519
  }
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
520
  });
498
521
  if (!attrs.has('llm')) {
499
522
  llmName = `${name}_llm`;
@@ -505,14 +528,64 @@ async function addAgentDefinition(def: AgentDefinition, moduleName: string) {
505
528
  }, @upsert}`;
506
529
  let wf = createAgent;
507
530
  if (llmName) {
508
- wf = `{${CoreAIModuleName}/${LlmEntityName} {name "${llmName}"}, @upsert}; ${wf}`;
531
+ const service = process.env.ANTHROPIC_API_KEY ? 'anthropic' : 'openai';
532
+ wf = `{${CoreAIModuleName}/${LlmEntityName} {name "${llmName}", service "${service}"}, @upsert}; ${wf}`;
509
533
  }
510
534
  (await parseWorkflow(`workflow A {${wf}}`)).statements.forEach((stmt: Statement) => {
511
- addStandaloneStatement(stmt, moduleName);
535
+ addStandaloneStatement(stmt, moduleName, false);
512
536
  });
513
537
  addAgent(def.name, attrs, moduleName);
514
538
  }
515
539
 
540
+ function processAgentArray(array: ArrayLiteral, attrName: string): string {
541
+ return array.vals
542
+ .map((stmt: Statement) => {
543
+ const expr = stmt.pattern.expr;
544
+ return processAgentArrayValue(expr, attrName);
545
+ })
546
+ .join(',');
547
+ }
548
+
549
+ function processAgentArrayValue(expr: Expr | undefined, attrName: string): string {
550
+ if (expr && isLiteral(expr)) {
551
+ const s = expr.str || expr.id || expr.ref || expr.bool;
552
+ if (s != undefined) {
553
+ return s;
554
+ }
555
+ if (expr.array) {
556
+ return processAgentArray(expr.array, attrName);
557
+ } else if (expr.map) {
558
+ const m = new Array<string>();
559
+ expr.map.entries.forEach((me: MapEntry) => {
560
+ m.push(
561
+ `${me.key.str || me.key.num || me.key.bool || ''}: ${processAgentArrayValue(me.value, attrName)}`
562
+ );
563
+ });
564
+ return `{${m.join(',')}}`;
565
+ } else {
566
+ throw new Error(`Type not supprted in agent-arrays - ${attrName}`);
567
+ }
568
+ } else {
569
+ throw new Error(`Invalid value in array passed to agent ${attrName}`);
570
+ }
571
+ }
572
+
573
+ function addFlowDefinition(def: FlowDefinition, moduleName: string) {
574
+ if (def.body && def.$cstNode) {
575
+ const m = fetchModule(moduleName);
576
+ const sdef = def.$cstNode.text;
577
+ const idx = sdef.indexOf('{');
578
+ let f = '';
579
+ if (idx > 0) {
580
+ f = sdef.substring(idx + 1, sdef.lastIndexOf('}')).trim();
581
+ } else {
582
+ f = sdef;
583
+ }
584
+ m.addFlow(def.name, f);
585
+ registerFlow(`${moduleName}/${def.name}`, f);
586
+ }
587
+ }
588
+
516
589
  function addResolverDefinition(def: ResolverDefinition, moduleName: string) {
517
590
  const resolverName = `${moduleName}/${def.name}`;
518
591
  const paths = def.paths;
@@ -571,6 +644,7 @@ export async function addFromDef(def: Definition, moduleName: string) {
571
644
  else if (isAgentDefinition(def)) await addAgentDefinition(def, moduleName);
572
645
  else if (isStandaloneStatement(def)) addStandaloneStatement(def.stmt, moduleName);
573
646
  else if (isResolverDefinition(def)) addResolverDefinition(def, moduleName);
647
+ else if (isFlowDefinition(def)) addFlowDefinition(def, moduleName);
574
648
  }
575
649
 
576
650
  export async function parseAndIntern(code: string, moduleName?: string) {