agentlang 0.0.40 → 0.0.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/extension/main.cjs +250 -250
- package/out/extension/main.cjs.map +2 -2
- package/out/language/generated/ast.d.ts +57 -21
- package/out/language/generated/ast.d.ts.map +1 -1
- package/out/language/generated/ast.js +80 -26
- package/out/language/generated/ast.js.map +1 -1
- package/out/language/generated/grammar.d.ts.map +1 -1
- package/out/language/generated/grammar.js +337 -115
- package/out/language/generated/grammar.js.map +1 -1
- package/out/language/main.cjs +900 -637
- package/out/language/main.cjs.map +3 -3
- package/out/language/syntax.d.ts +7 -0
- package/out/language/syntax.d.ts.map +1 -1
- package/out/language/syntax.js +16 -0
- package/out/language/syntax.js.map +1 -1
- package/out/runtime/agents/common.d.ts +9 -1
- package/out/runtime/agents/common.d.ts.map +1 -1
- package/out/runtime/agents/common.js +83 -1
- package/out/runtime/agents/common.js.map +1 -1
- package/out/runtime/agents/registry.js +3 -1
- package/out/runtime/agents/registry.js.map +1 -1
- package/out/runtime/auth/cognito.js +1 -1
- package/out/runtime/defs.d.ts +1 -0
- package/out/runtime/defs.d.ts.map +1 -1
- package/out/runtime/defs.js +1 -0
- package/out/runtime/defs.js.map +1 -1
- package/out/runtime/interpreter.d.ts +5 -0
- package/out/runtime/interpreter.d.ts.map +1 -1
- package/out/runtime/interpreter.js +81 -9
- package/out/runtime/interpreter.js.map +1 -1
- package/out/runtime/loader.d.ts.map +1 -1
- package/out/runtime/loader.js +111 -40
- package/out/runtime/loader.js.map +1 -1
- package/out/runtime/module.d.ts +24 -2
- package/out/runtime/module.d.ts.map +1 -1
- package/out/runtime/module.js +103 -12
- package/out/runtime/module.js.map +1 -1
- package/out/runtime/modules/ai.d.ts +9 -0
- package/out/runtime/modules/ai.d.ts.map +1 -1
- package/out/runtime/modules/ai.js +50 -9
- package/out/runtime/modules/ai.js.map +1 -1
- package/out/runtime/modules/auth.d.ts.map +1 -1
- package/out/runtime/modules/auth.js.map +1 -1
- package/out/runtime/modules/core.d.ts +1 -0
- package/out/runtime/modules/core.d.ts.map +1 -1
- package/out/runtime/modules/core.js +15 -5
- package/out/runtime/modules/core.js.map +1 -1
- package/out/runtime/resolvers/authinfo.d.ts +8 -0
- package/out/runtime/resolvers/authinfo.d.ts.map +1 -0
- package/out/runtime/resolvers/authinfo.js +14 -0
- package/out/runtime/resolvers/authinfo.js.map +1 -0
- package/out/runtime/resolvers/interface.d.ts +1 -7
- package/out/runtime/resolvers/interface.d.ts.map +1 -1
- package/out/runtime/resolvers/interface.js +3 -16
- package/out/runtime/resolvers/interface.js.map +1 -1
- package/out/runtime/resolvers/sqldb/database.d.ts +3 -1
- package/out/runtime/resolvers/sqldb/database.d.ts.map +1 -1
- package/out/runtime/resolvers/sqldb/database.js +72 -3
- package/out/runtime/resolvers/sqldb/database.js.map +1 -1
- package/out/syntaxes/agentlang.monarch.js +3 -3
- package/out/syntaxes/agentlang.monarch.js.map +1 -1
- package/package.json +156 -153
- package/src/language/agentlang.langium +12 -4
- package/src/language/generated/ast.ts +144 -49
- package/src/language/generated/grammar.ts +337 -115
- package/src/language/syntax.ts +21 -0
- package/src/runtime/agents/common.ts +91 -1
- package/src/runtime/agents/registry.ts +3 -3
- package/src/runtime/auth/cognito.ts +3 -3
- package/src/runtime/defs.ts +1 -0
- package/src/runtime/interpreter.ts +117 -8
- package/src/runtime/loader.ts +113 -39
- package/src/runtime/module.ts +123 -13
- package/src/runtime/modules/ai.ts +67 -11
- package/src/runtime/modules/auth.ts +6 -1
- package/src/runtime/modules/core.ts +16 -4
- package/src/runtime/resolvers/authinfo.ts +14 -0
- package/src/runtime/resolvers/interface.ts +2 -19
- package/src/runtime/resolvers/sqldb/database.ts +76 -3
- package/src/syntaxes/agentlang.monarch.ts +3 -3
package/src/language/syntax.ts
CHANGED
|
@@ -715,3 +715,24 @@ function patternsToString(body: BasePattern[], sep = ';\n'): string {
|
|
|
715
715
|
})
|
|
716
716
|
.join(sep);
|
|
717
717
|
}
|
|
718
|
+
|
|
719
|
+
export class FlowStepPattern extends BasePattern {
|
|
720
|
+
first: string;
|
|
721
|
+
next: string;
|
|
722
|
+
condition?: string;
|
|
723
|
+
|
|
724
|
+
constructor(first: string, next: string, condition?: string) {
|
|
725
|
+
super();
|
|
726
|
+
this.first = first;
|
|
727
|
+
this.next = next;
|
|
728
|
+
this.condition = condition;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
override toString(): string {
|
|
732
|
+
if (this.condition) {
|
|
733
|
+
return `${this.first} --> ${this.condition} ${this.next}`;
|
|
734
|
+
} else {
|
|
735
|
+
return `${this.first} --> ${this.next}`;
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
}
|
|
@@ -250,7 +250,7 @@ workflow sendEmail {
|
|
|
250
250
|
{email {to emp.email body "please call me as soon as possible"}}
|
|
251
251
|
}
|
|
252
252
|
|
|
253
|
-
The point is use the immediate context to fill-in values in generated patterns, as much as possible.
|
|
253
|
+
The point is, use the immediate context to fill-in values in generated patterns, as much as possible.
|
|
254
254
|
|
|
255
255
|
Also generate a workflow only if required explicitly by the user or the contextual information is incomplete. Otherwise, just return an array of patterns.
|
|
256
256
|
As an example, if the user request is "send an email to employee 101 with this message - 'please call me as soon as possible'", you must return:
|
|
@@ -263,3 +263,93 @@ You MUST separate each pattern in the array with a semi-colon (;) and never use
|
|
|
263
263
|
Now consider the following module definition and generate appropriate patterns in response to the user instructions. You must return only valid patterns or workflows,
|
|
264
264
|
no other descriptive text or comments are needed.
|
|
265
265
|
`;
|
|
266
|
+
|
|
267
|
+
export const FlowExecInstructions = `The following is the textual representation of a flowchart.
|
|
268
|
+
|
|
269
|
+
checkOrder --> "ProductA" acceptOrder
|
|
270
|
+
checkOrder --> "ProductB" acceptOrder
|
|
271
|
+
checkOrder --> "ProductC" rejectOrder
|
|
272
|
+
acceptOrder --> sendPaymentLinkToCustomer
|
|
273
|
+
rejectOrder --> sendRejectionEmailToCustomer
|
|
274
|
+
|
|
275
|
+
Along with this flowchart, you'll be passed a "context", which contain the steps in the flowchart that was executed so far, along with
|
|
276
|
+
their results. Based on the context, you need to return the name of the step that needs to execute next. If you have reached the end
|
|
277
|
+
of the chart, return 'DONE'.
|
|
278
|
+
|
|
279
|
+
At the beginning of the execution, the context will contain only the order information, say something like:
|
|
280
|
+
|
|
281
|
+
OrderNo: 101, Item: "ProductB", customerEmail: "manager@acme.com"
|
|
282
|
+
|
|
283
|
+
This means you have to return 'checkOrder' as the next step (i.e you move the root node of the flowchart).
|
|
284
|
+
After the step checkOrder executes, you'll be passed the following context:
|
|
285
|
+
|
|
286
|
+
orderNo: 101, Item: "ProductB", customerEmail: "manager@acme.com"
|
|
287
|
+
checkOrder --> "ProductB"
|
|
288
|
+
|
|
289
|
+
Now you can infer from the context that if the result of checkOrder is either "ProductA" or "ProductB", you must move to the step 'acceptOrder'.
|
|
290
|
+
So you return 'acceptOrder'. After this, you'll return the updated context as:
|
|
291
|
+
|
|
292
|
+
OrderNo: 101, Item: "ProductB", customerEmail: "manager@acme.com"
|
|
293
|
+
checkOrder --> "ProductB"
|
|
294
|
+
acceptOrder --> {orderNo: 101, customerEmail: "manager@acme.com", acceptedOn: "2025-07-01"}
|
|
295
|
+
|
|
296
|
+
You see that 'acceptOrder' has produced the result '{orderNo: 101, customerEmail: "manager@acme.com", acceptedOn: "2025-07-01"}' - but from the flowchart you know that, whatever the result of 'acceptOrder',
|
|
297
|
+
you have to move to the 'sendPaymentLinkToCustomer' step and so you return 'sendPaymentLinkToCustomer'.
|
|
298
|
+
|
|
299
|
+
The next context you'll see will be:
|
|
300
|
+
|
|
301
|
+
OrderNo: 101, Item: "ProductB", customerEmail: "manager@acme.com"
|
|
302
|
+
checkOrder --> "ProductB"
|
|
303
|
+
acceptOrder --> {orderNo: 101, customerEmail: "manager@acme.com", acceptedOn: "2025-07-01"}
|
|
304
|
+
sendPaymentLinkToCustomer --> "manager@acme.com"
|
|
305
|
+
|
|
306
|
+
The 'sendPaymentLinkToCustomer' has returned the customer email. You look at the flowchart and detect that, whatever the return value of
|
|
307
|
+
'sendPaymentLinkToCustomer' there is nothing else to do. So you return 'DONE'.
|
|
308
|
+
|
|
309
|
+
Generally a flowchart has the following two types of entries:
|
|
310
|
+
1. a --> b, meaning after step 'a' do step 'b'.
|
|
311
|
+
2. a --> "x" b - this means if 'a' returns the string "x", then do step 'b'.
|
|
312
|
+
If you detect that you have reached the end of the chart, return 'DONE'. Otherwise, return only the name of the next step. Never return
|
|
313
|
+
any additional description, direction or comments.
|
|
314
|
+
`;
|
|
315
|
+
|
|
316
|
+
export type FlowSpec = string;
|
|
317
|
+
export type FlowStep = string;
|
|
318
|
+
|
|
319
|
+
const AgentFlows = new Map<string, string[]>();
|
|
320
|
+
const FlowRegistry = new Map<string, FlowSpec>();
|
|
321
|
+
|
|
322
|
+
export function registerFlow(name: string, flow: FlowSpec): string {
|
|
323
|
+
FlowRegistry.set(name, flow);
|
|
324
|
+
return name;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
export function getFlow(name: string): FlowSpec | undefined {
|
|
328
|
+
return FlowRegistry.get(name);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export function registerAgentFlow(agentName: string, flowSpecName: string): string {
|
|
332
|
+
let currentFlows = AgentFlows.get(agentName);
|
|
333
|
+
if (currentFlows) {
|
|
334
|
+
currentFlows.push(flowSpecName);
|
|
335
|
+
} else {
|
|
336
|
+
currentFlows = new Array<string>();
|
|
337
|
+
currentFlows.push(flowSpecName);
|
|
338
|
+
}
|
|
339
|
+
AgentFlows.set(agentName, currentFlows);
|
|
340
|
+
return agentName;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Return the first flow registered with the agent.
|
|
344
|
+
export function getAgentFlow(agentName: string): FlowSpec | undefined {
|
|
345
|
+
const currentFlows = AgentFlows.get(agentName);
|
|
346
|
+
if (currentFlows) {
|
|
347
|
+
return getFlow(currentFlows[0]);
|
|
348
|
+
} else {
|
|
349
|
+
return undefined;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
export function getAllAgentFlows(agentName: string): FlowSpec[] | undefined {
|
|
354
|
+
return AgentFlows.get(agentName);
|
|
355
|
+
}
|
|
@@ -18,9 +18,9 @@ export function provider(service: string) {
|
|
|
18
18
|
p = Providers.get(availableService);
|
|
19
19
|
if (p) return p;
|
|
20
20
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
);
|
|
21
|
+
const errorMessage = `${service} provider requested but ${service.toUpperCase()}_API_KEY not found. Available providers: ${getAvailableProviders().join(', ') || 'none'}`;
|
|
22
|
+
console.error(errorMessage);
|
|
23
|
+
throw new Error(errorMessage);
|
|
24
24
|
}
|
|
25
25
|
} else {
|
|
26
26
|
throw new Error(`No provider found for ${service}`);
|
|
@@ -543,11 +543,11 @@ export class CognitoAuth implements AgentlangAuth {
|
|
|
543
543
|
const idtok = result.getIdToken();
|
|
544
544
|
const idToken = idtok.getJwtToken();
|
|
545
545
|
const idTokenPayload = idtok.decodePayload();
|
|
546
|
-
|
|
546
|
+
|
|
547
547
|
const firstName = idTokenPayload['given_name'] || idTokenPayload['name'] || '';
|
|
548
548
|
const lastName = idTokenPayload['family_name'] || '';
|
|
549
549
|
const userGroups = idTokenPayload['cognito:groups'];
|
|
550
|
-
|
|
550
|
+
|
|
551
551
|
let localUser = await findUserByEmail(username, env);
|
|
552
552
|
if (!localUser) {
|
|
553
553
|
localUser = await ensureUser(username, firstName, lastName, env);
|
|
@@ -891,7 +891,7 @@ export class CognitoAuth implements AgentlangAuth {
|
|
|
891
891
|
try {
|
|
892
892
|
// Get additional user details from Cognito
|
|
893
893
|
const client = new CognitoIdentityProviderClient({
|
|
894
|
-
region: process.env.AWS_REGION || 'us-west-2'
|
|
894
|
+
region: process.env.AWS_REGION || 'us-west-2',
|
|
895
895
|
});
|
|
896
896
|
|
|
897
897
|
const command = new AdminGetUserCommand({
|
package/src/runtime/defs.ts
CHANGED
|
@@ -47,7 +47,8 @@ import {
|
|
|
47
47
|
Relationship,
|
|
48
48
|
Workflow,
|
|
49
49
|
} from './module.js';
|
|
50
|
-
import { JoinInfo, Resolver
|
|
50
|
+
import { JoinInfo, Resolver } from './resolvers/interface.js';
|
|
51
|
+
import { ResolverAuthInfo } from './resolvers/authinfo.js';
|
|
51
52
|
import { SqlDbResolver } from './resolvers/sqldb/impl.js';
|
|
52
53
|
import {
|
|
53
54
|
CrudType,
|
|
@@ -72,7 +73,12 @@ import { parseStatement, parseWorkflow } from '../language/parser.js';
|
|
|
72
73
|
import { ActiveSessionInfo, AdminSession, AdminUserId } from './auth/defs.js';
|
|
73
74
|
import { AgentInstance, AgentEntityName, AgentFqName, findAgentByName } from './modules/ai.js';
|
|
74
75
|
import { logger } from './logger.js';
|
|
75
|
-
import {
|
|
76
|
+
import {
|
|
77
|
+
FlowSuspensionTag,
|
|
78
|
+
ParentAttributeName,
|
|
79
|
+
PathAttributeName,
|
|
80
|
+
PathAttributeNameQuery,
|
|
81
|
+
} from './defs.js';
|
|
76
82
|
import {
|
|
77
83
|
addCreateAudit,
|
|
78
84
|
addDeleteAudit,
|
|
@@ -84,6 +90,7 @@ import {
|
|
|
84
90
|
import { invokeModuleFn } from './jsmodules.js';
|
|
85
91
|
import { invokeOpenApiEvent, isOpenApiEventInstance } from './openapi.js';
|
|
86
92
|
import { fetchDoc } from './docs.js';
|
|
93
|
+
import { FlowSpec, FlowStep, getAgentFlow } from './agents/common.js';
|
|
87
94
|
|
|
88
95
|
export type Result = any;
|
|
89
96
|
|
|
@@ -156,6 +163,7 @@ export class Environment extends Instance {
|
|
|
156
163
|
this.activeResolvers = new Map<string, Resolver>();
|
|
157
164
|
this.activeTransactions = new Map<string, string>();
|
|
158
165
|
this.activeCatchHandlers = new Array<CatchHandlers>();
|
|
166
|
+
this.attributes.set('process', process);
|
|
159
167
|
}
|
|
160
168
|
}
|
|
161
169
|
|
|
@@ -238,6 +246,22 @@ export class Environment extends Instance {
|
|
|
238
246
|
return this;
|
|
239
247
|
}
|
|
240
248
|
|
|
249
|
+
private static FlowContextTag = 'flow-context';
|
|
250
|
+
|
|
251
|
+
setFlowContext(s: string): Environment {
|
|
252
|
+
this.attributes.set(Environment.FlowContextTag, s);
|
|
253
|
+
return this;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
resetFlowContext(): Environment {
|
|
257
|
+
this.attributes.set(Environment.FlowContextTag, undefined);
|
|
258
|
+
return this;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
getFlowContext(): string | undefined {
|
|
262
|
+
return this.attributes.get(Environment.FlowContextTag);
|
|
263
|
+
}
|
|
264
|
+
|
|
241
265
|
static SuspensionUserData = '^';
|
|
242
266
|
|
|
243
267
|
bindSuspensionUserData(userData: string): Environment {
|
|
@@ -1093,7 +1117,7 @@ async function evaluateCrudMap(crud: CrudMap, env: Environment): Promise<void> {
|
|
|
1093
1117
|
await runPostCreateEvents(inst, env);
|
|
1094
1118
|
}
|
|
1095
1119
|
if (r && entryName == AgentEntityName) {
|
|
1096
|
-
defineAgentEvent(env.getActiveModuleName(), r.lookup('name'));
|
|
1120
|
+
defineAgentEvent(env.getActiveModuleName(), r.lookup('name'), r.lookup('instruction'));
|
|
1097
1121
|
}
|
|
1098
1122
|
env.setLastResult(r);
|
|
1099
1123
|
const betRelInfo: BetweenRelInfo | undefined = env.getBetweenRelInfo();
|
|
@@ -1365,10 +1389,9 @@ async function walkJoinQueryPattern(
|
|
|
1365
1389
|
|
|
1366
1390
|
const MAX_PLANNER_RETRIES = 3;
|
|
1367
1391
|
|
|
1368
|
-
async function
|
|
1369
|
-
const
|
|
1370
|
-
|
|
1371
|
-
const msg: string = isString(origMsg) ? origMsg : agentInputAsString(origMsg);
|
|
1392
|
+
async function agentInvoke(agent: AgentInstance, msg: string, env: Environment): Promise<void> {
|
|
1393
|
+
const flowContext = env.getFlowContext();
|
|
1394
|
+
msg = flowContext ? `context: ${flowContext}\n${msg}` : msg;
|
|
1372
1395
|
await agent.invoke(msg, env);
|
|
1373
1396
|
const r: string | undefined = env.getLastResult();
|
|
1374
1397
|
const isPlanner = agent.isPlanner();
|
|
@@ -1420,7 +1443,93 @@ async function handleAgentInvocation(agentEventInst: Instance, env: Environment)
|
|
|
1420
1443
|
await pushToAgent(agent.output, env.getLastResult(), env);
|
|
1421
1444
|
}
|
|
1422
1445
|
} else {
|
|
1423
|
-
|
|
1446
|
+
throw new Error(`Agent ${agent.name} failed to generate a response`);
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
async function handleAgentInvocation(agentEventInst: Instance, env: Environment): Promise<void> {
|
|
1451
|
+
const agent: AgentInstance = await findAgentByName(agentEventInst.name, env);
|
|
1452
|
+
const origMsg: any = agentEventInst.lookup('message');
|
|
1453
|
+
const msg: string = isString(origMsg) ? origMsg : agentInputAsString(origMsg);
|
|
1454
|
+
const flow = getAgentFlow(agent.name);
|
|
1455
|
+
if (flow) {
|
|
1456
|
+
await handleAgentInvocationWithFlow(agent, flow, msg, env);
|
|
1457
|
+
} else {
|
|
1458
|
+
await agentInvoke(agent, msg, env).catch((reason: any) => {
|
|
1459
|
+
logger.warn(reason);
|
|
1460
|
+
});
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
async function handleAgentInvocationWithFlow(
|
|
1465
|
+
rootAgent: AgentInstance,
|
|
1466
|
+
flow: FlowSpec,
|
|
1467
|
+
msg: string,
|
|
1468
|
+
env: Environment
|
|
1469
|
+
): Promise<void> {
|
|
1470
|
+
await iterateOnFlow(flow, rootAgent, msg, env);
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
async function saveFlowSuspension(
|
|
1474
|
+
agent: AgentInstance,
|
|
1475
|
+
context: string,
|
|
1476
|
+
step: FlowStep,
|
|
1477
|
+
env: Environment
|
|
1478
|
+
): Promise<void> {
|
|
1479
|
+
const suspId = await createSuspension(
|
|
1480
|
+
env.getSuspensionId(),
|
|
1481
|
+
[FlowSuspensionTag, agent.name, step, context],
|
|
1482
|
+
env
|
|
1483
|
+
);
|
|
1484
|
+
env.setLastResult({ suspension: suspId || 'null' });
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
export async function restartFlow(
|
|
1488
|
+
flowContext: string[],
|
|
1489
|
+
userData: string,
|
|
1490
|
+
env: Environment
|
|
1491
|
+
): Promise<void> {
|
|
1492
|
+
const [_, agentName, step, ctx] = flowContext;
|
|
1493
|
+
const flow = getAgentFlow(agentName);
|
|
1494
|
+
if (flow) {
|
|
1495
|
+
const rootAgent = await findAgentByName(agentName, env);
|
|
1496
|
+
const newCtx = `${ctx}\n${step} --> ${userData}\n`;
|
|
1497
|
+
await iterateOnFlow(flow, rootAgent, newCtx, env);
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
const MaxFlowSteps = 25;
|
|
1502
|
+
|
|
1503
|
+
async function iterateOnFlow(
|
|
1504
|
+
flow: FlowSpec,
|
|
1505
|
+
rootAgent: AgentInstance,
|
|
1506
|
+
msg: string,
|
|
1507
|
+
env: Environment
|
|
1508
|
+
): Promise<void> {
|
|
1509
|
+
rootAgent.disableSession();
|
|
1510
|
+
const s = `Now consider the following flowchart and context:\n${flow}\n\n${msg}`;
|
|
1511
|
+
await agentInvoke(rootAgent, s, env);
|
|
1512
|
+
let step = env.getLastResult();
|
|
1513
|
+
let context = msg;
|
|
1514
|
+
let stepc = 0;
|
|
1515
|
+
while (step != 'DONE') {
|
|
1516
|
+
if (stepc > MaxFlowSteps) {
|
|
1517
|
+
throw new Error(`Flow execution exceeded maximum steps limit`);
|
|
1518
|
+
}
|
|
1519
|
+
++stepc;
|
|
1520
|
+
const agent = AgentInstance.FromFlowStep(step, rootAgent);
|
|
1521
|
+
agent.disableSession();
|
|
1522
|
+
env.setFlowContext(context);
|
|
1523
|
+
await agentInvoke(agent, '', env);
|
|
1524
|
+
env.resetFlowContext();
|
|
1525
|
+
if (env.isSuspended()) {
|
|
1526
|
+
await saveFlowSuspension(rootAgent, context, step, env);
|
|
1527
|
+
return;
|
|
1528
|
+
}
|
|
1529
|
+
const r = env.getLastResult();
|
|
1530
|
+
context = `${context}\n${step} --> ${agentInputAsString(r)}\n`;
|
|
1531
|
+
await agentInvoke(rootAgent, `${s}\n${context}`, env);
|
|
1532
|
+
step = env.getLastResult();
|
|
1424
1533
|
}
|
|
1425
1534
|
}
|
|
1426
1535
|
|
package/src/runtime/loader.ts
CHANGED
|
@@ -22,8 +22,13 @@ import {
|
|
|
22
22
|
isResolverDefinition,
|
|
23
23
|
ResolverDefinition,
|
|
24
24
|
ResolverMethodSpec,
|
|
25
|
-
|
|
25
|
+
GenericPropertyDef,
|
|
26
26
|
isLiteral,
|
|
27
|
+
ArrayLiteral,
|
|
28
|
+
MapEntry,
|
|
29
|
+
Expr,
|
|
30
|
+
FlowDefinition,
|
|
31
|
+
isFlowDefinition,
|
|
27
32
|
} from '../language/generated/ast.js';
|
|
28
33
|
import {
|
|
29
34
|
addEntity,
|
|
@@ -43,10 +48,12 @@ import {
|
|
|
43
48
|
removeModule,
|
|
44
49
|
newInstanceAttributes,
|
|
45
50
|
addAgent,
|
|
51
|
+
fetchModule,
|
|
46
52
|
} from './module.js';
|
|
47
53
|
import {
|
|
48
54
|
escapeSpecialChars,
|
|
49
55
|
findRbacSchema,
|
|
56
|
+
isFqName,
|
|
50
57
|
isString,
|
|
51
58
|
makeFqName,
|
|
52
59
|
maybeExtends,
|
|
@@ -69,6 +76,7 @@ import { getModuleFn, importModule } from './jsmodules.js';
|
|
|
69
76
|
import { SetSubscription } from './defs.js';
|
|
70
77
|
import { ExtendedFileSystem } from '../utils/fs/interfaces.js';
|
|
71
78
|
import z from 'zod';
|
|
79
|
+
import { registerAgentFlow, registerFlow } from './agents/common.js';
|
|
72
80
|
|
|
73
81
|
export async function extractDocument(
|
|
74
82
|
fileName: string,
|
|
@@ -288,6 +296,7 @@ export async function loadCoreModules() {
|
|
|
288
296
|
|
|
289
297
|
async function loadModule(fileName: string, fsOptions?: any, callback?: Function): Promise<Module> {
|
|
290
298
|
// Initialize filesystem if not already done
|
|
299
|
+
console.log(`loading ${fileName}`);
|
|
291
300
|
const fs = await getFileSystem(fsOptions);
|
|
292
301
|
|
|
293
302
|
const fsAdapter = getFsAdapter(fs);
|
|
@@ -418,7 +427,7 @@ export function addWorkflowFromDef(def: WorkflowDefinition, moduleName: string):
|
|
|
418
427
|
|
|
419
428
|
const StandaloneStatements = new Map<string, Statement[]>();
|
|
420
429
|
|
|
421
|
-
function addStandaloneStatement(stmt: Statement, moduleName: string) {
|
|
430
|
+
function addStandaloneStatement(stmt: Statement, moduleName: string, userDefined = true) {
|
|
422
431
|
let stmts: Array<Statement> | undefined = StandaloneStatements.get(moduleName);
|
|
423
432
|
if (stmts == undefined) {
|
|
424
433
|
stmts = new Array<Statement>();
|
|
@@ -427,6 +436,10 @@ function addStandaloneStatement(stmt: Statement, moduleName: string) {
|
|
|
427
436
|
if (!StandaloneStatements.has(moduleName)) {
|
|
428
437
|
StandaloneStatements.set(moduleName, stmts);
|
|
429
438
|
}
|
|
439
|
+
if (userDefined) {
|
|
440
|
+
const m = fetchModule(moduleName);
|
|
441
|
+
m.addStandaloneStatement(stmt);
|
|
442
|
+
}
|
|
430
443
|
}
|
|
431
444
|
|
|
432
445
|
export async function runStandaloneStatements() {
|
|
@@ -455,45 +468,55 @@ async function addAgentDefinition(def: AgentDefinition, moduleName: string) {
|
|
|
455
468
|
const attrsStrs = new Array<string>();
|
|
456
469
|
attrsStrs.push(`name "${name}"`);
|
|
457
470
|
const attrs = newInstanceAttributes();
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
.
|
|
471
|
+
attrsStrs.push(`moduleName "${moduleName}"`);
|
|
472
|
+
attrs.set('moduleName', moduleName);
|
|
473
|
+
def.body?.attributes.forEach((apdef: GenericPropertyDef) => {
|
|
474
|
+
if (apdef.name == 'flows') {
|
|
475
|
+
let fnames: string | undefined = undefined;
|
|
476
|
+
if (apdef.value.array) {
|
|
477
|
+
fnames = processAgentArray(apdef.value.array, name);
|
|
478
|
+
} else {
|
|
479
|
+
fnames = apdef.value.id || apdef.value.str;
|
|
480
|
+
}
|
|
481
|
+
if (fnames) {
|
|
482
|
+
fnames.split(',').forEach((n: string) => {
|
|
483
|
+
n = n.trim();
|
|
484
|
+
const fqn = isFqName(n) ? n : `${moduleName}/${n}`;
|
|
485
|
+
registerAgentFlow(name, fqn);
|
|
486
|
+
});
|
|
487
|
+
attrsStrs.push(`type "flow-exec"`);
|
|
488
|
+
attrs.set('type', 'flow-exec');
|
|
489
|
+
attrsStrs.push(`flows "${fnames}"`);
|
|
490
|
+
attrs.set('flows', fnames);
|
|
491
|
+
} else {
|
|
492
|
+
throw new Error(`Invalid flows list in agent ${name}`);
|
|
493
|
+
}
|
|
476
494
|
} else {
|
|
477
|
-
v =
|
|
495
|
+
let v: any = undefined;
|
|
496
|
+
if (apdef.value.array) {
|
|
497
|
+
v = processAgentArray(apdef.value.array, name);
|
|
498
|
+
} else {
|
|
499
|
+
v = apdef.value.str || apdef.value.id || apdef.value.ref || apdef.value.num;
|
|
500
|
+
if (v == undefined) {
|
|
501
|
+
v = apdef.value.bool;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
478
504
|
if (v == undefined) {
|
|
479
|
-
|
|
505
|
+
throw new Error(`Cannot initialize agent ${name}, only literals can be set for attributes`);
|
|
480
506
|
}
|
|
507
|
+
if (llmName == undefined && apdef.name == 'llm') {
|
|
508
|
+
llmName = v;
|
|
509
|
+
hasUserLlm = true;
|
|
510
|
+
}
|
|
511
|
+
const ov = v;
|
|
512
|
+
if (apdef.value.id || apdef.value.ref || apdef.value.array) {
|
|
513
|
+
v = `"${v}"`;
|
|
514
|
+
} else if (apdef.value.str) {
|
|
515
|
+
v = `"${escapeSpecialChars(v)}"`;
|
|
516
|
+
}
|
|
517
|
+
attrsStrs.push(`${apdef.name} ${v}`);
|
|
518
|
+
attrs.set(apdef.name, ov);
|
|
481
519
|
}
|
|
482
|
-
if (v == undefined) {
|
|
483
|
-
throw new Error(`Cannot initialize agent ${name}, only literals can be set for attributes`);
|
|
484
|
-
}
|
|
485
|
-
if (llmName == undefined && apdef.name == 'llm') {
|
|
486
|
-
llmName = v;
|
|
487
|
-
hasUserLlm = true;
|
|
488
|
-
}
|
|
489
|
-
const ov = v;
|
|
490
|
-
if (apdef.value.id || apdef.value.ref || apdef.value.array) {
|
|
491
|
-
v = `"${v}"`;
|
|
492
|
-
} else if (apdef.value.str) {
|
|
493
|
-
v = `"${escapeSpecialChars(v)}"`;
|
|
494
|
-
}
|
|
495
|
-
attrsStrs.push(`${apdef.name} ${v}`);
|
|
496
|
-
attrs.set(apdef.name, ov);
|
|
497
520
|
});
|
|
498
521
|
if (!attrs.has('llm')) {
|
|
499
522
|
llmName = `${name}_llm`;
|
|
@@ -505,14 +528,64 @@ async function addAgentDefinition(def: AgentDefinition, moduleName: string) {
|
|
|
505
528
|
}, @upsert}`;
|
|
506
529
|
let wf = createAgent;
|
|
507
530
|
if (llmName) {
|
|
508
|
-
|
|
531
|
+
const service = process.env.ANTHROPIC_API_KEY ? 'anthropic' : 'openai';
|
|
532
|
+
wf = `{${CoreAIModuleName}/${LlmEntityName} {name "${llmName}", service "${service}"}, @upsert}; ${wf}`;
|
|
509
533
|
}
|
|
510
534
|
(await parseWorkflow(`workflow A {${wf}}`)).statements.forEach((stmt: Statement) => {
|
|
511
|
-
addStandaloneStatement(stmt, moduleName);
|
|
535
|
+
addStandaloneStatement(stmt, moduleName, false);
|
|
512
536
|
});
|
|
513
537
|
addAgent(def.name, attrs, moduleName);
|
|
514
538
|
}
|
|
515
539
|
|
|
540
|
+
function processAgentArray(array: ArrayLiteral, attrName: string): string {
|
|
541
|
+
return array.vals
|
|
542
|
+
.map((stmt: Statement) => {
|
|
543
|
+
const expr = stmt.pattern.expr;
|
|
544
|
+
return processAgentArrayValue(expr, attrName);
|
|
545
|
+
})
|
|
546
|
+
.join(',');
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
function processAgentArrayValue(expr: Expr | undefined, attrName: string): string {
|
|
550
|
+
if (expr && isLiteral(expr)) {
|
|
551
|
+
const s = expr.str || expr.id || expr.ref || expr.bool;
|
|
552
|
+
if (s != undefined) {
|
|
553
|
+
return s;
|
|
554
|
+
}
|
|
555
|
+
if (expr.array) {
|
|
556
|
+
return processAgentArray(expr.array, attrName);
|
|
557
|
+
} else if (expr.map) {
|
|
558
|
+
const m = new Array<string>();
|
|
559
|
+
expr.map.entries.forEach((me: MapEntry) => {
|
|
560
|
+
m.push(
|
|
561
|
+
`${me.key.str || me.key.num || me.key.bool || ''}: ${processAgentArrayValue(me.value, attrName)}`
|
|
562
|
+
);
|
|
563
|
+
});
|
|
564
|
+
return `{${m.join(',')}}`;
|
|
565
|
+
} else {
|
|
566
|
+
throw new Error(`Type not supprted in agent-arrays - ${attrName}`);
|
|
567
|
+
}
|
|
568
|
+
} else {
|
|
569
|
+
throw new Error(`Invalid value in array passed to agent ${attrName}`);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
function addFlowDefinition(def: FlowDefinition, moduleName: string) {
|
|
574
|
+
if (def.body && def.$cstNode) {
|
|
575
|
+
const m = fetchModule(moduleName);
|
|
576
|
+
const sdef = def.$cstNode.text;
|
|
577
|
+
const idx = sdef.indexOf('{');
|
|
578
|
+
let f = '';
|
|
579
|
+
if (idx > 0) {
|
|
580
|
+
f = sdef.substring(idx + 1, sdef.lastIndexOf('}')).trim();
|
|
581
|
+
} else {
|
|
582
|
+
f = sdef;
|
|
583
|
+
}
|
|
584
|
+
m.addFlow(def.name, f);
|
|
585
|
+
registerFlow(`${moduleName}/${def.name}`, f);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
516
589
|
function addResolverDefinition(def: ResolverDefinition, moduleName: string) {
|
|
517
590
|
const resolverName = `${moduleName}/${def.name}`;
|
|
518
591
|
const paths = def.paths;
|
|
@@ -571,6 +644,7 @@ export async function addFromDef(def: Definition, moduleName: string) {
|
|
|
571
644
|
else if (isAgentDefinition(def)) await addAgentDefinition(def, moduleName);
|
|
572
645
|
else if (isStandaloneStatement(def)) addStandaloneStatement(def.stmt, moduleName);
|
|
573
646
|
else if (isResolverDefinition(def)) addResolverDefinition(def, moduleName);
|
|
647
|
+
else if (isFlowDefinition(def)) addFlowDefinition(def, moduleName);
|
|
574
648
|
}
|
|
575
649
|
|
|
576
650
|
export async function parseAndIntern(code: string, moduleName?: string) {
|