agentlang 0.1.9 → 0.2.1

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 (67) hide show
  1. package/out/api/http.js +3 -3
  2. package/out/api/http.js.map +1 -1
  3. package/out/language/agentlang-validator.d.ts.map +1 -1
  4. package/out/language/agentlang-validator.js +3 -1
  5. package/out/language/agentlang-validator.js.map +1 -1
  6. package/out/language/generated/ast.d.ts +35 -9
  7. package/out/language/generated/ast.d.ts.map +1 -1
  8. package/out/language/generated/ast.js +40 -1
  9. package/out/language/generated/ast.js.map +1 -1
  10. package/out/language/generated/grammar.d.ts.map +1 -1
  11. package/out/language/generated/grammar.js +289 -120
  12. package/out/language/generated/grammar.js.map +1 -1
  13. package/out/language/main.cjs +323 -122
  14. package/out/language/main.cjs.map +2 -2
  15. package/out/language/parser.d.ts +1 -0
  16. package/out/language/parser.d.ts.map +1 -1
  17. package/out/language/parser.js +14 -13
  18. package/out/language/parser.js.map +1 -1
  19. package/out/runtime/agents/common.d.ts +2 -1
  20. package/out/runtime/agents/common.d.ts.map +1 -1
  21. package/out/runtime/agents/common.js +42 -3
  22. package/out/runtime/agents/common.js.map +1 -1
  23. package/out/runtime/exec-graph.d.ts.map +1 -1
  24. package/out/runtime/exec-graph.js +15 -7
  25. package/out/runtime/exec-graph.js.map +1 -1
  26. package/out/runtime/interpreter.d.ts +1 -0
  27. package/out/runtime/interpreter.d.ts.map +1 -1
  28. package/out/runtime/interpreter.js +76 -32
  29. package/out/runtime/interpreter.js.map +1 -1
  30. package/out/runtime/loader.d.ts.map +1 -1
  31. package/out/runtime/loader.js +16 -9
  32. package/out/runtime/loader.js.map +1 -1
  33. package/out/runtime/module.d.ts +15 -0
  34. package/out/runtime/module.d.ts.map +1 -1
  35. package/out/runtime/module.js +96 -24
  36. package/out/runtime/module.js.map +1 -1
  37. package/out/runtime/modules/ai.d.ts +7 -3
  38. package/out/runtime/modules/ai.d.ts.map +1 -1
  39. package/out/runtime/modules/ai.js +85 -22
  40. package/out/runtime/modules/ai.js.map +1 -1
  41. package/out/runtime/resolvers/interface.js +2 -2
  42. package/out/runtime/resolvers/interface.js.map +1 -1
  43. package/out/runtime/resolvers/sqldb/impl.js +2 -2
  44. package/out/runtime/resolvers/sqldb/impl.js.map +1 -1
  45. package/out/runtime/util.d.ts +2 -1
  46. package/out/runtime/util.d.ts.map +1 -1
  47. package/out/runtime/util.js +4 -1
  48. package/out/runtime/util.js.map +1 -1
  49. package/out/syntaxes/agentlang.monarch.js +3 -3
  50. package/out/syntaxes/agentlang.monarch.js.map +1 -1
  51. package/package.json +8 -6
  52. package/src/api/http.ts +3 -3
  53. package/src/language/agentlang-validator.ts +3 -1
  54. package/src/language/agentlang.langium +8 -2
  55. package/src/language/generated/ast.ts +80 -9
  56. package/src/language/generated/grammar.ts +289 -120
  57. package/src/language/parser.ts +15 -14
  58. package/src/runtime/agents/common.ts +43 -3
  59. package/src/runtime/exec-graph.ts +14 -7
  60. package/src/runtime/interpreter.ts +82 -32
  61. package/src/runtime/loader.ts +23 -8
  62. package/src/runtime/module.ts +111 -22
  63. package/src/runtime/modules/ai.ts +97 -23
  64. package/src/runtime/resolvers/interface.ts +2 -2
  65. package/src/runtime/resolvers/sqldb/impl.ts +2 -2
  66. package/src/runtime/util.ts +5 -1
  67. package/src/syntaxes/agentlang.monarch.ts +3 -3
@@ -23,7 +23,7 @@ import {
23
23
  } from '../language/generated/ast.js';
24
24
  import {
25
25
  Path,
26
- splitFqName,
26
+ nameToPath,
27
27
  isString,
28
28
  isNumber,
29
29
  isBoolean,
@@ -42,6 +42,7 @@ import {
42
42
  findUqCompositeAttributes,
43
43
  escapeFqName,
44
44
  encryptPassword,
45
+ splitFqName,
45
46
  } from './util.js';
46
47
  import { parseStatement } from '../language/parser.js';
47
48
  import { ActiveSessionInfo, AdminSession } from './auth/defs.js';
@@ -52,6 +53,7 @@ import {
52
53
  AgentCondition,
53
54
  AgentGlossaryEntry,
54
55
  AgentScenario,
56
+ getAgentDirectives,
55
57
  getAgentDirectivesJson,
56
58
  getAgentGlossary,
57
59
  getAgentResponseSchema,
@@ -295,7 +297,7 @@ export class Record extends ModuleEntry {
295
297
  let t: string | undefined = isArrayType ? a.arrayType : a.type;
296
298
  if (a.refSpec) {
297
299
  let fp = a.refSpec.ref;
298
- const rp = splitFqName(fp);
300
+ const rp = nameToPath(fp);
299
301
  if (!rp.hasModule()) {
300
302
  rp.setModuleName(this.moduleName);
301
303
  fp = rp.asFqName();
@@ -515,14 +517,34 @@ export class Record extends ModuleEntry {
515
517
  }
516
518
 
517
519
  override toString(): string {
520
+ return this.toString_();
521
+ }
522
+
523
+ toString_(internParentSchema: boolean = false): string {
518
524
  if (this.type == RecordType.EVENT && this.meta && this.meta.get(SystemDefinedEvent)) {
519
525
  return '';
520
526
  }
521
527
  let s: string = `${RecordType[this.type].toLowerCase()} ${this.name}`;
522
- if (this.parentEntryName) {
528
+ let scm: RecordSchema = this.schema;
529
+ if (this.parentEntryName && !internParentSchema) {
523
530
  s = s.concat(` extends ${this.parentEntryName}`);
531
+ scm = newRecordSchema();
532
+ let modName = this.moduleName;
533
+ let pname = this.parentEntryName;
534
+ if (isFqName(pname)) {
535
+ const parts = splitFqName(pname);
536
+ modName = parts[0];
537
+ pname = parts[1];
538
+ }
539
+ const p = fetchModule(modName).getEntry(pname) as Record;
540
+ const pks = new Set(p.schema.keys());
541
+ this.schema.forEach((v: AttributeSpec, n: string) => {
542
+ if (!pks.has(n)) {
543
+ scm.set(n, v);
544
+ }
545
+ });
524
546
  }
525
- let scms = recordSchemaToString(this.schema);
547
+ let scms = recordSchemaToString(scm);
526
548
  if (this.rbac && this.rbac.length > 0) {
527
549
  const rbs = this.rbac.map((rs: RbacSpecification) => {
528
550
  return rs.toString();
@@ -563,7 +585,7 @@ function fetchModuleByEntryName(
563
585
  suspectModuleName: string
564
586
  ): FetchModuleByEntryNameResult {
565
587
  if (isFqName(entryName)) {
566
- const path: Path = splitFqName(entryName);
588
+ const path: Path = nameToPath(entryName);
567
589
  entryName = path.getEntryName();
568
590
  suspectModuleName = path.getModuleName();
569
591
  }
@@ -623,7 +645,7 @@ function asPropertiesMap(props: PropertyDefinition[]): Map<string, any> | undefi
623
645
  function maybeProcessRefProperty(props: Map<string, any>): Map<string, any> {
624
646
  const v: string | undefined = props.get('ref');
625
647
  if (v != undefined) {
626
- const parts: Path = splitFqName(v);
648
+ const parts: Path = nameToPath(v);
627
649
  if (!parts.hasModule()) {
628
650
  parts.setModuleName(activeModule);
629
651
  }
@@ -902,26 +924,46 @@ export class Agent extends Record {
902
924
  return this.getStrings('flows');
903
925
  }
904
926
 
927
+ getAgentFqName(): string {
928
+ return makeFqName(this.moduleName, this.getName());
929
+ }
930
+
905
931
  setDirectives(conds: AgentCondition[]): Agent {
906
- registerAgentDirectives(this.getFqName(), conds);
932
+ registerAgentDirectives(this.getAgentFqName(), conds);
907
933
  return this;
908
934
  }
909
935
 
936
+ getDirectives(): AgentCondition[] | undefined {
937
+ return getAgentDirectives(this.getAgentFqName());
938
+ }
939
+
910
940
  setScenarios(scenarios: AgentScenario[]): Agent {
911
- registerAgentScenarios(this.getFqName(), scenarios);
941
+ registerAgentScenarios(this.getAgentFqName(), scenarios);
912
942
  return this;
913
943
  }
914
944
 
945
+ getScenarios(): AgentScenario[] | undefined {
946
+ return getAgentScenarios(this.getAgentFqName());
947
+ }
948
+
915
949
  setGlossary(glossary: AgentGlossaryEntry[]): Agent {
916
- registerAgentGlossary(this.getFqName(), glossary);
950
+ registerAgentGlossary(this.getAgentFqName(), glossary);
917
951
  return this;
918
952
  }
919
953
 
954
+ getGlossary(): AgentGlossaryEntry[] | undefined {
955
+ return getAgentGlossary(this.getAgentFqName());
956
+ }
957
+
920
958
  setResponseSchema(entryName: string): Agent {
921
- registerAgentResponseSchema(this.getFqName(), entryName);
959
+ registerAgentResponseSchema(this.getAgentFqName(), entryName);
922
960
  return this;
923
961
  }
924
962
 
963
+ getResponseSchema(): string | undefined {
964
+ return getAgentResponseSchema(this.getAgentFqName());
965
+ }
966
+
925
967
  override toString(): string {
926
968
  const attrs = new Array<string>();
927
969
  this.attributes.forEach((value: any, key: string) => {
@@ -1025,7 +1067,7 @@ export type RelationshipNode = {
1025
1067
  };
1026
1068
 
1027
1069
  export function newRelNodeEntry(nodeFqName: string, alias?: string): RelationshipNode {
1028
- const p: Path = splitFqName(nodeFqName);
1070
+ const p: Path = nameToPath(nodeFqName);
1029
1071
  return {
1030
1072
  path: p,
1031
1073
  alias: alias ? alias : p.getEntryName(),
@@ -1043,7 +1085,7 @@ function relNodeEntryToString(node: RelationshipNode): string {
1043
1085
  }
1044
1086
 
1045
1087
  function asRelNodeEntry(n: NodeDefinition): RelationshipNode {
1046
- const path: Path = splitFqName(n.name);
1088
+ const path: Path = nameToPath(n.name);
1047
1089
  let modName = activeModule;
1048
1090
  const entryName = path.getEntryName();
1049
1091
  if (path.hasModule()) {
@@ -1523,6 +1565,25 @@ export function flowGraphNext(
1523
1565
  return undefined;
1524
1566
  }
1525
1567
 
1568
+ export class Decision extends ModuleEntry {
1569
+ cases: string[];
1570
+
1571
+ constructor(name: string, moduleName: string, cases: string[]) {
1572
+ super(name, moduleName);
1573
+ this.cases = cases;
1574
+ }
1575
+
1576
+ joinedCases(): string {
1577
+ return this.cases.join('\n');
1578
+ }
1579
+
1580
+ override toString(): string {
1581
+ return `decision ${this.name} {
1582
+ ${this.cases.join('\n')}
1583
+ }`;
1584
+ }
1585
+ }
1586
+
1526
1587
  class StandaloneStatement extends ModuleEntry {
1527
1588
  stmt: Statement;
1528
1589
 
@@ -1588,10 +1649,12 @@ export class Module {
1588
1649
  getFlow(name: string): Flow | undefined {
1589
1650
  const n = Flow.asFlowName(name);
1590
1651
  if (this.hasEntry(n)) {
1591
- return this.getEntry(n) as Flow;
1592
- } else {
1593
- return undefined;
1652
+ const e = this.getEntry(n);
1653
+ if (e instanceof Flow) {
1654
+ return e as Flow;
1655
+ }
1594
1656
  }
1657
+ return undefined;
1595
1658
  }
1596
1659
 
1597
1660
  getAllFlows(): Flow[] {
@@ -1607,6 +1670,22 @@ export class Module {
1607
1670
  return false;
1608
1671
  }
1609
1672
 
1673
+ addDecision(name: string, cases: string[]): Decision {
1674
+ const d = new Decision(name, this.name, cases);
1675
+ this.addEntry(d);
1676
+ return d;
1677
+ }
1678
+
1679
+ getDecision(name: string): Decision | undefined {
1680
+ if (this.hasEntry(name)) {
1681
+ const e = this.getEntry(name);
1682
+ if (e instanceof Decision) {
1683
+ return e as Decision;
1684
+ }
1685
+ }
1686
+ return undefined;
1687
+ }
1688
+
1610
1689
  addStandaloneStatement(stmt: Statement): StandaloneStatement {
1611
1690
  const s = new StandaloneStatement(stmt, this.name);
1612
1691
  this.addEntry(s);
@@ -1918,7 +1997,7 @@ export function isBuiltInType(type: string): boolean {
1918
1997
 
1919
1998
  export function isValidType(type: string): boolean {
1920
1999
  if (isBuiltInType(type)) return true;
1921
- const path: Path = splitFqName(type);
2000
+ const path: Path = nameToPath(type);
1922
2001
  let modName: string = '';
1923
2002
  if (path.hasModule()) modName = path.getModuleName();
1924
2003
  else modName = activeModule;
@@ -2286,7 +2365,7 @@ export function prePostWorkflowName(
2286
2365
  entityName: string,
2287
2366
  moduleName?: string
2288
2367
  ): string {
2289
- const parts = splitFqName(entityName);
2368
+ const parts = nameToPath(entityName);
2290
2369
  const mname = parts.hasModule() ? parts.getModuleName() : moduleName;
2291
2370
  if (!mname) {
2292
2371
  throw new Error(`Cannot infer module name for ${entityName}`);
@@ -2312,7 +2391,7 @@ export function parsePrePostWorkflowName(name: string): ThinWfHeader {
2312
2391
 
2313
2392
  function getEntityDef(entityName: string, moduleName: string): Entity | undefined {
2314
2393
  try {
2315
- const parts = splitFqName(entityName);
2394
+ const parts = nameToPath(entityName);
2316
2395
  const mname = parts.hasModule() ? parts.getModuleName() : moduleName;
2317
2396
  return getEntity(parts.getEntryName(), mname);
2318
2397
  } catch (reason: any) {
@@ -2327,7 +2406,7 @@ export function getWorkflow(eventInstance: Instance): Workflow {
2327
2406
 
2328
2407
  export function getWorkflowForEvent(eventName: string, moduleName?: string): Workflow {
2329
2408
  if (isFqName(eventName)) {
2330
- const parts = splitFqName(eventName);
2409
+ const parts = nameToPath(eventName);
2331
2410
  eventName = parts.getEntryName();
2332
2411
  moduleName = parts.getModuleName();
2333
2412
  }
@@ -2351,7 +2430,7 @@ export function getEntity(name: string, moduleName: string): Entity | undefined
2351
2430
  }
2352
2431
 
2353
2432
  function isEntryOfType(t: RecordType, fqName: string): boolean {
2354
- const path = splitFqName(fqName);
2433
+ const path = nameToPath(fqName);
2355
2434
  const mod = fetchModule(path.getModuleName());
2356
2435
  return mod.isEntryOfType(t, path.getEntryName());
2357
2436
  }
@@ -3177,7 +3256,7 @@ export function instanceToObject<Type>(inst: Instance, obj: any): Type {
3177
3256
  }
3178
3257
 
3179
3258
  export function getEntityRbacRules(entityFqName: string): RbacSpecification[] | undefined {
3180
- const p = splitFqName(entityFqName);
3259
+ const p = nameToPath(entityFqName);
3181
3260
  const mn = p.getModuleName();
3182
3261
  const en = p.getEntryName();
3183
3262
  const m = isModule(mn) && fetchModule(mn);
@@ -3191,7 +3270,7 @@ export function getEntityRbacRules(entityFqName: string): RbacSpecification[] |
3191
3270
  }
3192
3271
 
3193
3272
  export function asJSONSchema(fqName: string): string {
3194
- const parts = splitFqName(fqName);
3273
+ const parts = nameToPath(fqName);
3195
3274
  if (parts.hasModule()) {
3196
3275
  const mod = fetchModule(parts.getModuleName());
3197
3276
  const record = mod.getRecord(parts.getEntryName());
@@ -3209,3 +3288,13 @@ export function asJSONSchema(fqName: string): string {
3209
3288
  throw new Error(`Failed to find module for ${fqName}`);
3210
3289
  }
3211
3290
  }
3291
+
3292
+ export function getDecision(name: string, moduleName: string): Decision | undefined {
3293
+ if (isFqName(name)) {
3294
+ const parts = splitFqName(name);
3295
+ name = parts[1];
3296
+ moduleName = parts[0];
3297
+ }
3298
+ const m = fetchModule(moduleName);
3299
+ return m.getDecision(name);
3300
+ }
@@ -1,4 +1,4 @@
1
- import { isFqName, makeCoreModuleName, makeFqName, splitFqName } from '../util.js';
1
+ import { isFqName, makeCoreModuleName, makeFqName, nameToPath, splitFqName } from '../util.js';
2
2
  import {
3
3
  Environment,
4
4
  GlobalEnvironment,
@@ -7,12 +7,15 @@ import {
7
7
  } from '../interpreter.js';
8
8
  import {
9
9
  asJSONSchema,
10
+ Decision,
10
11
  fetchModule,
12
+ getDecision,
11
13
  Instance,
12
14
  instanceToObject,
13
15
  isModule,
14
16
  makeInstance,
15
17
  newInstanceAttributes,
18
+ Record,
16
19
  } from '../module.js';
17
20
  import { provider } from '../agents/registry.js';
18
21
  import {
@@ -27,6 +30,7 @@ import {
27
30
  AgentCondition,
28
31
  AgentGlossaryEntry,
29
32
  AgentScenario,
33
+ DecisionAgentInstructions,
30
34
  FlowExecInstructions,
31
35
  getAgentDirectives,
32
36
  getAgentGlossary,
@@ -38,6 +42,8 @@ import {
38
42
  import { PathAttributeNameQuery } from '../defs.js';
39
43
  import { logger } from '../logger.js';
40
44
  import { FlowStep } from '../agents/flows.js';
45
+ import Handlebars from 'handlebars';
46
+ import { Statement } from '../../language/generated/ast.js';
41
47
 
42
48
  export const CoreAIModuleName = makeCoreModuleName('ai');
43
49
  export const AgentEntityName = 'Agent';
@@ -112,6 +118,7 @@ export class AgentInstance {
112
118
  private hasModuleTools = false;
113
119
  private withSession = true;
114
120
  private fqName: string | undefined;
121
+ private decisionExecutor = false;
115
122
 
116
123
  private constructor() {}
117
124
 
@@ -136,7 +143,7 @@ export class AgentInstance {
136
143
  for (let i = 0; i < agent.toolsArray.length; ++i) {
137
144
  const n = agent.toolsArray[i];
138
145
  if (isFqName(n)) {
139
- const parts = splitFqName(n);
146
+ const parts = nameToPath(n);
140
147
  agent.hasModuleTools = isModule(parts.getModuleName());
141
148
  } else {
142
149
  agent.hasModuleTools = isModule(n);
@@ -147,7 +154,11 @@ export class AgentInstance {
147
154
  return agent;
148
155
  }
149
156
 
150
- static FromFlowStep(step: FlowStep, flowAgent: AgentInstance): AgentInstance {
157
+ static FromFlowStep(step: FlowStep, flowAgent: AgentInstance, context: string): AgentInstance {
158
+ const desc = getDecision(step, flowAgent.moduleName);
159
+ if (desc) {
160
+ return AgentInstance.FromDecision(desc, flowAgent, context);
161
+ }
151
162
  const fqs = isFqName(step) ? step : `${flowAgent.moduleName}/${step}`;
152
163
  const instruction = `Analyse the context and generate the pattern required to invoke ${fqs}.
153
164
  Never include references in the pattern. All attribute values must be literals derived from the context.`;
@@ -162,7 +173,21 @@ export class AgentInstance {
162
173
  .set('tools', fqs)
163
174
  .set('type', 'planner')
164
175
  );
165
- return AgentInstance.FromInstance(inst);
176
+ return AgentInstance.FromInstance(inst).disableSession();
177
+ }
178
+
179
+ static FromDecision(desc: Decision, flowAgent: AgentInstance, context: string): AgentInstance {
180
+ const instruction = `${DecisionAgentInstructions}\n${context}\n\n${desc.joinedCases()}`;
181
+ const inst = makeInstance(
182
+ CoreAIModuleName,
183
+ AgentEntityName,
184
+ newInstanceAttributes()
185
+ .set('llm', flowAgent.llm)
186
+ .set('name', `${desc.name}_agent`)
187
+ .set('moduleName', flowAgent.moduleName)
188
+ .set('instruction', instruction)
189
+ );
190
+ return AgentInstance.FromInstance(inst).disableSession().markAsDecisionExecutor();
166
191
  }
167
192
 
168
193
  disableSession(): AgentInstance {
@@ -187,6 +212,15 @@ export class AgentInstance {
187
212
  return this.type == 'flow-exec';
188
213
  }
189
214
 
215
+ markAsDecisionExecutor(): AgentInstance {
216
+ this.decisionExecutor = true;
217
+ return this;
218
+ }
219
+
220
+ isDecisionExecutor(): boolean {
221
+ return this.decisionExecutor;
222
+ }
223
+
190
224
  private directivesAsString(fqName: string): string {
191
225
  const conds = getAgentDirectives(fqName);
192
226
  if (conds) {
@@ -202,14 +236,9 @@ export class AgentInstance {
202
236
  return '';
203
237
  }
204
238
 
205
- private cachedInstruction: string | undefined = undefined;
206
-
207
- private getFullInstructions(): string {
208
- if (this.cachedInstruction) {
209
- return this.cachedInstruction;
210
- }
239
+ private getFullInstructions(env: Environment): string {
211
240
  const fqName = this.getFqName();
212
- this.cachedInstruction = `${this.instruction || ''} ${this.directivesAsString(fqName)}`;
241
+ let finalInstruction = `${this.instruction || ''} ${this.directivesAsString(fqName)}`;
213
242
  const gls = getAgentGlossary(fqName);
214
243
  if (gls) {
215
244
  const glss = new Array<string>();
@@ -218,23 +247,39 @@ export class AgentInstance {
218
247
  `${age.name}: ${age.meaning}. ${age.synonyms ? `These words are synonyms for ${age.name}: ${age.synonyms}` : ''}`
219
248
  );
220
249
  });
221
- this.cachedInstruction = `${this.cachedInstruction}\nThe following glossary will be helpful for understanding user requests.
250
+ finalInstruction = `${finalInstruction}\nThe following glossary will be helpful for understanding user requests.
222
251
  ${glss.join('\n')}\n`;
223
252
  }
224
253
  const scenarios = getAgentScenarios(fqName);
225
254
  if (scenarios) {
226
255
  const scs = new Array<string>();
227
256
  scenarios.forEach((sc: AgentScenario) => {
228
- scs.push(`User: ${sc.user}\nAI: ${sc.ai}\n`);
257
+ const aiResp = processScenarioResponse(sc.ai);
258
+ scs.push(`User: ${sc.user}\nAI: ${aiResp}\n`);
229
259
  });
230
- this.cachedInstruction = `${this.cachedInstruction}\nHere are some example user requests and the corresponding responses you are supposed to produce:\n${scs.join('\n')}`;
260
+ finalInstruction = `${finalInstruction}\nHere are some example user requests and the corresponding responses you are supposed to produce:\n${scs.join('\n')}`;
231
261
  }
232
262
  const responseSchema = getAgentResponseSchema(fqName);
233
263
  if (responseSchema) {
234
- this.cachedInstruction = `${this.cachedInstruction}\nReturn your response in the following JSON schema:\n${asJSONSchema(responseSchema)}
264
+ finalInstruction = `${finalInstruction}\nReturn your response in the following JSON schema:\n${asJSONSchema(responseSchema)}
235
265
  Only return a pure JSON object with no extra text, annotations etc.`;
236
266
  }
237
- return this.cachedInstruction;
267
+ const spad = env.getScratchPad();
268
+ if (spad != undefined) {
269
+ if (finalInstruction.indexOf('{{') > 0) {
270
+ return AgentInstance.maybeRewriteTemplatePatterns(spad, finalInstruction);
271
+ } else {
272
+ const ctx = JSON.stringify(spad);
273
+ return `${finalInstruction}\nSome additional context:\n${ctx}`;
274
+ }
275
+ } else {
276
+ return finalInstruction;
277
+ }
278
+ }
279
+
280
+ private static maybeRewriteTemplatePatterns(scratchPad: any, instruction: string): string {
281
+ const templ = Handlebars.compile(instruction);
282
+ return templ(scratchPad);
238
283
  }
239
284
 
240
285
  maybeValidateJsonResponse(response: string | undefined): object | undefined {
@@ -242,7 +287,7 @@ Only return a pure JSON object with no extra text, annotations etc.`;
242
287
  const responseSchema = getAgentResponseSchema(this.getFqName());
243
288
  if (responseSchema) {
244
289
  const attrs = JSON.parse(response);
245
- const parts = splitFqName(responseSchema);
290
+ const parts = nameToPath(responseSchema);
246
291
  const moduleName = parts.getModuleName();
247
292
  const entryName = parts.getEntryName();
248
293
  const attrsMap = new Map(Object.entries(attrs));
@@ -317,23 +362,32 @@ Only return a pure JSON object with no extra text, annotations etc.`;
317
362
  }
318
363
  const sess: Instance | null = this.withSession ? await findAgentChatSession(chatId, env) : null;
319
364
  let msgs: BaseMessage[] | undefined;
365
+ let cachedMsg: string | undefined = undefined;
320
366
  if (sess) {
321
367
  msgs = sess.lookup('messages');
322
368
  } else {
323
- msgs = [systemMessage(this.getFullInstructions() || '')];
369
+ cachedMsg = this.getFullInstructions(env);
370
+ msgs = [systemMessage(cachedMsg || '')];
324
371
  }
325
372
  if (msgs) {
326
373
  try {
327
374
  const sysMsg = msgs[0];
328
375
  if (isplnr || isflow) {
329
376
  const s = isplnr ? PlannerInstructions : FlowExecInstructions;
330
- const newSysMsg = systemMessage(
331
- `${s}\n${this.toolsAsString()}\n${this.getFullInstructions()}`
332
- );
377
+ const ts = this.toolsAsString();
378
+ const msg = `${s}\n${ts}\n${cachedMsg || this.getFullInstructions(env)}`;
379
+ const newSysMsg = systemMessage(msg);
333
380
  msgs[0] = newSysMsg;
334
381
  }
335
382
  msgs.push(humanMessage(await this.maybeAddRelevantDocuments(message, env)));
336
383
  const externalToolSpecs = this.getExternalToolSpecs();
384
+ logger.debug(
385
+ `Invoking LLM ${this.llm} via agent ${this.fqName} with messages:\n${msgs
386
+ .map((bm: BaseMessage) => {
387
+ return bm.content;
388
+ })
389
+ .join('\n')}`
390
+ );
337
391
  const response: AIResponse = await p.invoke(msgs, externalToolSpecs);
338
392
  msgs.push(assistantMessage(response.content));
339
393
  if (isplnr) {
@@ -412,7 +466,7 @@ Only return a pure JSON object with no extra text, annotations etc.`;
412
466
  let moduleName: string | undefined;
413
467
  let entryName: string | undefined;
414
468
  if (isFqName(n)) {
415
- const parts = splitFqName(n);
469
+ const parts = nameToPath(n);
416
470
  moduleName = parts.getModuleName();
417
471
  entryName = parts.getEntryName();
418
472
  } else {
@@ -423,7 +477,10 @@ Only return a pure JSON object with no extra text, annotations etc.`;
423
477
  if (entryName) {
424
478
  const hasmod = slimModules.has(moduleName);
425
479
  const defs = hasmod ? slimModules.get(moduleName) : new Array<string>();
426
- defs?.push(m.getEntry(entryName).toString());
480
+ const entry = m.getEntry(entryName);
481
+ const s =
482
+ entry instanceof Record ? (entry as Record).toString_(true) : entry.toString();
483
+ defs?.push(s);
427
484
  if (!hasmod && defs) {
428
485
  slimModules.set(moduleName, defs);
429
486
  }
@@ -562,3 +619,20 @@ export async function saveAgentChatSession(chatId: string, messages: any[], env:
562
619
  export function agentName(agentInstance: Instance): string {
563
620
  return agentInstance.lookup('name');
564
621
  }
622
+
623
+ function processScenarioResponse(resp: string): string {
624
+ const r = resp.trimStart();
625
+ if (r.startsWith('[') || r.startsWith('{')) {
626
+ return resp;
627
+ }
628
+ if (isFqName(r)) {
629
+ const parts = splitFqName(r);
630
+ const m = fetchModule(parts[0]);
631
+ const wf = m.getWorkflowForEvent(parts[1]);
632
+ const ss = wf.statements.map((stmt: Statement) => {
633
+ return stmt.$cstNode?.text;
634
+ });
635
+ return `[${ss.join(';\n')}]`;
636
+ }
637
+ return resp;
638
+ }
@@ -13,7 +13,7 @@ import {
13
13
  newInstanceAttributes,
14
14
  Relationship,
15
15
  } from '../module.js';
16
- import { CrudType, splitFqName } from '../util.js';
16
+ import { CrudType, nameToPath } from '../util.js';
17
17
  import { DefaultAuthInfo, ResolverAuthInfo } from './authinfo.js';
18
18
 
19
19
  export type JoinInfo = {
@@ -223,7 +223,7 @@ export class Resolver {
223
223
  } else {
224
224
  const eventName = getSubscriptionEvent(this.name);
225
225
  if (eventName) {
226
- const path = splitFqName(eventName);
226
+ const path = nameToPath(eventName);
227
227
  const inst = makeInstance(
228
228
  path.getModuleName(),
229
229
  path.getEntryName(),
@@ -13,7 +13,7 @@ import {
13
13
  newInstanceAttributes,
14
14
  Relationship,
15
15
  } from '../../module.js';
16
- import { escapeFqName, makeFqName, splitFqName } from '../../util.js';
16
+ import { escapeFqName, makeFqName, nameToPath } from '../../util.js';
17
17
  import { JoinInfo, Resolver } from '../interface.js';
18
18
  import { asTableReference } from './dbutil.js';
19
19
  import {
@@ -259,7 +259,7 @@ export class SqlDbResolver extends Resolver {
259
259
  const joinClauses: JoinClause[] = [];
260
260
  this.processJoinInfo(tableName, inst, joinsSpec, joinClauses);
261
261
  intoSpec.forEach((v: string, k: string) => {
262
- const p = splitFqName(v);
262
+ const p = nameToPath(v);
263
263
  const mn = p.hasModule() ? p.getModuleName() : inst.moduleName;
264
264
  intoSpec.set(k, asTableReference(mn, p.getEntryName()));
265
265
  });
@@ -141,7 +141,7 @@ export function isFqName(s: string): boolean {
141
141
  return s.indexOf('/') > 0;
142
142
  }
143
143
 
144
- export function splitFqName(s: string): Path {
144
+ export function nameToPath(s: string): Path {
145
145
  if (s.indexOf('/') > 0) {
146
146
  const parts: string[] = s.split('/');
147
147
  return new Path(parts[0], parts[1]);
@@ -149,6 +149,10 @@ export function splitFqName(s: string): Path {
149
149
  return new Path(undefined, s);
150
150
  }
151
151
 
152
+ export function splitFqName(s: string): string[] {
153
+ return s.split('/');
154
+ }
155
+
152
156
  export function splitRefs(s: string): string[] {
153
157
  if (s.indexOf('.') > 0) {
154
158
  return s.split('.');
@@ -1,12 +1,12 @@
1
1
  // Monarch syntax highlighting for the agentlang language.
2
2
  export default {
3
3
  keywords: [
4
- '@actions','@after','@as','@async','@before','@catch','@distinct','@enum','@expr','@from','@into','@meta','@oneof','@rbac','@ref','@then','@upsert','@with_unique','agent','allow','and','await','between','contains','create','delete','else','entity','error','event','extends','false','flow','for','if','import','in','like','module','not','not_found','onSubscription','or','purge','query','read','record','relationship','resolver','return','roles','subscribe','true','update','upsert','where','workflow'
4
+ '@actions','@after','@as','@async','@before','@catch','@distinct','@enum','@expr','@from','@into','@meta','@oneof','@rbac','@ref','@then','@upsert','@with_unique','agent','allow','and','await','between','case','contains','create','decision','delete','else','entity','error','event','extends','false','flow','for','if','import','in','like','module','not','not_found','onSubscription','or','purge','query','read','record','relationship','resolver','return','roles','subscribe','true','update','upsert','where','workflow'
5
5
  ],
6
6
  operators: [
7
- '!=','*','+',',','-','-->','.','/',':',';','<','<=','<>','=','>','>=','?','@'
7
+ '!=','*','+',',','-','-->','.','/',':',';','<','<=','<>','=','==','>','>=','?','@'
8
8
  ],
9
- symbols: /!=|\(|\)|\*|\+|,|-|-->|\.|\/|:|;|<|<=|<>|=|>|>=|\?|@|\[|\]|\{|\}/,
9
+ symbols: /!=|\(|\)|\*|\+|,|-|-->|\.|\/|:|;|<|<=|<>|=|==|>|>=|\?|@|\[|\]|\{|\}/,
10
10
 
11
11
  tokenizer: {
12
12
  initial: [