agentlang 0.0.18 → 0.0.20

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 (104) hide show
  1. package/out/cli/main.d.ts.map +1 -1
  2. package/out/cli/main.js +35 -6
  3. package/out/cli/main.js.map +1 -1
  4. package/out/language/generated/ast.d.ts +23 -4
  5. package/out/language/generated/ast.d.ts.map +1 -1
  6. package/out/language/generated/ast.js +29 -1
  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 +251 -171
  10. package/out/language/generated/grammar.js.map +1 -1
  11. package/out/language/main.cjs +271 -172
  12. package/out/language/main.cjs.map +2 -2
  13. package/out/language/parser.d.ts +1 -0
  14. package/out/language/parser.d.ts.map +1 -1
  15. package/out/language/parser.js +25 -9
  16. package/out/language/parser.js.map +1 -1
  17. package/out/runtime/agents/common.d.ts +1 -1
  18. package/out/runtime/agents/common.d.ts.map +1 -1
  19. package/out/runtime/agents/common.js +4 -1
  20. package/out/runtime/agents/common.js.map +1 -1
  21. package/out/runtime/agents/impl/anthropic.d.ts +54 -0
  22. package/out/runtime/agents/impl/anthropic.d.ts.map +1 -1
  23. package/out/runtime/agents/impl/anthropic.js +109 -3
  24. package/out/runtime/agents/impl/anthropic.js.map +1 -1
  25. package/out/runtime/auth/cognito.d.ts +1 -1
  26. package/out/runtime/auth/cognito.d.ts.map +1 -1
  27. package/out/runtime/auth/cognito.js +1 -1
  28. package/out/runtime/auth/cognito.js.map +1 -1
  29. package/out/runtime/defs.d.ts +4 -0
  30. package/out/runtime/defs.d.ts.map +1 -1
  31. package/out/runtime/defs.js +8 -0
  32. package/out/runtime/defs.js.map +1 -1
  33. package/out/runtime/interpreter.d.ts.map +1 -1
  34. package/out/runtime/interpreter.js +87 -25
  35. package/out/runtime/interpreter.js.map +1 -1
  36. package/out/runtime/jsmodules.d.ts +0 -1
  37. package/out/runtime/jsmodules.d.ts.map +1 -1
  38. package/out/runtime/jsmodules.js +26 -34
  39. package/out/runtime/jsmodules.js.map +1 -1
  40. package/out/runtime/loader.d.ts.map +1 -1
  41. package/out/runtime/loader.js +58 -50
  42. package/out/runtime/loader.js.map +1 -1
  43. package/out/runtime/module.d.ts +2 -2
  44. package/out/runtime/module.d.ts.map +1 -1
  45. package/out/runtime/module.js +19 -3
  46. package/out/runtime/module.js.map +1 -1
  47. package/out/runtime/modules/ai.d.ts +1 -0
  48. package/out/runtime/modules/ai.d.ts.map +1 -1
  49. package/out/runtime/modules/ai.js +7 -1
  50. package/out/runtime/modules/ai.js.map +1 -1
  51. package/out/runtime/modules/core.js +1 -1
  52. package/out/runtime/modules/core.js.map +1 -1
  53. package/out/runtime/openapi.d.ts +16 -0
  54. package/out/runtime/openapi.d.ts.map +1 -0
  55. package/out/runtime/openapi.js +51 -0
  56. package/out/runtime/openapi.js.map +1 -0
  57. package/out/runtime/resolvers/interface.d.ts.map +1 -1
  58. package/out/runtime/resolvers/interface.js +11 -5
  59. package/out/runtime/resolvers/interface.js.map +1 -1
  60. package/out/runtime/resolvers/registry.d.ts +1 -2
  61. package/out/runtime/resolvers/registry.d.ts.map +1 -1
  62. package/out/runtime/resolvers/registry.js +2 -1
  63. package/out/runtime/resolvers/registry.js.map +1 -1
  64. package/out/runtime/state.d.ts +23 -0
  65. package/out/runtime/state.d.ts.map +1 -1
  66. package/out/runtime/state.js +7 -0
  67. package/out/runtime/state.js.map +1 -1
  68. package/out/runtime/util.d.ts +1 -0
  69. package/out/runtime/util.d.ts.map +1 -1
  70. package/out/runtime/util.js +20 -0
  71. package/out/runtime/util.js.map +1 -1
  72. package/out/syntaxes/agentlang.monarch.js +1 -1
  73. package/out/syntaxes/agentlang.monarch.js.map +1 -1
  74. package/package.json +3 -6
  75. package/src/cli/main.ts +34 -6
  76. package/src/language/agentlang.langium +9 -3
  77. package/src/language/generated/ast.ts +55 -4
  78. package/src/language/generated/grammar.ts +251 -171
  79. package/src/language/parser.ts +30 -9
  80. package/src/runtime/agents/common.ts +4 -1
  81. package/src/runtime/agents/impl/anthropic.ts +190 -4
  82. package/src/runtime/auth/cognito.ts +1 -1
  83. package/src/runtime/defs.ts +12 -0
  84. package/src/runtime/interpreter.ts +87 -24
  85. package/src/runtime/jsmodules.ts +26 -37
  86. package/src/runtime/loader.ts +63 -55
  87. package/src/runtime/module.ts +27 -3
  88. package/src/runtime/modules/ai.ts +8 -2
  89. package/src/runtime/modules/core.ts +1 -1
  90. package/src/runtime/openapi.ts +74 -0
  91. package/src/runtime/resolvers/interface.ts +14 -9
  92. package/src/runtime/resolvers/registry.ts +3 -2
  93. package/src/runtime/state.ts +9 -0
  94. package/src/runtime/util.ts +22 -0
  95. package/src/syntaxes/agentlang.monarch.ts +1 -1
  96. package/out/cli/docs.d.ts +0 -2
  97. package/out/cli/docs.d.ts.map +0 -1
  98. package/out/cli/docs.js +0 -236
  99. package/out/cli/docs.js.map +0 -1
  100. package/out/cli/openapi-docs.yml +0 -695
  101. package/out/index.d.ts +0 -19
  102. package/out/index.d.ts.map +0 -1
  103. package/out/index.js +0 -25
  104. package/out/index.js.map +0 -1
@@ -103,16 +103,37 @@ export async function parseWorkflow(workflowDef: string): Promise<WorkflowDefini
103
103
  }
104
104
  }
105
105
 
106
+ export function maybeGetValidationErrors(document: LangiumDocument): string[] | undefined {
107
+ const validationErrors = (document.diagnostics ?? []).filter(e => e.severity === 1);
108
+
109
+ const sls = new Set<number>();
110
+ const scs = new Set<number>();
111
+ if (validationErrors.length > 0) {
112
+ const lineErrs = new Array<string>();
113
+ for (const validationError of validationErrors) {
114
+ if (
115
+ !sls.has(validationError.range.start.line) &&
116
+ !scs.has(validationError.range.start.character)
117
+ ) {
118
+ const s = document.textDocument.getText(validationError.range);
119
+ lineErrs.push(
120
+ `Error on line ${validationError.range.start.line + 1}, column ${validationError.range.start.character + 1}, unexpected token(s) '${s}'`
121
+ );
122
+ sls.add(validationError.range.start.line);
123
+ scs.add(validationError.range.start.character);
124
+ }
125
+ }
126
+
127
+ return lineErrs;
128
+ } else {
129
+ return undefined;
130
+ }
131
+ }
132
+
106
133
  function maybeRaiseParserErrors(document: LangiumDocument) {
107
- if (document.parseResult.lexerErrors.length > 0 || document.parseResult.parserErrors.length > 0) {
108
- const errs: Array<string> = [];
109
- document.parseResult.lexerErrors.forEach((v: any) => {
110
- errs.push(v.message);
111
- });
112
- document.parseResult.parserErrors.forEach((v: any) => {
113
- errs.push(v.message);
114
- });
115
- throw new Error(`There were parser errors: \n ${errs.join('\n')}`);
134
+ const errs = maybeGetValidationErrors(document);
135
+ if (errs) {
136
+ throw new Error(errs.join('\n'));
116
137
  }
117
138
  }
118
139
 
@@ -145,9 +145,12 @@ are invalid, because the alias 'employee' is not defined:
145
145
 
146
146
  A fix for the reference-error is shown below:
147
147
 
148
- {Employee {id? 101}} @as employee;
148
+ {Employee {id? 101}} @as [employee];
149
149
  {SendEmail {to employee.email, body "hello"}}
150
150
 
151
+ Note that the alias for the query is '[employee]' so that the resultset is destructured to select exactly one instance of Employee
152
+ selected into the reference. You must follow this pattern if your goal is to select exactly a single instance.
153
+
151
154
  Keep in mind that the only valid syntax for the 'if' condition is:
152
155
 
153
156
  if (<expr>) {
@@ -12,8 +12,64 @@ export interface AnthropicConfig {
12
12
  defaultHeaders?: Record<string, string>;
13
13
  [key: string]: any;
14
14
  };
15
+
16
+ /**
17
+ * Enable prompt caching to reuse context across API calls.
18
+ * This reduces latency and costs by caching static portions of prompts.
19
+ * Cache has a 5-minute lifetime by default, refreshed on each use.
20
+ * Minimum cacheable length: 1024 tokens for Claude 3.5+, 2048 for Haiku.
21
+ * Beta header: prompt-caching-2024-07-31
22
+ * @see https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching
23
+ */
15
24
  enablePromptCaching?: boolean;
25
+
26
+ /**
27
+ * Cache control type for prompt caching.
28
+ * Currently only 'ephemeral' is supported with 5-minute TTL.
29
+ * Can be extended to 1-hour with extended-cache-ttl-2025-04-11 beta.
30
+ */
16
31
  cacheControl?: 'ephemeral';
32
+
33
+ /**
34
+ * Enable extended thinking mode for Claude to show its reasoning process.
35
+ * When enabled, responses include thinking blocks showing Claude's thought process.
36
+ * Requires minimum budgetTokens of 1024 and counts towards maxTokens.
37
+ * Useful for complex reasoning, problem-solving, and transparency.
38
+ * @see https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking
39
+ */
40
+ enableThinking?: boolean;
41
+
42
+ /**
43
+ * Token budget for thinking mode (minimum 1024).
44
+ * Determines how many tokens Claude can use for internal reasoning.
45
+ * Larger budgets enable more thorough analysis for complex problems.
46
+ * Must be less than maxTokens.
47
+ */
48
+ budgetTokens?: number;
49
+
50
+ /**
51
+ * Enable extended output to generate up to 128,000 tokens in a single response.
52
+ * Useful for long-form content, detailed reports, extensive code generation.
53
+ * Beta header: output-128k-2025-02-19
54
+ * Note: Use streaming to avoid timeouts with long outputs.
55
+ */
56
+ enableExtendedOutput?: boolean;
57
+
58
+ /**
59
+ * Enable interleaved thinking to see Claude's reasoning in real-time during streaming.
60
+ * When combined with extended thinking, thinking blocks are streamed alongside content.
61
+ * Provides transparency into Claude's problem-solving process as it happens.
62
+ * Beta header: interleaved-thinking-2025-05-14
63
+ */
64
+ enableInterleavedThinking?: boolean;
65
+
66
+ /**
67
+ * Enable fine-grained tool streaming for more responsive tool use.
68
+ * Streams partial JSON updates and character-by-character tool parameters.
69
+ * Improves UI responsiveness when Claude invokes tools.
70
+ * Beta header: fine-grained-tool-streaming-2025-05-14
71
+ */
72
+ enableFineGrainedToolStreaming?: boolean;
17
73
  }
18
74
 
19
75
  export class AnthropicProvider implements AgentServiceProvider {
@@ -38,16 +94,58 @@ export class AnthropicProvider implements AgentServiceProvider {
38
94
  chatConfig.clientOptions = this.config.clientOptions;
39
95
  }
40
96
 
97
+ // Configure beta headers based on enabled features
98
+ const betaFeatures: string[] = [];
99
+
100
+ // Prompt caching: Reuse static content across API calls
101
+ // Reduces costs by 90% for cached content, improves latency
41
102
  if (this.config.enablePromptCaching) {
103
+ betaFeatures.push('prompt-caching-2024-07-31');
104
+ }
105
+
106
+ // Extended output: Generate up to 128k tokens (vs standard 8k)
107
+ // Essential for long-form content generation
108
+ if (this.config.enableExtendedOutput) {
109
+ betaFeatures.push('output-128k-2025-02-19');
110
+ }
111
+
112
+ // Interleaved thinking: Stream thinking blocks alongside regular content
113
+ // Shows Claude's reasoning process in real-time during streaming
114
+ if (this.config.enableInterleavedThinking) {
115
+ betaFeatures.push('interleaved-thinking-2025-05-14');
116
+ }
117
+
118
+ // Fine-grained tool streaming: Stream partial tool parameters
119
+ // Provides character-by-character updates for better UX
120
+ if (this.config.enableFineGrainedToolStreaming) {
121
+ betaFeatures.push('fine-grained-tool-streaming-2025-05-14');
122
+ }
123
+
124
+ if (betaFeatures.length > 0) {
42
125
  chatConfig.clientOptions = {
43
126
  ...chatConfig.clientOptions,
44
127
  defaultHeaders: {
45
128
  ...chatConfig.clientOptions?.defaultHeaders,
46
- 'anthropic-beta': 'prompt-caching-2024-07-31',
129
+ 'anthropic-beta': betaFeatures.join(','),
47
130
  },
48
131
  };
49
132
  }
50
133
 
134
+ // Validate thinking configuration if enabled
135
+ // Thinking mode requires careful token budget management
136
+ if (this.config.enableThinking) {
137
+ // Validate budget tokens (minimum 1024 required by API)
138
+ const budgetTokens = Math.max(1024, this.config.budgetTokens || 1024);
139
+
140
+ // Ensure budget tokens don't exceed max tokens
141
+ // This prevents API errors and ensures proper token allocation
142
+ if (budgetTokens >= (this.config.maxTokens || 8192)) {
143
+ throw new Error(
144
+ `budgetTokens (${budgetTokens}) must be less than maxTokens (${this.config.maxTokens || 8192})`
145
+ );
146
+ }
147
+ }
148
+
51
149
  this.model = new ChatAnthropic(chatConfig);
52
150
  }
53
151
 
@@ -59,6 +157,11 @@ export class AnthropicProvider implements AgentServiceProvider {
59
157
  maxRetries: 2,
60
158
  enablePromptCaching: false,
61
159
  cacheControl: 'ephemeral',
160
+ enableThinking: false,
161
+ budgetTokens: 1024, // Minimum budget tokens for thinking mode
162
+ enableExtendedOutput: false,
163
+ enableInterleavedThinking: false,
164
+ enableFineGrainedToolStreaming: false,
62
165
  };
63
166
 
64
167
  if (!config) {
@@ -81,6 +184,31 @@ export class AnthropicProvider implements AgentServiceProvider {
81
184
  defaultConfig.enablePromptCaching,
82
185
  cacheControl:
83
186
  config.get('cacheControl') || config.get('cache_control') || defaultConfig.cacheControl,
187
+ enableThinking:
188
+ config.get('enableThinking') ||
189
+ config.get('enable_thinking') ||
190
+ config.get('thinking') ||
191
+ defaultConfig.enableThinking,
192
+ budgetTokens:
193
+ config.get('budgetTokens') ||
194
+ config.get('budget_tokens') ||
195
+ config.get('thinking_budget') ||
196
+ defaultConfig.budgetTokens,
197
+ enableExtendedOutput:
198
+ config.get('enableExtendedOutput') ||
199
+ config.get('enable_extended_output') ||
200
+ config.get('extendedOutput') ||
201
+ defaultConfig.enableExtendedOutput,
202
+ enableInterleavedThinking:
203
+ config.get('enableInterleavedThinking') ||
204
+ config.get('enable_interleaved_thinking') ||
205
+ config.get('interleavedThinking') ||
206
+ defaultConfig.enableInterleavedThinking,
207
+ enableFineGrainedToolStreaming:
208
+ config.get('enableFineGrainedToolStreaming') ||
209
+ config.get('enable_fine_grained_tool_streaming') ||
210
+ config.get('fineGrainedToolStreaming') ||
211
+ defaultConfig.enableFineGrainedToolStreaming,
84
212
  apiKey,
85
213
  clientOptions: config.get('clientOptions') || config.get('client_options'),
86
214
  };
@@ -99,9 +227,25 @@ export class AnthropicProvider implements AgentServiceProvider {
99
227
  processedMessages = this.applyCacheControl(messages);
100
228
  }
101
229
 
102
- return asAIResponse(await this.model.invoke(processedMessages));
230
+ // Add thinking configuration to the invoke options if enabled
231
+ // Thinking mode is passed as a parameter during invocation, not in constructor
232
+ const invokeOptions: any = {};
233
+ if (this.config.enableThinking) {
234
+ const budgetTokens = Math.max(1024, this.config.budgetTokens || 1024);
235
+ invokeOptions.thinking = {
236
+ type: 'enabled',
237
+ budget_tokens: budgetTokens,
238
+ };
239
+ }
240
+
241
+ return asAIResponse(await this.model.invoke(processedMessages, invokeOptions));
103
242
  }
104
243
 
244
+ /**
245
+ * Apply cache control to messages for prompt caching optimization.
246
+ * Caches system messages with substantial content (>1000 chars) to reduce costs.
247
+ * Cache hits cost 90% less than regular input tokens.
248
+ */
105
249
  private applyCacheControl(messages: BaseMessage[]): BaseMessage[] {
106
250
  // Apply cache control to the last system message if present
107
251
  // This follows Anthropic's recommendation to cache long context at the end of system messages
@@ -112,7 +256,7 @@ export class AnthropicProvider implements AgentServiceProvider {
112
256
  // Find the last system message and apply cache control
113
257
  for (let i = processedMessages.length - 1; i >= 0; i--) {
114
258
  const message = processedMessages[i];
115
- if (message._getType() === 'system') {
259
+ if ((message as any)._getType() === 'system') {
116
260
  // Apply cache control to system message content
117
261
  const content = message.content;
118
262
  if (typeof content === 'string' && content.length > 1000) {
@@ -151,16 +295,58 @@ export class AnthropicProvider implements AgentServiceProvider {
151
295
  chatConfig.clientOptions = this.config.clientOptions;
152
296
  }
153
297
 
298
+ // Configure beta headers based on enabled features
299
+ const betaFeatures: string[] = [];
300
+
301
+ // Prompt caching: Reuse static content across API calls
302
+ // Reduces costs by 90% for cached content, improves latency
154
303
  if (this.config.enablePromptCaching) {
304
+ betaFeatures.push('prompt-caching-2024-07-31');
305
+ }
306
+
307
+ // Extended output: Generate up to 128k tokens (vs standard 8k)
308
+ // Essential for long-form content generation
309
+ if (this.config.enableExtendedOutput) {
310
+ betaFeatures.push('output-128k-2025-02-19');
311
+ }
312
+
313
+ // Interleaved thinking: Stream thinking blocks alongside regular content
314
+ // Shows Claude's reasoning process in real-time during streaming
315
+ if (this.config.enableInterleavedThinking) {
316
+ betaFeatures.push('interleaved-thinking-2025-05-14');
317
+ }
318
+
319
+ // Fine-grained tool streaming: Stream partial tool parameters
320
+ // Provides character-by-character updates for better UX
321
+ if (this.config.enableFineGrainedToolStreaming) {
322
+ betaFeatures.push('fine-grained-tool-streaming-2025-05-14');
323
+ }
324
+
325
+ if (betaFeatures.length > 0) {
155
326
  chatConfig.clientOptions = {
156
327
  ...chatConfig.clientOptions,
157
328
  defaultHeaders: {
158
329
  ...chatConfig.clientOptions?.defaultHeaders,
159
- 'anthropic-beta': 'prompt-caching-2024-07-31',
330
+ 'anthropic-beta': betaFeatures.join(','),
160
331
  },
161
332
  };
162
333
  }
163
334
 
335
+ // Validate thinking configuration if enabled
336
+ // Thinking mode requires careful token budget management
337
+ if (this.config.enableThinking) {
338
+ // Validate budget tokens (minimum 1024 required by API)
339
+ const budgetTokens = Math.max(1024, this.config.budgetTokens || 1024);
340
+
341
+ // Ensure budget tokens don't exceed max tokens
342
+ // This prevents API errors and ensures proper token allocation
343
+ if (budgetTokens >= (this.config.maxTokens || 8192)) {
344
+ throw new Error(
345
+ `budgetTokens (${budgetTokens}) must be less than maxTokens (${this.config.maxTokens || 8192})`
346
+ );
347
+ }
348
+ }
349
+
164
350
  this.model = new ChatAnthropic(chatConfig);
165
351
  }
166
352
  }
@@ -400,7 +400,7 @@ export class CognitoAuth implements AgentlangAuth {
400
400
  }
401
401
  }
402
402
 
403
- async confirmSignup(username: string, confirmationCode: string, env: Environment): Promise<void> {
403
+ async confirmSignup(username: string, confirmationCode: string, _: Environment): Promise<void> {
404
404
  try {
405
405
  const client = new CognitoIdentityProviderClient({
406
406
  region: process.env.AWS_REGION || 'us-west-2',
@@ -76,3 +76,15 @@ export class CodeMismatchError extends Error {
76
76
  super(message || 'The verification code is incorrect. Please try again.', options);
77
77
  }
78
78
  }
79
+
80
+ export let FetchModuleFn: any = undefined;
81
+
82
+ export function setModuleFnFetcher(f: Function) {
83
+ FetchModuleFn = f;
84
+ }
85
+
86
+ export let SetSubscription: any = undefined;
87
+
88
+ export function setSubscriptionFn(f: Function) {
89
+ SetSubscription = f;
90
+ }
@@ -54,6 +54,7 @@ import {
54
54
  DefaultModuleName,
55
55
  escapeFqName,
56
56
  escapeQueryName,
57
+ escapeSpecialChars,
57
58
  fqNameFromPath,
58
59
  isFqName,
59
60
  isPath,
@@ -80,6 +81,7 @@ import {
80
81
  setTimerRunning,
81
82
  } from './modules/core.js';
82
83
  import { invokeModuleFn } from './jsmodules.js';
84
+ import { invokeOpenApiEvent, isOpenApiEventInstance } from './openapi.js';
83
85
 
84
86
  export type Result = any;
85
87
 
@@ -545,6 +547,15 @@ export async function evaluate(
545
547
  }
546
548
  await evaluateStatements(wf.statements, env, continuation);
547
549
  return env.getLastResult();
550
+ } else if (isOpenApiEventInstance(eventInstance)) {
551
+ env = new Environment(eventInstance.name + '.env', activeEnv);
552
+ await handleOpenApiEvent(eventInstance, env);
553
+ const r = env.getLastResult();
554
+ if (continuation) continuation(r);
555
+ return r;
556
+ } else {
557
+ if (continuation) continuation(null);
558
+ return null;
548
559
  }
549
560
  } else {
550
561
  throw new Error('Not an event - ' + eventInstance.name);
@@ -1180,6 +1191,7 @@ async function evaluateCrudMap(crud: CrudMap, env: Environment): Promise<void> {
1180
1191
  }
1181
1192
  } else if (isEventInstance(inst)) {
1182
1193
  if (isAgentEventInstance(inst)) await handleAgentInvocation(inst, env);
1194
+ else if (isOpenApiEventInstance(inst)) await handleOpenApiEvent(inst, env);
1183
1195
  else await evaluate(inst, (result: Result) => env.setLastResult(result), env);
1184
1196
  } else {
1185
1197
  env.setLastResult(inst);
@@ -1299,46 +1311,88 @@ async function walkJoinQueryPattern(
1299
1311
  }
1300
1312
  }
1301
1313
 
1314
+ const MAX_PLANNER_RETRIES = 3;
1315
+
1302
1316
  async function handleAgentInvocation(agentEventInst: Instance, env: Environment): Promise<void> {
1303
1317
  const agent: AgentInstance = await findAgentByName(agentEventInst.name, env);
1304
1318
  await agent.invoke(agentEventInst.lookup('message'), env);
1305
1319
  const r: string | undefined = env.getLastResult();
1306
1320
  const isPlanner = agent.isPlanner();
1307
- const result: string | undefined = isPlanner ? cleanupAgentResponse(r) : r;
1321
+ let result: string | undefined = isPlanner ? cleanupAgentResponse(r) : r;
1308
1322
  if (result) {
1309
1323
  if (isPlanner) {
1310
- logger.debug(`Agent ${agent.name} generated pattern: ${result}`);
1311
- try {
1312
- let rs = result.trim();
1313
- let isWf = rs.startsWith('workflow');
1314
- const isGrp = rs.startsWith('[');
1315
- if (!isWf && !isGrp && rs.indexOf(';') > 0) {
1316
- rs = `workflow T {${rs}}`;
1317
- isWf = true;
1318
- } else if (!isWf && isGrp) {
1319
- const stmts = rs.substring(1, rs.length - 1);
1320
- rs = `workflow T {${stmts}}`;
1321
- isWf = true;
1322
- }
1323
- if (isWf) {
1324
- const wf = await parseWorkflow(rs);
1325
- if (agent.runWorkflows) {
1324
+ let retries = 0;
1325
+ while (true) {
1326
+ logger.debug(`Agent ${agent.name} generated pattern: ${result}`);
1327
+ try {
1328
+ let rs: string = result ? result.trim() : '';
1329
+ let isWf = rs.startsWith('workflow');
1330
+ if (isWf && !agent.runWorkflows) {
1331
+ await parseWorkflow(rs);
1332
+ return;
1333
+ }
1334
+ const isGrp = rs.startsWith('[');
1335
+ if (!isWf && !isGrp && rs.indexOf(';') > 0) {
1336
+ rs = `workflow T {${rs}}`;
1337
+ isWf = true;
1338
+ } else if (!isWf && isGrp) {
1339
+ const stmts = rs.substring(1, rs.length - 1);
1340
+ rs = `workflow T {${stmts}}`;
1341
+ isWf = true;
1342
+ }
1343
+ if (isWf) {
1344
+ const wf = await parseWorkflow(rs);
1326
1345
  await evaluateStatements(wf.statements, env);
1346
+ } else {
1347
+ env.setLastResult(await parseAndEvaluateStatement(rs, undefined, env));
1348
+ }
1349
+ break;
1350
+ } catch (err: any) {
1351
+ if (retries < MAX_PLANNER_RETRIES) {
1352
+ await agent.invoke(`Please fix these errors:\n ${err}`, env);
1353
+ const r: string | undefined = env.getLastResult();
1354
+ result = cleanupAgentResponse(r);
1355
+ ++retries;
1356
+ } else {
1357
+ logger.error(
1358
+ `Failed to evaluate pattern generated by agent ${agent.name} - ${result}, ${err}`
1359
+ );
1360
+ break;
1327
1361
  }
1328
- } else {
1329
- env.setLastResult(await parseAndEvaluateStatement(rs, undefined, env));
1330
1362
  }
1331
- } catch (err: any) {
1332
- logger.error(
1333
- `Failed to evaluate pattern generated by agent ${agent.name} - ${result}, ${err}`
1334
- );
1335
1363
  }
1336
1364
  }
1365
+ if (agent.output) {
1366
+ await pushToAgent(agent.output, env.getLastResult(), env);
1367
+ }
1337
1368
  } else {
1338
1369
  logger.warn(`Agent ${agent.name} failed to generate a response`);
1339
1370
  }
1340
1371
  }
1341
1372
 
1373
+ function agentInputAsString(result: any): string {
1374
+ if (!isString(result)) {
1375
+ if (result instanceof Instance) {
1376
+ return JSON.stringify((result as Instance).asObject());
1377
+ } else if (result instanceof Array) {
1378
+ return `[${(result as Array<any>)
1379
+ .map((r: any) => {
1380
+ return agentInputAsString(r);
1381
+ })
1382
+ .join(',')}]`;
1383
+ } else {
1384
+ return JSON.stringify(result);
1385
+ }
1386
+ }
1387
+ return result;
1388
+ }
1389
+
1390
+ async function pushToAgent(agentName: string, result: any, env: Environment) {
1391
+ const r = escapeSpecialChars(agentInputAsString(result));
1392
+ const pat = `{${agentName} {message "\n${r}"}}`;
1393
+ env.setLastResult(await parseAndEvaluateStatement(pat, undefined, env));
1394
+ }
1395
+
1342
1396
  function cleanupAgentResponse(response: string | undefined): string | undefined {
1343
1397
  if (response) {
1344
1398
  const resp = response.trim();
@@ -1371,6 +1425,15 @@ function cleanupAgentResponse(response: string | undefined): string | undefined
1371
1425
  }
1372
1426
  }
1373
1427
 
1428
+ async function handleOpenApiEvent(eventInst: Instance, env: Environment): Promise<void> {
1429
+ const r = await invokeOpenApiEvent(
1430
+ eventInst.moduleName,
1431
+ eventInst.name,
1432
+ eventInst.attributesAsObject()
1433
+ );
1434
+ env.setLastResult(r);
1435
+ }
1436
+
1374
1437
  async function evaluateUpsert(crud: CrudMap, env: Environment): Promise<void> {
1375
1438
  env.setInUpsertMode(true);
1376
1439
  try {
@@ -1634,7 +1697,7 @@ async function runPrePostEvents(
1634
1697
  if (env.hasHandlers()) {
1635
1698
  throw reason;
1636
1699
  } else {
1637
- logger.error(`${prefix}: ${reason}`);
1700
+ throw new Error(`${prefix}: ${reason}`);
1638
1701
  }
1639
1702
  };
1640
1703
  if (trigInfo.async) {
@@ -1,7 +1,7 @@
1
1
  import { logger } from './logger.js';
2
- import { setSubscription } from './resolvers/registry.js';
3
2
  import { now, splitRefs } from './util.js';
4
3
  import { isNodeEnv } from '../utils/runtime.js';
4
+ import { setModuleFnFetcher } from './defs.js';
5
5
 
6
6
  let dirname: any = undefined;
7
7
  let sep: any = undefined;
@@ -26,39 +26,37 @@ const importedModules = new Map<string, any>();
26
26
 
27
27
  // Usage: importModule("./mymodels/acme.js")
28
28
  export async function importModule(path: string, name: string, moduleFileName?: string) {
29
- if (importedModules.has(name)) {
30
- logger.warn(`Alias '${name}' will overwrite a previously imported module`);
31
- }
32
- if (moduleFileName) {
33
- let s: string = dirname(moduleFileName);
34
- if (s.startsWith('./')) {
35
- s = s.substring(2);
29
+ if (isNodeEnv) {
30
+ if (importedModules.has(name)) {
31
+ logger.warn(`Alias '${name}' will overwrite a previously imported module`);
36
32
  }
37
- path = `${s}${sep}${path}`;
38
- }
39
- if ((path.startsWith(sep) || path.startsWith('.')) && moduleFileName) {
40
- path = process.cwd() + sep + path;
33
+ if (moduleFileName) {
34
+ let s: string = dirname(moduleFileName);
35
+ if (s.startsWith('./')) {
36
+ s = s.substring(2);
37
+ } else if (s == '.') {
38
+ s = process.cwd();
39
+ }
40
+ path = `${s}${sep}${path}`;
41
+ }
42
+ if (!(path.startsWith(sep) || path.startsWith('.'))) {
43
+ path = process.cwd() + sep + path;
44
+ }
45
+ const m = await import(/* @vite-ignore */ path);
46
+ importedModules.set(name, m);
47
+ // e.g of dynamic fn-call:
48
+ //// let f = eval("(a, b) => m.add(a, b)");
49
+ //// console.log(f(10, 20))
50
+ return m;
51
+ } else {
52
+ return {};
41
53
  }
42
- const m = await import(/* @vite-ignore */ path);
43
- importedModules.set(name, m);
44
- // e.g of dynamic fn-call:
45
- //// let f = eval("(a, b) => m.add(a, b)");
46
- //// console.log(f(10, 20))
47
- return m;
48
54
  }
49
55
 
50
56
  export function moduleImported(moduleName: string): boolean {
51
57
  return importedModules.has(moduleName);
52
58
  }
53
59
 
54
- const ReservedImports = new Set<string>(['resolvers']);
55
-
56
- export function validateImportName(n: string) {
57
- if (ReservedImports.has(n)) {
58
- throw new Error(`${n} is an import reserved by the runtime`);
59
- }
60
- }
61
-
62
60
  function maybeEvalFunction(fnName: string): Function | undefined {
63
61
  try {
64
62
  return eval(fnName);
@@ -68,14 +66,6 @@ function maybeEvalFunction(fnName: string): Function | undefined {
68
66
  }
69
67
  }
70
68
 
71
- function invokeReservedFn(moduleName: string, fnName: string, args: Array<any> | null) {
72
- if (moduleName == 'resolvers' && fnName == 'setSubscription' && args != null) {
73
- return setSubscription(args[0], args[1]);
74
- } else {
75
- throw new Error(`Failed to call ${moduleName}.${fnName} with the given arguments`);
76
- }
77
- }
78
-
79
69
  async function invokeBuiltInFn(fnName: string, args: Array<any> | null, isAsync: boolean = false) {
80
70
  if (fnName == 'now') {
81
71
  return now();
@@ -112,9 +102,6 @@ export async function invokeModuleFn(
112
102
  }
113
103
  }
114
104
  const mname = refs[0];
115
- if (ReservedImports.has(mname)) {
116
- return invokeReservedFn(mname, refs[1], args);
117
- }
118
105
  const m = importedModules.get(mname);
119
106
  if (m != undefined) {
120
107
  const f = m[refs[1]];
@@ -151,3 +138,5 @@ export function getModuleFn(fqFnName: string): Function | undefined {
151
138
  return m[refs[1]];
152
139
  } else return undefined;
153
140
  }
141
+
142
+ setModuleFnFetcher(getModuleFn);