agentlang 0.9.5 → 0.9.7

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 (122) hide show
  1. package/out/cli/main.d.ts.map +1 -1
  2. package/out/cli/main.js +8 -3
  3. package/out/cli/main.js.map +1 -1
  4. package/out/language/generated/ast.d.ts +80 -3
  5. package/out/language/generated/ast.d.ts.map +1 -1
  6. package/out/language/generated/ast.js +62 -0
  7. package/out/language/generated/ast.js.map +1 -1
  8. package/out/language/generated/grammar.d.ts.map +1 -1
  9. package/out/language/generated/grammar.js +432 -218
  10. package/out/language/generated/grammar.js.map +1 -1
  11. package/out/language/main.cjs +485 -218
  12. package/out/language/main.cjs.map +2 -2
  13. package/out/language/parser.js +8 -8
  14. package/out/language/parser.js.map +1 -1
  15. package/out/runtime/agents/common.d.ts +7 -1
  16. package/out/runtime/agents/common.d.ts.map +1 -1
  17. package/out/runtime/agents/common.js +101 -0
  18. package/out/runtime/agents/common.js.map +1 -1
  19. package/out/runtime/agents/impl/anthropic.js +4 -4
  20. package/out/runtime/agents/impl/anthropic.js.map +1 -1
  21. package/out/runtime/agents/impl/openai.js +4 -4
  22. package/out/runtime/agents/impl/openai.js.map +1 -1
  23. package/out/runtime/docs.d.ts.map +1 -1
  24. package/out/runtime/docs.js +109 -7
  25. package/out/runtime/docs.js.map +1 -1
  26. package/out/runtime/embeddings/chunker.d.ts +9 -0
  27. package/out/runtime/embeddings/chunker.d.ts.map +1 -0
  28. package/out/runtime/embeddings/chunker.js +41 -0
  29. package/out/runtime/embeddings/chunker.js.map +1 -0
  30. package/out/runtime/embeddings/index.d.ts +6 -0
  31. package/out/runtime/embeddings/index.d.ts.map +1 -0
  32. package/out/runtime/embeddings/index.js +6 -0
  33. package/out/runtime/embeddings/index.js.map +1 -0
  34. package/out/runtime/embeddings/openai.d.ts +15 -0
  35. package/out/runtime/embeddings/openai.d.ts.map +1 -0
  36. package/out/runtime/embeddings/openai.js +34 -0
  37. package/out/runtime/embeddings/openai.js.map +1 -0
  38. package/out/runtime/embeddings/provider.d.ts +20 -0
  39. package/out/runtime/embeddings/provider.d.ts.map +1 -0
  40. package/out/runtime/embeddings/provider.js +17 -0
  41. package/out/runtime/embeddings/provider.js.map +1 -0
  42. package/out/runtime/embeddings/registry.d.ts +3 -0
  43. package/out/runtime/embeddings/registry.d.ts.map +1 -0
  44. package/out/runtime/embeddings/registry.js +16 -0
  45. package/out/runtime/embeddings/registry.js.map +1 -0
  46. package/out/runtime/exec-graph.d.ts.map +1 -1
  47. package/out/runtime/exec-graph.js +5 -0
  48. package/out/runtime/exec-graph.js.map +1 -1
  49. package/out/runtime/interpreter.d.ts +4 -0
  50. package/out/runtime/interpreter.d.ts.map +1 -1
  51. package/out/runtime/interpreter.js +27 -7
  52. package/out/runtime/interpreter.js.map +1 -1
  53. package/out/runtime/loader.d.ts.map +1 -1
  54. package/out/runtime/loader.js +42 -5
  55. package/out/runtime/loader.js.map +1 -1
  56. package/out/runtime/module.d.ts +22 -4
  57. package/out/runtime/module.d.ts.map +1 -1
  58. package/out/runtime/module.js +76 -10
  59. package/out/runtime/module.js.map +1 -1
  60. package/out/runtime/modules/ai.d.ts +20 -2
  61. package/out/runtime/modules/ai.d.ts.map +1 -1
  62. package/out/runtime/modules/ai.js +333 -37
  63. package/out/runtime/modules/ai.js.map +1 -1
  64. package/out/runtime/modules/auth.d.ts.map +1 -1
  65. package/out/runtime/modules/auth.js +11 -5
  66. package/out/runtime/modules/auth.js.map +1 -1
  67. package/out/runtime/resolvers/interface.d.ts +1 -1
  68. package/out/runtime/resolvers/interface.d.ts.map +1 -1
  69. package/out/runtime/resolvers/interface.js.map +1 -1
  70. package/out/runtime/resolvers/sqldb/database.d.ts +1 -1
  71. package/out/runtime/resolvers/sqldb/database.d.ts.map +1 -1
  72. package/out/runtime/resolvers/sqldb/database.js +139 -50
  73. package/out/runtime/resolvers/sqldb/database.js.map +1 -1
  74. package/out/runtime/resolvers/sqldb/impl.d.ts +22 -2
  75. package/out/runtime/resolvers/sqldb/impl.d.ts.map +1 -1
  76. package/out/runtime/resolvers/sqldb/impl.js +178 -47
  77. package/out/runtime/resolvers/sqldb/impl.js.map +1 -1
  78. package/out/runtime/state.d.ts +1 -0
  79. package/out/runtime/state.d.ts.map +1 -1
  80. package/out/runtime/state.js +3 -0
  81. package/out/runtime/state.js.map +1 -1
  82. package/out/syntaxes/agentlang.monarch.js +1 -1
  83. package/out/syntaxes/agentlang.monarch.js.map +1 -1
  84. package/package.json +188 -185
  85. package/public/pdf.worker.mjs +65152 -0
  86. package/src/cli/main.ts +7 -2
  87. package/src/language/agentlang.langium +8 -2
  88. package/src/language/generated/ast.ts +96 -2
  89. package/src/language/generated/grammar.ts +432 -218
  90. package/src/language/parser.ts +8 -8
  91. package/src/runtime/agents/common.ts +107 -0
  92. package/src/runtime/agents/impl/anthropic.ts +4 -4
  93. package/src/runtime/agents/impl/openai.ts +4 -4
  94. package/src/runtime/docs.ts +120 -9
  95. package/src/runtime/embeddings/chunker.ts +50 -0
  96. package/src/runtime/embeddings/index.ts +5 -0
  97. package/src/runtime/embeddings/openai.ts +49 -0
  98. package/src/runtime/embeddings/provider.ts +37 -0
  99. package/src/runtime/embeddings/registry.ts +17 -0
  100. package/src/runtime/exec-graph.ts +4 -0
  101. package/src/runtime/interpreter.ts +39 -16
  102. package/src/runtime/loader.ts +42 -3
  103. package/src/runtime/module.ts +127 -41
  104. package/src/runtime/modules/ai.ts +467 -38
  105. package/src/runtime/modules/auth.ts +11 -5
  106. package/src/runtime/resolvers/interface.ts +1 -1
  107. package/src/runtime/resolvers/sqldb/database.ts +146 -56
  108. package/src/runtime/resolvers/sqldb/impl.ts +238 -61
  109. package/src/runtime/state.ts +4 -0
  110. package/src/syntaxes/agentlang.monarch.ts +1 -1
  111. package/out/setupClassic.d.ts +0 -98
  112. package/out/setupClassic.d.ts.map +0 -1
  113. package/out/setupClassic.js +0 -38
  114. package/out/setupClassic.js.map +0 -1
  115. package/out/setupCommon.d.ts +0 -2
  116. package/out/setupCommon.d.ts.map +0 -1
  117. package/out/setupCommon.js +0 -33
  118. package/out/setupCommon.js.map +0 -1
  119. package/out/setupExtended.d.ts +0 -40
  120. package/out/setupExtended.d.ts.map +0 -1
  121. package/out/setupExtended.js +0 -67
  122. package/out/setupExtended.js.map +0 -1
@@ -5,6 +5,7 @@ import {
5
5
  makeCoreModuleName,
6
6
  makeFqName,
7
7
  nameToPath,
8
+ restoreSpecialChars,
8
9
  sleepMilliseconds,
9
10
  splitFqName,
10
11
  } from '../util.js';
@@ -15,6 +16,7 @@ import {
15
16
  parseAndEvaluateStatement,
16
17
  } from '../interpreter.js';
17
18
  import {
19
+ AgentEvaluator,
18
20
  asJSONSchema,
19
21
  Decision,
20
22
  fetchModule,
@@ -38,24 +40,26 @@ import {
38
40
  humanMessage,
39
41
  systemMessage,
40
42
  } from '../agents/provider.js';
41
- import { AIMessage, BaseMessage, HumanMessage } from '@langchain/core/messages';
43
+ import { AIMessage, BaseMessage, HumanMessage, SystemMessage } from '@langchain/core/messages';
42
44
  import {
43
45
  AgentCondition,
44
46
  AgentGlossaryEntry,
45
47
  AgentScenario,
48
+ AgentSummary as AgentLearningResult,
46
49
  DecisionAgentInstructions,
50
+ EvalInstructions,
47
51
  FlowExecInstructions,
48
52
  getAgentDirectives,
49
53
  getAgentGlossary,
50
54
  getAgentResponseSchema,
51
55
  getAgentScenarios,
52
56
  getAgentScratchNames,
57
+ LearningAgentInstructions as LearnerAgentInstructions,
53
58
  newAgentDirective,
54
59
  newAgentGlossaryEntry,
55
60
  newAgentScenario,
56
61
  PlannerInstructions,
57
62
  } from '../agents/common.js';
58
- import { PathAttributeNameQuery } from '../defs.js';
59
63
  import { logger } from '../logger.js';
60
64
  import { FlowStep } from '../agents/flows.js';
61
65
  import Handlebars from 'handlebars';
@@ -65,9 +69,14 @@ import { isMonitoringEnabled, TtlCache } from '../state.js';
65
69
  export const CoreAIModuleName = makeCoreModuleName('ai');
66
70
  export const AgentEntityName = 'Agent';
67
71
  export const LlmEntityName = 'LLM';
72
+ export const AgentLearnerType = 'learner';
73
+
74
+ const AgentEvalType = 'eval';
68
75
 
69
76
  export default `module ${CoreAIModuleName}
70
77
 
78
+ import "./modules/ai.js" @as ai
79
+
71
80
  entity ${LlmEntityName} {
72
81
  name String @id,
73
82
  service String @default("openai"),
@@ -77,7 +86,7 @@ entity ${LlmEntityName} {
77
86
  entity ${AgentEntityName} {
78
87
  name String @id,
79
88
  moduleName String @default("${CoreAIModuleName}"),
80
- type @enum("chat", "planner", "flow-exec") @default("chat"),
89
+ type @enum("chat", "planner", "flow-exec", "${AgentEvalType}", "${AgentLearnerType}") @default("chat"),
81
90
  runWorkflows Boolean @default(true),
82
91
  instruction String @optional,
83
92
  tools String @optional, // comma-separated list of tool names
@@ -136,8 +145,122 @@ entity GlossaryEntry {
136
145
  meaning String,
137
146
  synonyms String @optional
138
147
  }
148
+
149
+ entity EvaluationResult {
150
+ id UUID @id @default(uuid()),
151
+ agentFqName String @indexed,
152
+ userRequest String,
153
+ score Int,
154
+ summary String
155
+ }
156
+
157
+ entity AgentLearningResult {
158
+ id UUID @id @default(uuid()),
159
+ agentFqName String @indexed,
160
+ data String,
161
+ summary String
162
+ }
163
+
164
+ @public event agentLearning{
165
+ agentName String,
166
+ agentModuleName String,
167
+ instruction String
168
+ }
169
+
170
+ workflow agentLearning {
171
+ await ai.processAgentLearning(agentLearning.agentModuleName, agentLearning.agentName, agentLearning.instruction)
172
+ }
139
173
  `;
140
174
 
175
+ enum AgentCacheType {
176
+ DIRECTIVE,
177
+ GLOSSARY,
178
+ SCENARIO,
179
+ SUMMARY,
180
+ }
181
+
182
+ type AgentInstructionActivator = {
183
+ provider: AgentServiceProvider;
184
+ userMessage: string;
185
+ agentInstruction: string;
186
+ agentRole: string | undefined;
187
+ };
188
+
189
+ const MAX_USER_DEFINED_GLOSSARY = 20;
190
+ const MAX_USER_DEFINED_DIRECTIVES = 20;
191
+ const MAX_USER_DEFINED_SCENARIOS = 5;
192
+ const MAX_USER_DEFINED_SUMMARIES = 5;
193
+
194
+ async function activatedUserDefinedAgentLearnings<T>(
195
+ objLabel: string,
196
+ learningObjects: T[],
197
+ activator: AgentInstructionActivator,
198
+ maxResults: number
199
+ ): Promise<T[]> {
200
+ const msg = `Consider the following ${objLabel} (in JSON format):
201
+ ${JSON.stringify(learningObjects)}
202
+
203
+ Return the indices of the ${objLabel} relevant for the following text:
204
+
205
+ ${activator.userMessage}
206
+
207
+ Return the relevant indices and a JSON array of integers with the index starting at zero (0). Do not return any additional comments
208
+ or text.
209
+ `;
210
+ const msgs = new Array<BaseMessage>();
211
+ msgs.push(
212
+ new SystemMessage(
213
+ 'You are an agent that filters a JSON array and return relevant indices as a JSON array of integers.'
214
+ )
215
+ );
216
+ msgs.push(new HumanMessage(msg));
217
+ const response: AIResponse = await activator.provider.invoke(msgs, undefined);
218
+ const indices: number[] = JSON.parse(normalizeGeneratedCode(response.content));
219
+ if (indices.length == 0 || indices.length == learningObjects.length) return learningObjects;
220
+ const result = new Array<T>();
221
+ for (let i = 0; i < indices.length; ++i) {
222
+ if (i >= maxResults) break;
223
+ result.push(learningObjects[indices[i]]);
224
+ }
225
+ return result;
226
+ }
227
+
228
+ async function activatedUserDefinedAgentGlossary(
229
+ gls: AgentGlossaryEntry[],
230
+ activator: AgentInstructionActivator
231
+ ): Promise<AgentGlossaryEntry[]> {
232
+ return await activatedUserDefinedAgentLearnings<AgentGlossaryEntry>(
233
+ 'glossary entries',
234
+ gls,
235
+ activator,
236
+ MAX_USER_DEFINED_GLOSSARY
237
+ );
238
+ }
239
+
240
+ async function activatedUserDefinedAgentScenarios(
241
+ scns: AgentScenario[],
242
+ activator: AgentInstructionActivator
243
+ ): Promise<AgentScenario[]> {
244
+ return await activatedUserDefinedAgentLearnings<AgentScenario>(
245
+ 'scenarios',
246
+ scns,
247
+ activator,
248
+ MAX_USER_DEFINED_SCENARIOS
249
+ );
250
+ }
251
+
252
+ async function activatedUserDefinedAgentDirectives(
253
+ dirs: AgentCondition[],
254
+ activator: AgentInstructionActivator
255
+ ): Promise<AgentCondition[]> {
256
+ return await activatedUserDefinedAgentLearnings<AgentCondition>(
257
+ 'directives or conditions',
258
+ dirs,
259
+ activator,
260
+ MAX_USER_DEFINED_DIRECTIVES
261
+ );
262
+ }
263
+
141
264
  export const AgentFqName = makeFqName(CoreAIModuleName, AgentEntityName);
142
265
 
143
266
  const ProviderDb = new Map<string, AgentServiceProvider>();
@@ -276,10 +399,18 @@ export class AgentInstance {
276
399
  return this.hasModuleTools || this.type == 'planner';
277
400
  }
278
401
 
402
+ isLearner(): boolean {
403
+ return this.type === 'learner';
404
+ }
405
+
279
406
  isFlowExecutor(): boolean {
280
407
  return this.type == 'flow-exec';
281
408
  }
282
409
 
410
+ isEvaluator(): boolean {
411
+ return this.type == AgentEvalType;
412
+ }
413
+
283
414
  markAsDecisionExecutor(): AgentInstance {
284
415
  this.decisionExecutor = true;
285
416
  return this;
@@ -301,14 +432,22 @@ export class AgentInstance {
301
432
  let r: AgentCondition[] = [];
302
433
  if (result && result.length > 0) {
303
434
  r = result.map((inst: Instance) => {
304
- return newAgentDirective(inst.lookup('condition'), inst.lookup('consequent'));
435
+ return newAgentDirective(
436
+ restoreSpecialChars(inst.lookup('condition')),
437
+ restoreSpecialChars(inst.lookup('consequent'))
438
+ );
305
439
  });
306
440
  }
307
441
  return AgentInstance.DirectivesCache.set(fqName, r);
308
442
  }
309
443
 
310
- private async directivesAsString(fqName: string): Promise<string> {
311
- const userDirs = await this.getUserDefinedAgentDirectives(fqName);
444
+ private async directivesAsString(
445
+ fqName: string,
446
+ activator: AgentInstructionActivator
447
+ ): Promise<string> {
448
+ let userDirs = await this.getUserDefinedAgentDirectives(fqName);
449
+ if (userDirs.length > MAX_USER_DEFINED_DIRECTIVES)
450
+ userDirs = await activatedUserDefinedAgentDirectives(userDirs, activator);
312
451
  const dirs = getAgentDirectives(fqName) || [];
313
452
  const conds = dirs.concat(userDirs);
314
453
  if (conds.length > 0) {
@@ -341,7 +480,7 @@ export class AgentInstance {
341
480
  r = result.map((inst: Instance) => {
342
481
  return newAgentGlossaryEntry(
343
482
  inst.lookup('name'),
344
- inst.lookup('meaning'),
483
+ restoreSpecialChars(inst.lookup('meaning')),
345
484
  inst.lookup('synonyms')
346
485
  );
347
486
  });
@@ -349,6 +488,23 @@ export class AgentInstance {
349
488
  return AgentInstance.GlossaryCache.set(fqName, r);
350
489
  }
351
490
 
491
+ private static SummariesCache = new TtlCache<AgentLearningResult[]>(AgentInstance.CACHE_TTL_MS);
492
+
493
+ private async getUserDefinedAgentLearningResults(fqName: string): Promise<AgentLearningResult[]> {
494
+ const cached = AgentInstance.SummariesCache.get(fqName);
495
+ if (cached !== undefined) return cached;
496
+ const result: Instance[] = await parseAndEvaluateStatement(
497
+ `{${CoreAIModuleName}/AgentLearningResult {agentFqName? "${fqName}"}}`
498
+ );
499
+ let r: AgentLearningResult[] = [];
500
+ if (result && result.length > 0) {
501
+ r = result.map((inst: Instance) => {
502
+ return { data: inst.lookup('data'), summary: inst.lookup('summary') };
503
+ });
504
+ }
505
+ return AgentInstance.SummariesCache.set(fqName, r);
506
+ }
507
+
352
508
  private static ScenariosCache = new TtlCache<AgentScenario[]>(AgentInstance.CACHE_TTL_MS);
353
509
 
354
510
  private async getUserDefinedAgentScenarios(fqName: string): Promise<AgentScenario[]> {
@@ -366,12 +522,34 @@ export class AgentInstance {
366
522
  return AgentInstance.ScenariosCache.set(fqName, r);
367
523
  }
368
524
 
369
- private async getFullInstructions(env: Environment): Promise<string> {
525
+ public static ResetCache(fqName: string, type: AgentCacheType) {
526
+ switch (type) {
527
+ case AgentCacheType.DIRECTIVE:
528
+ AgentInstance.DirectivesCache.delete(fqName);
529
+ break;
530
+ case AgentCacheType.GLOSSARY:
531
+ AgentInstance.GlossaryCache.delete(fqName);
532
+ break;
533
+ case AgentCacheType.SCENARIO:
534
+ AgentInstance.ScenariosCache.delete(fqName);
535
+ break;
536
+ case AgentCacheType.SUMMARY:
537
+ AgentInstance.SummariesCache.delete(fqName);
538
+ break;
539
+ }
540
+ }
541
+
542
+ private async getFullInstructions(
543
+ env: Environment,
544
+ activator: AgentInstructionActivator
545
+ ): Promise<string> {
370
546
  const fqName = this.getFqName();
371
547
  const ins = this.role ? `${this.role}\n${this.instruction || ''}` : this.instruction || '';
372
- let finalInstruction = `${ins} ${await this.directivesAsString(fqName)}`;
548
+ let finalInstruction = `${ins} ${await this.directivesAsString(fqName, activator)}`;
373
549
  const staticGls = getAgentGlossary(fqName) || [];
374
- const userGls = await this.getUserDefinedAgentGlossary(fqName);
550
+ let userGls = await this.getUserDefinedAgentGlossary(fqName);
551
+ if (userGls.length > MAX_USER_DEFINED_GLOSSARY)
552
+ userGls = await activatedUserDefinedAgentGlossary(userGls, activator);
375
553
  const gls = staticGls.concat(userGls);
376
554
  if (gls.length > 0) {
377
555
  const glss = new Array<string>();
@@ -384,7 +562,9 @@ export class AgentInstance {
384
562
  ${glss.join('\n')}\n`;
385
563
  }
386
564
  const staticScns = getAgentScenarios(fqName) || [];
387
- const userScns = await this.getUserDefinedAgentScenarios(fqName);
565
+ let userScns = await this.getUserDefinedAgentScenarios(fqName);
566
+ if (userScns.length > MAX_USER_DEFINED_SCENARIOS)
567
+ userScns = await activatedUserDefinedAgentScenarios(userScns, activator);
388
568
  const scenarios = staticScns.concat(userScns);
389
569
  if (scenarios.length > 0) {
390
570
  const scs = new Array<string>();
@@ -398,6 +578,20 @@ export class AgentInstance {
398
578
  });
399
579
  finalInstruction = `${finalInstruction}\nHere are some example user requests and the corresponding responses you are supposed to produce:\n${scs.join('\n')}`;
400
580
  }
581
+ const summaries = await this.getUserDefinedAgentLearningResults(fqName);
582
+ if (summaries.length > 0) {
583
+ let s: string[] = summaries.map((sa: AgentLearningResult) => {
584
+ return restoreSpecialChars(sa.summary);
585
+ });
586
+ if (s.length > MAX_USER_DEFINED_SUMMARIES)
587
+ s = await activatedUserDefinedAgentLearnings<string>(
588
+ 'summaries',
589
+ s,
590
+ activator,
591
+ MAX_USER_DEFINED_SUMMARIES
592
+ );
593
+ finalInstruction = `${finalInstruction}\nAlso keep in mind the following points:\n\n${s.join('\n')}\n\n`;
594
+ }
401
595
  const responseSchema = getAgentResponseSchema(fqName);
402
596
  if (responseSchema) {
403
597
  finalInstruction = `${finalInstruction}\nReturn your response in the following JSON schema:\n${asJSONSchema(responseSchema)}
@@ -430,7 +624,7 @@ Only return a pure JSON object with no extra text, annotations etc.`;
430
624
  if (response) {
431
625
  const responseSchema = getAgentResponseSchema(this.getFqName());
432
626
  if (responseSchema) {
433
- const attrs = JSON.parse(trimGeneratedCode(response));
627
+ const attrs = JSON.parse(normalizeGeneratedCode(response));
434
628
  const parts = nameToPath(responseSchema);
435
629
  const moduleName = parts.getModuleName();
436
630
  const entryName = parts.getEntryName();
@@ -495,16 +689,78 @@ Only return a pure JSON object with no extra text, annotations etc.`;
495
689
  return this;
496
690
  }
497
691
 
692
+ private static AgentEvaluators = new Map<string, AgentInstance>();
693
+
694
+ public static RegisterEvaluator(e: AgentEvaluator): AgentInstance {
695
+ const n = e.normalizedName();
696
+ const agentFqName = isFqName(n) ? n : makeFqName(e.moduleName, n);
697
+ const instruction = e.instruction;
698
+ let llm = e.llm;
699
+ const [agentModule, agentName] = splitFqName(agentFqName);
700
+ if (llm === undefined) llm = `${agentName}_llm`;
701
+ const inst = makeInstance(
702
+ CoreAIModuleName,
703
+ AgentEntityName,
704
+ newInstanceAttributes()
705
+ .set('llm', llm)
706
+ .set('name', agentName)
707
+ .set('moduleName', agentModule)
708
+ .set(
709
+ 'instruction',
710
+ instruction || 'You are an agent that evaluates the performance of another agent.'
711
+ )
712
+ .set('type', AgentEvalType)
713
+ );
714
+ const einst = AgentInstance.FromInstance(inst).disableSession();
715
+ this.AgentEvaluators.set(agentFqName, einst);
716
+ return einst;
717
+ }
718
+
719
+ private static async maybeEvaluateResponse(
720
+ agent: AgentInstance,
721
+ userRequest: string,
722
+ fullRequest: string,
723
+ response: string,
724
+ env: Environment
725
+ ): Promise<void> {
726
+ const fqn = agent.getFqName();
727
+ const e: AgentInstance | undefined = AgentInstance.AgentEvaluators.get(fqn);
728
+ if (e !== undefined) {
729
+ await e.invoke(
730
+ JSON.stringify({ requestToAgent: fullRequest, responseFromAgent: response }),
731
+ env
732
+ );
733
+ try {
734
+ const r = JSON.parse(normalizeGeneratedCode(env.getLastResult()));
735
+ const score = r.score;
736
+ if (score === undefined || score === null) {
737
+ logger.warn(`Evaluation for agent ${fqn} failed to generate a valid score`);
738
+ } else {
739
+ await parseAndEvaluateStatement(`{${CoreAIModuleName}/EvaluationResult {
740
+ agentFqName "${fqn}",
741
+ userRequest "${escapeSpecialChars(userRequest)}",
742
+ score ${score},
743
+ summary "${escapeSpecialChars(r.summary)}"
744
+ }}`);
745
+ }
746
+ } catch (reason: any) {
747
+ logger.warn(`Failed to save evaluation for agent ${fqn} - ${reason}`);
748
+ }
749
+ }
750
+ }
751
+
498
752
  async invoke(message: string, env: Environment) {
499
753
  const p = await findProviderForLLM(this.llm, env);
500
754
  const agentName = this.name;
501
755
  const chatId = env.getAgentChatId() || agentName;
502
756
  let isplnr = this.isPlanner();
503
757
  const isflow = !isplnr && this.isFlowExecutor();
504
- if (isplnr && this.withSession) {
758
+ const iseval = !isplnr && !isflow && this.isEvaluator();
759
+ const islearner = !isflow && !isplnr && !iseval && this.isLearner();
760
+ if ((isplnr || islearner || iseval) && this.withSession) {
505
761
  this.withSession = false;
506
762
  }
507
- if (isflow) {
763
+ if (isflow || islearner) {
508
764
  this.withSession = false;
509
765
  }
510
766
  if (this.withSession && env.getFlowContext()) {
@@ -520,19 +776,31 @@ Only return a pure JSON object with no extra text, annotations etc.`;
520
776
  const sess: Instance | null = this.withSession ? await findAgentChatSession(chatId, env) : null;
521
777
  let msgs: BaseMessage[] | undefined;
522
778
  let cachedMsg: string | undefined = undefined;
779
+ const activator: AgentInstructionActivator = {
780
+ provider: p,
781
+ userMessage: message,
782
+ agentInstruction: this.instruction,
783
+ agentRole: this.role,
784
+ };
523
785
  if (sess) {
524
786
  msgs = sess.lookup('messages');
525
787
  } else {
526
- cachedMsg = await this.getFullInstructions(env);
788
+ cachedMsg = await this.getFullInstructions(env, activator);
527
789
  msgs = [systemMessage(cachedMsg || '')];
528
790
  }
529
791
  if (msgs) {
530
792
  try {
531
793
  const sysMsg = msgs[0];
532
- if (isplnr || isflow) {
533
- const s = isplnr ? PlannerInstructions : FlowExecInstructions;
794
+ if (isplnr || isflow || iseval || islearner) {
795
+ const s = isplnr
796
+ ? PlannerInstructions
797
+ : isflow
798
+ ? FlowExecInstructions
799
+ : iseval
800
+ ? EvalInstructions
801
+ : LearnerAgentInstructions;
534
802
  const ts = this.toolsAsString();
535
- const msg = `${s}\n${ts}\n${cachedMsg || (await this.getFullInstructions(env))}`;
803
+ const msg = `${s}\n${ts}\n${cachedMsg || (await this.getFullInstructions(env, activator))}`;
536
804
  const newSysMsg = systemMessage(msg);
537
805
  msgs[0] = newSysMsg;
538
806
  }
@@ -570,6 +838,14 @@ Only return a pure JSON object with no extra text, annotations etc.`;
570
838
  if (v) {
571
839
  response = await this.handleValidation(response, v, msgs, p);
572
840
  }
841
+ if (!iseval)
842
+ await AgentInstance.maybeEvaluateResponse(
843
+ this,
844
+ message,
845
+ msgsContent,
846
+ response.content,
847
+ env
848
+ );
573
849
  msgs.push(assistantMessage(response.content));
574
850
  if (isplnr) {
575
851
  msgs[0] = sysMsg;
@@ -606,7 +882,7 @@ Only return a pure JSON object with no extra text, annotations etc.`;
606
882
  validationEventName: string
607
883
  ): Promise<Instance> {
608
884
  let isstr = true;
609
- const content = trimGeneratedCode(response.content);
885
+ const content = normalizeGeneratedCode(response.content);
610
886
  try {
611
887
  const c = JSON.parse(content);
612
888
  isstr = isString(c);
@@ -703,34 +979,92 @@ Only return a pure JSON object with no extra text, annotations etc.`;
703
979
 
704
980
  private async maybeAddRelevantDocuments(message: string, env: Environment): Promise<string> {
705
981
  if (this.documents && this.documents.length > 0) {
706
- const s = `${message}. Relevant documents are: ${this.documents}`;
707
- const result: any[] = await parseHelper(`{${CoreAIModuleName}/Document? "${s}"}`, env);
708
- if (result && result.length > 0) {
709
- const docs: Instance[] = [];
710
- for (let i = 0; i < result.length; ++i) {
711
- const v: any = result[i];
712
- const r: Instance[] = await parseHelper(
713
- `{${CoreAIModuleName}/Document {${PathAttributeNameQuery} "${v.id}"}}`,
982
+ try {
983
+ const docNames = this.documents.split(',').map(d => d.trim());
984
+
985
+ const searchQuery = message;
986
+
987
+ try {
988
+ const semanticResult: any[] = await parseHelper(
989
+ `{${CoreAIModuleName}/Document {content? "${searchQuery.replace(/"/g, '\\"')}"}}`,
714
990
  env
715
991
  );
716
- if (r && r.length > 0) {
717
- docs.push(r[0]);
992
+
993
+ if (semanticResult && semanticResult.length > 0) {
994
+ const docs: Instance[] = [];
995
+ for (const doc of semanticResult) {
996
+ const docTitle = doc.lookup ? doc.lookup('title') : doc.title;
997
+ if (AgentInstance.docTitlesMatch(docTitle, docNames)) {
998
+ docs.push(
999
+ doc instanceof Instance
1000
+ ? doc
1001
+ : Instance.newWithAttributes(doc, new Map(Object.entries(doc)))
1002
+ );
1003
+ }
1004
+ }
1005
+
1006
+ if (docs.length > 0) {
1007
+ return message.concat('\n\nRelevant context from documents:\n').concat(
1008
+ docs
1009
+ .map((v: Instance) => {
1010
+ return `Document: ${v.lookup('title')}\n${v.lookup('content') as string}`;
1011
+ })
1012
+ .join('\n\n---\n\n')
1013
+ );
1014
+ }
718
1015
  }
719
- }
720
- if (docs.length > 0) {
721
- message = message.concat('\nUse the additional information given below:\n').concat(
722
- docs
723
- .map((v: Instance) => {
724
- return v.lookup('content');
725
- })
726
- .join('\n')
1016
+ } catch (semanticErr) {
1017
+ logger.debug(
1018
+ `Semantic search is not available, falling back to title-based filtering: ${semanticErr}`
727
1019
  );
728
1020
  }
1021
+
1022
+ const result: any[] = await parseHelper(`{${CoreAIModuleName}/Document? {}}`, env);
1023
+ if (result && result.length > 0) {
1024
+ const docs: Instance[] = [];
1025
+ for (let i = 0; i < result.length; ++i) {
1026
+ const v: any = result[i];
1027
+ const docTitle: string | undefined = AgentInstance.getDocumentTitle(v);
1028
+
1029
+ if (docTitle && docNames.includes(docTitle)) {
1030
+ if (v instanceof Instance) {
1031
+ docs.push(v);
1032
+ }
1033
+ }
1034
+ }
1035
+
1036
+ if (docs.length > 0) {
1037
+ return message.concat('\n\nRelevant context from documents:\n').concat(
1038
+ docs
1039
+ .map((v: Instance) => {
1040
+ return v.lookup('content') as string;
1041
+ })
1042
+ .join('\n\n')
1043
+ );
1044
+ }
1045
+ }
1046
+ } catch (err) {
1047
+ logger.debug(`Error retrieving documents: ${err}`);
729
1048
  }
730
1049
  }
731
1050
  return message;
732
1051
  }
733
1052
 
1053
+ private static docTitlesMatch(title: string | undefined, docNames: string[]): boolean {
1054
+ return title !== undefined && docNames.includes(title);
1055
+ }
1056
+
1057
+ private static getDocumentTitle(doc: any): string | undefined {
1058
+ if (typeof doc.lookup === 'function') {
1059
+ return doc.lookup('title') as string | undefined;
1060
+ } else if (doc.attributes) {
1061
+ return doc.attributes.get('title') as string | undefined;
1062
+ } else if (doc.title) {
1063
+ return doc.title;
1064
+ }
1065
+ return undefined;
1066
+ }
1067
+
734
1068
  private static ToolsCache = new Map<string, string>();
735
1069
 
736
1070
  private toolsAsString(): string {
@@ -920,7 +1254,7 @@ function processScenarioResponse(resp: string): string {
920
1254
  return resp;
921
1255
  }
922
1256
 
923
- export function trimGeneratedCode(code: string | undefined): string {
1257
+ export function normalizeGeneratedCode(code: string | undefined): string {
924
1258
  if (code !== undefined) {
925
1259
  let s = code.trim();
926
1260
  if (s.startsWith('```')) {
@@ -935,3 +1269,98 @@ export function trimGeneratedCode(code: string | undefined): string {
935
1269
  return '';
936
1270
  }
937
1271
  }
1272
+
1273
+ async function parseAndInternAgentLearning(
1274
+ moduleName: string,
1275
+ agentName: string,
1276
+ learning: string,
1277
+ env: Environment
1278
+ ) {
1279
+ const obj = JSON.parse(normalizeGeneratedCode(learning));
1280
+ const fqName = makeFqName(moduleName, agentName);
1281
+ if (obj.decisions) {
1282
+ for (let j = 0; j < obj.decisions.length; ++j) {
1283
+ const conds: any[] = obj.decisions[j].conditions;
1284
+ if (conds && conds.length > 0) {
1285
+ AgentInstance.ResetCache(fqName, AgentCacheType.DIRECTIVE);
1286
+ for (let i = 0; i < conds.length; ++i) {
1287
+ const entry: any = conds[i];
1288
+ const cond: string = entry.if;
1289
+ const conseq: string = entry.then;
1290
+ if (cond && conseq) {
1291
+ await parseAndEvaluateStatement(
1292
+ `{${CoreAIModuleName}/Directive {
1293
+ agentFqName "${fqName}",
1294
+ condition "${escapeSpecialChars(cond)}",
1295
+ consequent "${escapeSpecialChars(conseq)}"}}`,
1296
+ env.getActiveUser(),
1297
+ env
1298
+ );
1299
+ } else {
1300
+ throw new Error(`Invalid directive generated - missing 'if' or 'then' in ${learning}`);
1301
+ }
1302
+ }
1303
+ }
1304
+ }
1305
+ }
1306
+ if (obj.glossary) {
1307
+ AgentInstance.ResetCache(fqName, AgentCacheType.GLOSSARY);
1308
+ for (let i = 0; i < obj.glossary.length; ++i) {
1309
+ const word = obj.glossary[i].word;
1310
+ const meaning = obj.glossary[i].meaning;
1311
+ if (word && meaning) {
1312
+ await parseAndEvaluateStatement(
1313
+ `{${CoreAIModuleName}/GlossaryEntry {
1314
+ agentFqName "${fqName}",
1315
+ name "${word}",
1316
+ meaning "${escapeSpecialChars(meaning)}"}}`,
1317
+ env.getActiveUser(),
1318
+ env
1319
+ );
1320
+ }
1321
+ }
1322
+ }
1323
+ if (obj.scenarios) {
1324
+ AgentInstance.ResetCache(fqName, AgentCacheType.SCENARIO);
1325
+ for (let i = 0; i < obj.scenarios.length; ++i) {
1326
+ const user = obj.scenarios[i].user;
1327
+ const ai = obj.scenarios[i].ai;
1328
+ if (user && ai) {
1329
+ await parseAndEvaluateStatement(
1330
+ `{${CoreAIModuleName}/Scenario {
1331
+ agentFqName "${fqName}",
1332
+ user "${escapeSpecialChars(user)}",
1333
+ ai "${escapeSpecialChars(ai)}"}}`,
1334
+ env.getActiveUser(),
1335
+ env
1336
+ );
1337
+ }
1338
+ }
1339
+ }
1340
+ AgentInstance.ResetCache(fqName, AgentCacheType.SUMMARY);
1341
+ const summary = obj.summary;
1342
+ delete obj.summary;
1343
+ await parseAndEvaluateStatement(
1344
+ `{${CoreAIModuleName}/AgentLearningResult {
1345
+ agentFqName "${fqName}",
1346
+ data "${escapeSpecialChars(JSON.stringify(obj))}",
1347
+ summary "${escapeSpecialChars(summary) || ''}"}}`,
1348
+ env.getActiveUser(),
1349
+ env
1350
+ );
1351
+ }
1352
+
1353
+ export async function processAgentLearning(
1354
+ moduleName: string,
1355
+ agentName: string,
1356
+ instruction: string,
1357
+ env: Environment
1358
+ ): Promise<any> {
1359
+ const learning = await parseAndEvaluateStatement(
1360
+ `{${moduleName}/${agentName}_${AgentLearnerType} {message \`${instruction}\`}}`,
1361
+ env.getActiveUser(),
1362
+ env
1363
+ );
1364
+ await parseAndInternAgentLearning(moduleName, agentName, learning, env);
1365
+ return { agentLearning: { result: learning } };
1366
+ }