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
@@ -411,27 +411,27 @@ function asFnCallPattern(fnCall: FnCall): FunctionCallPattern {
411
411
  }
412
412
 
413
413
  function introspectLiteral(lit: Literal): BasePattern {
414
- if (lit.id) {
414
+ if (lit.id !== undefined) {
415
415
  return LiteralPattern.Id(lit.id);
416
- } else if (lit.num) {
416
+ } else if (lit.num !== undefined) {
417
417
  return LiteralPattern.Number(lit.num);
418
- } else if (lit.ref) {
418
+ } else if (lit.ref !== undefined) {
419
419
  return LiteralPattern.Reference(lit.ref);
420
420
  } else if (lit.str !== undefined) {
421
421
  return LiteralPattern.String(lit.str);
422
- } else if (lit.bool) {
422
+ } else if (lit.bool !== undefined) {
423
423
  return LiteralPattern.Boolean(lit.bool == 'true' ? true : false);
424
- } else if (lit.fnCall) {
424
+ } else if (lit.fnCall !== undefined) {
425
425
  return asFnCallPattern(lit.fnCall);
426
- } else if (lit.asyncFnCall) {
426
+ } else if (lit.asyncFnCall !== undefined) {
427
427
  return asFnCallPattern(lit.asyncFnCall.fnCall).asAsync();
428
- } else if (lit.array) {
428
+ } else if (lit.array !== undefined) {
429
429
  return LiteralPattern.Array(
430
430
  lit.array.vals.map((stmt: Statement) => {
431
431
  return introspectStatement(stmt);
432
432
  })
433
433
  );
434
- } else if (lit.map) {
434
+ } else if (lit.map !== undefined) {
435
435
  return introspectMapLiteral(lit.map);
436
436
  } else {
437
437
  throw new Error(`Invalid literal - ${lit}`);
@@ -167,6 +167,9 @@ The following usage is NOT valid:
167
167
 
168
168
  <pattern> if (<expr>)
169
169
 
170
+ Also C-style ternary-expressions of the form \`condition ? consequent : alternative\` IS INVALID in Agentlang. Always use a proper
171
+ \`if-else\` statement.
172
+
170
173
  A pattern may execute asynchronously and its eventual result can be handled by patterns provided in the '@then' clause. An example is shown below:
171
174
 
172
175
  {sendChatMessage {to "amy", "text" "hello"}} @as response @then {
@@ -362,6 +365,105 @@ case or cases you selected and no additional text or comments. If you decide to
362
365
  Also select the case that is the best match for the given context, no need to look for a perfect match for all values specified in the context.
363
366
  Now apply the same analysis to the following context and cases provided by the user.
364
367
  `;
368
+ export const EvalInstructions = `Consider the following request passed to an intelligent agent and its response. Rate the response on a scale of
369
+ 1-5, where 1 being the lowest score (response unacceptable) and 5 being the highest score (best response). Also describe why you gave a particular score.
370
+ Reply in the JSON format {score: <score-for-the-response, summary: <your-reasons-for-giving-the-score>}`;
371
+
372
+ export const LearningAgentInstructions = `Summarize requirements and use-cases as three constructs: 'decisions' and 'glossaries'.
373
+ Your response must be encoded in JSON. The exact schema will be described later, but let's first consider an example that will help clarify
374
+ how decisions and glossaries could be generate from a use-case. This use-case is from the insurance industry:
375
+
376
+ In insurance, a claim is a formal request made by a policyholder (or beneficiary) to an insurance company asking for financial
377
+ compensation or service because a covered event (loss) has occurred. When the company receives a claim, look at its risk-factor and
378
+ set its approval-mode accordingly. If the risk-factor is 'low', then set the approval-mode to 'auto', if it's 'medium' then set approval-mode to
379
+ 'manual'. If the risk-factor is 'high', then set approval-mode to 'investigate'.
380
+
381
+ Given the above use-case you should return the summary as:
382
+ {
383
+ "summary": "A claim is a request for insurance benefits after a covered loss, and its risk level determines
384
+ whether it is auto-approved, manually reviewed, or investigated.",
385
+ "glossary": [
386
+ {
387
+ "word": "claim",
388
+ "meaning": "A claim is a request to an insurer for payment or service after a covered loss."
389
+ }
390
+ ],
391
+ "decisions": [
392
+ {
393
+ "name": "setApprovalByRiskFactor",
394
+ "conditions": [
395
+ {
396
+ "if": "risk-factor is low",
397
+ "then": "auto"
398
+ },
399
+ {
400
+ "if": "risk-factor is medium",
401
+ "then": "manual"
402
+ },
403
+ {
404
+ "if": "risk-factor is high",
405
+ "then": "investigate"
406
+ }
407
+ ]
408
+ }
409
+ ]
410
+ }
411
+
412
+ Sometimes, the use-case will also contain some examples, which you can summarize as 'scenarios'. An example follows:
413
+
414
+ The ACME company gives salary-hikes to employees based on their sales. If the sales is $50000 or above, a 5-percent hike is given.
415
+ If the sales is between $20000 and $50000, a hike of 2.5% is given. For sales below $20000, no hike is given. An employee who hit
416
+ the target of $50000 is said to have hit a "jackpot". For example, if you see a message that says - "jake@acme.com hit a jackpot", that means
417
+ the employee 'jake@acme.com' is eligible for a 5% hike.
418
+
419
+ Given the above instruction, you should return:
420
+
421
+ {
422
+ "summary": "ACME determines employee salary hikes based on achieved sales figures, with higher sales resulting in higher percentage increases. Employees who meet or exceed the top sales threshold are described as having hit a jackpot.",
423
+ "glossary": [
424
+ {
425
+ "word": "salary-hike",
426
+ "meaning": "An increase in an employee's salary based on defined performance criteria."
427
+ },
428
+ {
429
+ "word": "sales",
430
+ "meaning": "The total revenue generated by an employee, used as the basis for determining salary hikes."
431
+ },
432
+ {
433
+ "word": "jackpot",
434
+ "meaning": "A term used for employees whose sales are 50000 or above, making them eligible for the highest salary hike."
435
+ }
436
+ ],
437
+ "decisions": [
438
+ {
439
+ "name": "determineSalaryHikeBySales",
440
+ "conditions": [
441
+ {
442
+ "if": "sales is 50000 or above",
443
+ "then": "5-percent hike"
444
+ },
445
+ {
446
+ "if": "sales is between 20000 and 50000",
447
+ "then": "2.5-percent hike"
448
+ },
449
+ {
450
+ "if": "sales is below 20000",
451
+ "then": "no hike"
452
+ }
453
+ ]
454
+ }
455
+ ],
456
+ "scenarios": [
457
+ {
458
+ "user": "jake@acme.com hit a jackpot",
459
+ "ai": "give jake@acme.com a hike of 5-percent"
460
+ }
461
+ ]
462
+ }
463
+
464
+ For some user-requests, it may not be able to produce glossary or decisions (or both). In such cases, just return the 'summary'.
465
+ Now process the user-request that follows.
466
+ `;
365
467
 
366
468
  export type AgentCondition = {
367
469
  if: string;
@@ -575,3 +677,8 @@ export function getAgentScratchNames(agentFqName: string): Set<string> | undefin
575
677
  export function removeAgentScratchNames(agentFqName: string) {
576
678
  AgentScratchNames.delete(agentFqName);
577
679
  }
680
+
681
+ export type AgentSummary = {
682
+ data: string;
683
+ summary: string;
684
+ };
@@ -181,15 +181,15 @@ export class AnthropicProvider implements AgentServiceProvider {
181
181
  if (!config) {
182
182
  return {
183
183
  ...defaultConfig,
184
- apiKey: process.env.ANTHROPIC_API_KEY || getLocalEnv('ANTHROPIC_API_KEY'),
184
+ apiKey: process.env.AGENTLANG_ANTHROPIC_KEY || getLocalEnv('AGENTLANG_ANTHROPIC_KEY'),
185
185
  };
186
186
  }
187
187
 
188
188
  const apiKey =
189
189
  config.get('apiKey') ||
190
190
  config.get('api_key') ||
191
- process.env.ANTHROPIC_API_KEY ||
192
- getLocalEnv('ANTHROPIC_API_KEY');
191
+ process.env.AGENTLANG_ANTHROPIC_KEY ||
192
+ getLocalEnv('AGENTLANG_ANTHROPIC_KEY');
193
193
 
194
194
  return {
195
195
  model: config.get('model') || defaultConfig.model,
@@ -266,7 +266,7 @@ export class AnthropicProvider implements AgentServiceProvider {
266
266
  ): Promise<AIResponse> {
267
267
  if (!this.config.apiKey) {
268
268
  throw new Error(
269
- 'Anthropic API key is required. Set ANTHROPIC_API_KEY environment variable or use setLocalEnv("ANTHROPIC_API_KEY", key) or provide apiKey in config.'
269
+ 'Anthropic API key is required. Set AGENTLANG_ANTHROPIC_KEY environment variable or use setLocalEnv("AGENTLANG_ANTHROPIC_KEY", key) or provide apiKey in config.'
270
270
  );
271
271
  }
272
272
 
@@ -69,15 +69,15 @@ export class OpenAIProvider implements AgentServiceProvider {
69
69
  if (!config) {
70
70
  return {
71
71
  ...defaultConfig,
72
- apiKey: process.env.OPENAI_API_KEY || getLocalEnv('OPENAI_API_KEY'),
72
+ apiKey: process.env.AGENTLANG_OPENAI_KEY || getLocalEnv('AGENTLANG_OPENAI_KEY'),
73
73
  };
74
74
  }
75
75
 
76
76
  const apiKey =
77
77
  config.get('apiKey') ||
78
78
  config.get('api_key') ||
79
- process.env.OPENAI_API_KEY ||
80
- getLocalEnv('OPENAI_API_KEY');
79
+ process.env.AGENTLANG_OPENAI_KEY ||
80
+ getLocalEnv('AGENTLANG_OPENAI_KEY');
81
81
 
82
82
  return {
83
83
  model: config.get('model') || defaultConfig.model,
@@ -105,7 +105,7 @@ export class OpenAIProvider implements AgentServiceProvider {
105
105
  async invoke(messages: BaseMessage[], externalToolSpecs: any[] | undefined): Promise<AIResponse> {
106
106
  if (!this.config.apiKey) {
107
107
  throw new Error(
108
- 'OpenAI API key is required. Set OPENAI_API_KEY environment variable or use setLocalEnv("OPENAI_API_KEY", key) or provide apiKey in config.'
108
+ 'OpenAI API key is required. Set AGENTLANG_OPENAI_KEY environment variable or use setLocalEnv("AGENTLANG_OPENAI_KEY", key) or provide apiKey in config.'
109
109
  );
110
110
  }
111
111
  if (externalToolSpecs) {
@@ -1,5 +1,6 @@
1
- import { getFileSystem } from '../utils/fs-utils.js';
2
1
  import { logger } from './logger.js';
2
+ import { isNodeEnv } from '../utils/runtime.js';
3
+ import { getFileSystem } from '../utils/fs-utils.js';
3
4
 
4
5
  const DocFetchers = new Map<string, Function>();
5
6
 
@@ -25,6 +26,39 @@ export async function fetchDoc(url: string): Promise<string | undefined> {
25
26
  else return undefined;
26
27
  }
27
28
 
29
+ let PDFParse: any = null;
30
+ let pdfWorkerSet = false;
31
+
32
+ async function getPDFParse() {
33
+ if (!PDFParse) {
34
+ const pdfModule = await import('pdf-parse');
35
+ PDFParse = pdfModule.PDFParse;
36
+
37
+ // Set up web worker for browser
38
+ if (!isNodeEnv && !pdfWorkerSet && PDFParse.setWorker) {
39
+ // Worker is served from public/ directory
40
+ PDFParse.setWorker('/pdf.worker.mjs');
41
+ pdfWorkerSet = true;
42
+ }
43
+ }
44
+ return PDFParse;
45
+ }
46
+
47
+ async function parsePdfBuffer(buffer: Uint8Array): Promise<string> {
48
+ try {
49
+ const PDFParseClass = await getPDFParse();
50
+ const parser = new PDFParseClass({
51
+ data: buffer,
52
+ verbosity: 0,
53
+ });
54
+ const data = await parser.getText();
55
+ return data.text;
56
+ } catch (error: any) {
57
+ logger.error(`Failed to parse PDF: ${error.message}`);
58
+ throw new Error(`PDF parsing failed: ${error.message}`);
59
+ }
60
+ }
61
+
28
62
  async function httpFetcher(url: string): Promise<string | undefined> {
29
63
  try {
30
64
  const response = await fetch(url, {
@@ -32,12 +66,24 @@ async function httpFetcher(url: string): Promise<string | undefined> {
32
66
  });
33
67
 
34
68
  if (!response.ok) {
35
- logger.error(
36
- `Failed to fetch document ${url}, HTTP error! status: ${response.status} ${response.text} ${response.statusText}`
37
- );
69
+ logger.error(`Failed to fetch document ${url}, HTTP error! status: ${response.status}`);
38
70
  return undefined;
39
71
  }
40
- return await response.text();
72
+
73
+ const contentType = response.headers.get('content-type') || '';
74
+ const content = await response.arrayBuffer();
75
+
76
+ const lowerUrl = url.toLowerCase();
77
+
78
+ // Process based on content type or file extension
79
+ if (contentType.includes('application/pdf') || lowerUrl.endsWith('.pdf')) {
80
+ return await parsePdfBuffer(new Uint8Array(content));
81
+ } else if (contentType.includes('text/markdown') || lowerUrl.endsWith('.md')) {
82
+ return new TextDecoder().decode(content);
83
+ } else {
84
+ // Default to text
85
+ return new TextDecoder().decode(content);
86
+ }
41
87
  } catch (reason: any) {
42
88
  logger.error(`Failed to fetch document ${url}: ${reason}`);
43
89
  }
@@ -45,11 +91,76 @@ async function httpFetcher(url: string): Promise<string | undefined> {
45
91
  }
46
92
 
47
93
  async function fetchFile(path: string): Promise<string> {
48
- const fs = await getFileSystem();
49
- if (path.startsWith('.')) {
50
- path = `${process.cwd()}${path.substring(1)}`;
94
+ const lowerPath = path.toLowerCase();
95
+
96
+ if (lowerPath.endsWith('.pdf')) {
97
+ return await fetchPdfFile(path);
98
+ } else if (
99
+ lowerPath.endsWith('.md') ||
100
+ lowerPath.endsWith('.markdown') ||
101
+ lowerPath.endsWith('.mdown')
102
+ ) {
103
+ return await fetchMarkdownFile(path);
104
+ } else {
105
+ // Default: plain text
106
+ return await fetchTextFile(path);
107
+ }
108
+ }
109
+
110
+ async function fetchPdfFile(path: string): Promise<string> {
111
+ try {
112
+ const fs = await getFileSystem();
113
+
114
+ if (isNodeEnv && path.startsWith('.')) {
115
+ path = `${process.cwd()}${path.substring(1)}`;
116
+ }
117
+
118
+ const content = await fs.readFile(path);
119
+
120
+ let buffer: Uint8Array;
121
+ if (typeof content === 'string') {
122
+ buffer = new TextEncoder().encode(content);
123
+ } else if (Buffer.isBuffer(content)) {
124
+ buffer = new Uint8Array(content);
125
+ } else {
126
+ buffer = new Uint8Array(Buffer.from(content));
127
+ }
128
+
129
+ return await parsePdfBuffer(buffer);
130
+ } catch (error: any) {
131
+ logger.error(`Failed to read PDF file ${path}: ${error.message}`);
132
+ throw error;
133
+ }
134
+ }
135
+
136
+ async function fetchMarkdownFile(path: string): Promise<string> {
137
+ try {
138
+ const fs = await getFileSystem();
139
+
140
+ if (isNodeEnv && path.startsWith('.')) {
141
+ path = `${process.cwd()}${path.substring(1)}`;
142
+ }
143
+
144
+ return await fs.readFile(path);
145
+ } catch (error: any) {
146
+ logger.error(`Failed to read Markdown file ${path}: ${error.message}`);
147
+ throw error;
148
+ }
149
+ }
150
+
151
+ async function fetchTextFile(path: string): Promise<string> {
152
+ try {
153
+ const fs = await getFileSystem();
154
+
155
+ if (isNodeEnv && path.startsWith('.')) {
156
+ path = `${process.cwd()}${path.substring(1)}`;
157
+ }
158
+
159
+ return await fs.readFile(path);
160
+ } catch (error: any) {
161
+ logger.error(`Failed to read text file ${path}: ${error.message}`);
162
+ throw error;
51
163
  }
52
- return fs.readFile(path);
53
164
  }
54
165
 
55
166
  registerDocFetcher('http', httpFetcher);
@@ -0,0 +1,50 @@
1
+ export class TextChunker {
2
+ private chunkSize: number;
3
+ private chunkOverlap: number;
4
+ private separators: string[] = ['\n\n', '\n', '. ', ' ', ''];
5
+
6
+ constructor(chunkSize: number = 1000, chunkOverlap: number = 200) {
7
+ this.chunkSize = chunkSize;
8
+ this.chunkOverlap = chunkOverlap;
9
+ }
10
+
11
+ splitText(text: string): string[] {
12
+ if (text.length <= this.chunkSize) {
13
+ return [text];
14
+ }
15
+
16
+ const chunks: string[] = [];
17
+ let start = 0;
18
+
19
+ while (start < text.length) {
20
+ let end = Math.min(start + this.chunkSize, text.length);
21
+
22
+ if (end < text.length) {
23
+ end = this.findBestSplitPoint(text, start, end);
24
+ }
25
+
26
+ chunks.push(text.substring(start, end));
27
+ start = end - this.chunkOverlap;
28
+
29
+ if (start < 0) start = 0;
30
+ if (start >= text.length - this.chunkOverlap) {
31
+ if (start < text.length) {
32
+ chunks.push(text.substring(start));
33
+ }
34
+ break;
35
+ }
36
+ }
37
+
38
+ return chunks;
39
+ }
40
+
41
+ private findBestSplitPoint(text: string, start: number, end: number): number {
42
+ for (const sep of this.separators) {
43
+ const lastSep = text.lastIndexOf(sep, end);
44
+ if (lastSep > start) {
45
+ return Math.min(lastSep + sep.length, end);
46
+ }
47
+ }
48
+ return end;
49
+ }
50
+ }
@@ -0,0 +1,5 @@
1
+ export { EmbeddingProvider, EmbeddingProviderConfig } from './provider.js';
2
+ export { EmbeddingService } from '../resolvers/sqldb/impl.js';
3
+ export { TextChunker } from './chunker.js';
4
+ export { embeddingProvider, getDefaultEmbeddingProvider } from './registry.js';
5
+ export { OpenAIEmbeddingProvider, OpenAIEmbeddingConfig } from './openai.js';
@@ -0,0 +1,49 @@
1
+ import { OpenAIEmbeddings } from '@langchain/openai';
2
+ import { EmbeddingProvider, EmbeddingProviderConfig } from './provider.js';
3
+ import { getLocalEnv } from '../auth/defs.js';
4
+
5
+ export interface OpenAIEmbeddingConfig extends EmbeddingProviderConfig {
6
+ model?: string;
7
+ dimensions?: number;
8
+ maxRetries?: number;
9
+ }
10
+
11
+ export class OpenAIEmbeddingProvider extends EmbeddingProvider {
12
+ private openaiConfig: OpenAIEmbeddingConfig;
13
+
14
+ constructor(config?: EmbeddingProviderConfig) {
15
+ super(config || {});
16
+ this.openaiConfig = (this.config as OpenAIEmbeddingConfig) || {};
17
+ }
18
+
19
+ protected createEmbeddings(): OpenAIEmbeddings {
20
+ const config: any = {
21
+ apiKey: this.resolveApiKey(),
22
+ };
23
+
24
+ if (this.openaiConfig.model) {
25
+ config.model = this.openaiConfig.model;
26
+ }
27
+
28
+ if (this.openaiConfig.dimensions) {
29
+ config.dimensions = this.openaiConfig.dimensions;
30
+ }
31
+
32
+ if (this.openaiConfig.maxRetries !== undefined) {
33
+ config.maxRetries = this.openaiConfig.maxRetries;
34
+ }
35
+
36
+ return new OpenAIEmbeddings(config);
37
+ }
38
+
39
+ protected resolveApiKey(): string {
40
+ if (this.openaiConfig.apiKey) {
41
+ return this.openaiConfig.apiKey;
42
+ }
43
+ return process.env.AGENTLANG_OPENAI_KEY || getLocalEnv('AGENTLANG_OPENAI_KEY') || '';
44
+ }
45
+
46
+ getProviderName(): string {
47
+ return 'openai';
48
+ }
49
+ }
@@ -0,0 +1,37 @@
1
+ import { Embeddings } from '@langchain/core/embeddings';
2
+
3
+ export interface EmbeddingProviderConfig {
4
+ chunkSize?: number;
5
+ chunkOverlap?: number;
6
+ apiKey?: string;
7
+ model?: string;
8
+ [key: string]: any;
9
+ }
10
+
11
+ export abstract class EmbeddingProvider {
12
+ protected config: EmbeddingProviderConfig;
13
+ protected embeddings: Embeddings;
14
+
15
+ constructor(config: EmbeddingProviderConfig = {}) {
16
+ this.config = config;
17
+ this.embeddings = this.createEmbeddings();
18
+ }
19
+
20
+ protected abstract createEmbeddings(): Embeddings;
21
+ protected abstract resolveApiKey(): string;
22
+
23
+ abstract getProviderName(): string;
24
+
25
+ async embedText(text: string): Promise<number[]> {
26
+ return await this.embeddings.embedQuery(text);
27
+ }
28
+
29
+ getConfig(): EmbeddingProviderConfig {
30
+ return { ...this.config };
31
+ }
32
+
33
+ updateConfig(newConfig: Partial<EmbeddingProviderConfig>): void {
34
+ this.config = { ...this.config, ...newConfig };
35
+ this.embeddings = this.createEmbeddings();
36
+ }
37
+ }
@@ -0,0 +1,17 @@
1
+ import { OpenAIEmbeddingProvider } from './openai.js';
2
+
3
+ const EmbeddingProviders = new Map().set('openai', OpenAIEmbeddingProvider);
4
+
5
+ export function embeddingProvider(service: string): any {
6
+ const requestedService = service.toLowerCase();
7
+ const provider = EmbeddingProviders.get(requestedService);
8
+ if (provider) {
9
+ return provider;
10
+ } else {
11
+ throw new Error(`No embedding provider found for ${service}`);
12
+ }
13
+ }
14
+
15
+ export function getDefaultEmbeddingProvider(): string {
16
+ return 'openai';
17
+ }
@@ -468,15 +468,18 @@ export async function executeEventHelper(eventInstance: Instance, env?: Environm
468
468
  isLocalEnv = true;
469
469
  }
470
470
  let g: ExecGraph | undefined;
471
+ let escalatedRole: string | undefined;
471
472
  if (!isAgentEventInstance(eventInstance)) {
472
473
  g = await generateExecutionGraph(fqn);
473
474
  if (!g) {
474
475
  throw new Error(`Failed to generate graph for event ${fqn}`);
475
476
  }
477
+ escalatedRole = getWorkflowForEvent(fqn).getRoleEscalation();
476
478
  }
477
479
  const oldModuleName = env.switchActiveModuleName(eventInstance.moduleName);
478
480
  env.bind(eventInstance.name, eventInstance);
479
481
  env.bind(eventInstance.getFqName(), eventInstance);
482
+ if (escalatedRole) env.setEscalatedRole(escalatedRole);
480
483
  try {
481
484
  if (g) {
482
485
  await executeGraph(g, env);
@@ -498,6 +501,7 @@ export async function executeEventHelper(eventInstance: Instance, env?: Environm
498
501
  }
499
502
  throw err;
500
503
  } finally {
504
+ env.resetEscalatedRole();
501
505
  if (!isLocalEnv) env.switchActiveModuleName(oldModuleName);
502
506
  }
503
507
  }