agentlang 0.0.37 → 0.0.50
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/api/http.d.ts +1 -1
- package/out/api/http.d.ts.map +1 -1
- package/out/api/http.js +9 -3
- package/out/api/http.js.map +1 -1
- package/out/cli/main.js +2 -2
- package/out/cli/main.js.map +1 -1
- 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 +398 -135
- package/out/language/main.cjs.map +2 -2
- package/out/runtime/agents/common.d.ts +2 -1
- package/out/runtime/agents/common.d.ts.map +1 -1
- package/out/runtime/agents/common.js +49 -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.d.ts.map +1 -1
- package/out/runtime/auth/cognito.js +28 -8
- package/out/runtime/auth/cognito.js.map +1 -1
- package/out/runtime/auth/interface.d.ts +2 -0
- package/out/runtime/auth/interface.d.ts.map +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 +77 -8
- package/out/runtime/interpreter.js.map +1 -1
- package/out/runtime/loader.d.ts.map +1 -1
- package/out/runtime/loader.js +89 -37
- package/out/runtime/loader.js.map +1 -1
- package/out/runtime/module.d.ts +1 -1
- package/out/runtime/module.d.ts.map +1 -1
- package/out/runtime/module.js +10 -3
- package/out/runtime/module.js.map +1 -1
- package/out/runtime/modules/ai.d.ts +13 -0
- package/out/runtime/modules/ai.d.ts.map +1 -1
- package/out/runtime/modules/ai.js +80 -9
- package/out/runtime/modules/ai.js.map +1 -1
- package/out/runtime/modules/auth.d.ts +1 -0
- package/out/runtime/modules/auth.d.ts.map +1 -1
- package/out/runtime/modules/auth.js +18 -0
- 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/state.d.ts +5 -0
- package/out/runtime/state.d.ts.map +1 -1
- package/out/runtime/state.js +2 -0
- package/out/runtime/state.js.map +1 -1
- package/out/syntaxes/agentlang.monarch.js +3 -3
- package/out/syntaxes/agentlang.monarch.js.map +1 -1
- package/package.json +2 -2
- package/src/api/http.ts +8 -3
- package/src/cli/main.ts +1 -1
- 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/runtime/agents/common.ts +50 -1
- package/src/runtime/agents/registry.ts +3 -3
- package/src/runtime/auth/cognito.ts +30 -8
- package/src/runtime/auth/interface.ts +2 -0
- package/src/runtime/defs.ts +1 -0
- package/src/runtime/interpreter.ts +122 -8
- package/src/runtime/loader.ts +98 -37
- package/src/runtime/module.ts +13 -3
- package/src/runtime/modules/ai.ts +102 -11
- package/src/runtime/modules/auth.ts +28 -0
- package/src/runtime/modules/core.ts +16 -4
- package/src/runtime/state.ts +2 -0
- package/src/syntaxes/agentlang.monarch.ts +3 -3
|
@@ -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,52 @@ 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
|
+
`;
|
|
@@ -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}`);
|
|
@@ -378,9 +378,11 @@ export class CognitoAuth implements AgentlangAuth {
|
|
|
378
378
|
|
|
379
379
|
if (response.$metadata.httpStatusCode == 200) {
|
|
380
380
|
logger.info(`Signup successful for user: ${username}`);
|
|
381
|
-
const user = await ensureUser(username,
|
|
381
|
+
const user = await ensureUser(username, firstName, lastName, env);
|
|
382
382
|
const userInfo: UserInfo = {
|
|
383
383
|
username: username,
|
|
384
|
+
firstName: firstName,
|
|
385
|
+
lastName: lastName,
|
|
384
386
|
id: user.id,
|
|
385
387
|
systemUserInfo: response.UserSub,
|
|
386
388
|
};
|
|
@@ -538,15 +540,19 @@ export class CognitoAuth implements AgentlangAuth {
|
|
|
538
540
|
}
|
|
539
541
|
if (result) {
|
|
540
542
|
// After successful Cognito authentication, create/update local records
|
|
541
|
-
let localUser = await findUserByEmail(username, env);
|
|
542
|
-
if (!localUser) {
|
|
543
|
-
localUser = await ensureUser(username, '', '', env);
|
|
544
|
-
}
|
|
545
|
-
const userid = localUser.lookup('id');
|
|
546
543
|
const idtok = result.getIdToken();
|
|
547
544
|
const idToken = idtok.getJwtToken();
|
|
548
545
|
const idTokenPayload = idtok.decodePayload();
|
|
546
|
+
|
|
547
|
+
const firstName = idTokenPayload['given_name'] || idTokenPayload['name'] || '';
|
|
548
|
+
const lastName = idTokenPayload['family_name'] || '';
|
|
549
549
|
const userGroups = idTokenPayload['cognito:groups'];
|
|
550
|
+
|
|
551
|
+
let localUser = await findUserByEmail(username, env);
|
|
552
|
+
if (!localUser) {
|
|
553
|
+
localUser = await ensureUser(username, firstName, lastName, env);
|
|
554
|
+
}
|
|
555
|
+
const userid = localUser.lookup('id');
|
|
550
556
|
if (userGroups) {
|
|
551
557
|
await ensureUserRoles(userid, userGroups, env);
|
|
552
558
|
}
|
|
@@ -802,6 +808,8 @@ export class CognitoAuth implements AgentlangAuth {
|
|
|
802
808
|
}
|
|
803
809
|
|
|
804
810
|
const userEmail = localUser.lookup('email');
|
|
811
|
+
const firstName = localUser.lookup('firstName');
|
|
812
|
+
const lastName = localUser.lookup('lastName');
|
|
805
813
|
|
|
806
814
|
// Check if Cognito is configured
|
|
807
815
|
const cognitoConfigured = process.env.COGNITO_USER_POOL_ID && process.env.COGNITO_CLIENT_ID;
|
|
@@ -825,6 +833,8 @@ export class CognitoAuth implements AgentlangAuth {
|
|
|
825
833
|
return {
|
|
826
834
|
id: userId,
|
|
827
835
|
username: userEmail,
|
|
836
|
+
firstName: firstName,
|
|
837
|
+
lastName: lastName,
|
|
828
838
|
systemUserInfo: {
|
|
829
839
|
localUser: localUser,
|
|
830
840
|
cognitoData: {
|
|
@@ -847,6 +857,8 @@ export class CognitoAuth implements AgentlangAuth {
|
|
|
847
857
|
return {
|
|
848
858
|
id: userId,
|
|
849
859
|
username: userEmail,
|
|
860
|
+
firstName: firstName,
|
|
861
|
+
lastName: lastName,
|
|
850
862
|
systemUserInfo: localUser,
|
|
851
863
|
};
|
|
852
864
|
}
|
|
@@ -855,6 +867,8 @@ export class CognitoAuth implements AgentlangAuth {
|
|
|
855
867
|
return {
|
|
856
868
|
id: userId,
|
|
857
869
|
username: userEmail || userId,
|
|
870
|
+
firstName: firstName,
|
|
871
|
+
lastName: lastName,
|
|
858
872
|
systemUserInfo: localUser,
|
|
859
873
|
};
|
|
860
874
|
}
|
|
@@ -867,6 +881,8 @@ export class CognitoAuth implements AgentlangAuth {
|
|
|
867
881
|
}
|
|
868
882
|
|
|
869
883
|
const userId = localUser.lookup('id');
|
|
884
|
+
const firstName = localUser.lookup('firstName');
|
|
885
|
+
const lastName = localUser.lookup('lastName');
|
|
870
886
|
|
|
871
887
|
// Check if Cognito is configured
|
|
872
888
|
const cognitoConfigured = process.env.COGNITO_USER_POOL_ID && process.env.COGNITO_CLIENT_ID;
|
|
@@ -876,11 +892,11 @@ export class CognitoAuth implements AgentlangAuth {
|
|
|
876
892
|
// Get additional user details from Cognito
|
|
877
893
|
const client = new CognitoIdentityProviderClient({
|
|
878
894
|
region: process.env.AWS_REGION || 'us-west-2',
|
|
879
|
-
credentials: fromEnv(),
|
|
880
895
|
});
|
|
881
896
|
|
|
882
897
|
const command = new AdminGetUserCommand({
|
|
883
898
|
UserPoolId: this.fetchUserPoolId(),
|
|
899
|
+
ClientId: this.fetchClientId(),
|
|
884
900
|
Username: email,
|
|
885
901
|
});
|
|
886
902
|
|
|
@@ -890,6 +906,8 @@ export class CognitoAuth implements AgentlangAuth {
|
|
|
890
906
|
return {
|
|
891
907
|
id: userId,
|
|
892
908
|
username: email,
|
|
909
|
+
firstName: firstName,
|
|
910
|
+
lastName: lastName,
|
|
893
911
|
systemUserInfo: {
|
|
894
912
|
localUser: localUser,
|
|
895
913
|
cognitoData: {
|
|
@@ -904,7 +922,7 @@ export class CognitoAuth implements AgentlangAuth {
|
|
|
904
922
|
},
|
|
905
923
|
};
|
|
906
924
|
} catch (err: any) {
|
|
907
|
-
|
|
925
|
+
console.log(`Failed to get Cognito user info for email ${email}, using local data only:`, {
|
|
908
926
|
errorName: err.name,
|
|
909
927
|
errorMessage: sanitizeErrorMessage(err.message),
|
|
910
928
|
});
|
|
@@ -912,6 +930,8 @@ export class CognitoAuth implements AgentlangAuth {
|
|
|
912
930
|
return {
|
|
913
931
|
id: userId,
|
|
914
932
|
username: email,
|
|
933
|
+
firstName: firstName,
|
|
934
|
+
lastName: lastName,
|
|
915
935
|
systemUserInfo: localUser,
|
|
916
936
|
};
|
|
917
937
|
}
|
|
@@ -920,6 +940,8 @@ export class CognitoAuth implements AgentlangAuth {
|
|
|
920
940
|
return {
|
|
921
941
|
id: userId,
|
|
922
942
|
username: email,
|
|
943
|
+
firstName: firstName,
|
|
944
|
+
lastName: lastName,
|
|
923
945
|
systemUserInfo: localUser,
|
|
924
946
|
};
|
|
925
947
|
}
|
package/src/runtime/defs.ts
CHANGED
|
@@ -70,9 +70,22 @@ import {
|
|
|
70
70
|
import { getResolver, getResolverNameForPath } from './resolvers/registry.js';
|
|
71
71
|
import { parseStatement, parseWorkflow } from '../language/parser.js';
|
|
72
72
|
import { ActiveSessionInfo, AdminSession, AdminUserId } from './auth/defs.js';
|
|
73
|
-
import {
|
|
73
|
+
import {
|
|
74
|
+
AgentInstance,
|
|
75
|
+
AgentEntityName,
|
|
76
|
+
AgentFqName,
|
|
77
|
+
findAgentByName,
|
|
78
|
+
FlowSpec,
|
|
79
|
+
getAgentFlow,
|
|
80
|
+
FlowStep,
|
|
81
|
+
} from './modules/ai.js';
|
|
74
82
|
import { logger } from './logger.js';
|
|
75
|
-
import {
|
|
83
|
+
import {
|
|
84
|
+
FlowSuspensionTag,
|
|
85
|
+
ParentAttributeName,
|
|
86
|
+
PathAttributeName,
|
|
87
|
+
PathAttributeNameQuery,
|
|
88
|
+
} from './defs.js';
|
|
76
89
|
import {
|
|
77
90
|
addCreateAudit,
|
|
78
91
|
addDeleteAudit,
|
|
@@ -238,6 +251,22 @@ export class Environment extends Instance {
|
|
|
238
251
|
return this;
|
|
239
252
|
}
|
|
240
253
|
|
|
254
|
+
private static FlowContextTag = 'flow-context';
|
|
255
|
+
|
|
256
|
+
setFlowContext(s: string): Environment {
|
|
257
|
+
this.attributes.set(Environment.FlowContextTag, s);
|
|
258
|
+
return this;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
resetFlowContext(): Environment {
|
|
262
|
+
this.attributes.set(Environment.FlowContextTag, undefined);
|
|
263
|
+
return this;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
getFlowContext(): string | undefined {
|
|
267
|
+
return this.attributes.get(Environment.FlowContextTag);
|
|
268
|
+
}
|
|
269
|
+
|
|
241
270
|
static SuspensionUserData = '^';
|
|
242
271
|
|
|
243
272
|
bindSuspensionUserData(userData: string): Environment {
|
|
@@ -1093,7 +1122,7 @@ async function evaluateCrudMap(crud: CrudMap, env: Environment): Promise<void> {
|
|
|
1093
1122
|
await runPostCreateEvents(inst, env);
|
|
1094
1123
|
}
|
|
1095
1124
|
if (r && entryName == AgentEntityName) {
|
|
1096
|
-
defineAgentEvent(env.getActiveModuleName(), r.lookup('name'));
|
|
1125
|
+
defineAgentEvent(env.getActiveModuleName(), r.lookup('name'), r.lookup('instruction'));
|
|
1097
1126
|
}
|
|
1098
1127
|
env.setLastResult(r);
|
|
1099
1128
|
const betRelInfo: BetweenRelInfo | undefined = env.getBetweenRelInfo();
|
|
@@ -1365,10 +1394,9 @@ async function walkJoinQueryPattern(
|
|
|
1365
1394
|
|
|
1366
1395
|
const MAX_PLANNER_RETRIES = 3;
|
|
1367
1396
|
|
|
1368
|
-
async function
|
|
1369
|
-
const
|
|
1370
|
-
|
|
1371
|
-
const msg: string = isString(origMsg) ? origMsg : agentInputAsString(origMsg);
|
|
1397
|
+
async function agentInvoke(agent: AgentInstance, msg: string, env: Environment): Promise<void> {
|
|
1398
|
+
const flowContext = env.getFlowContext();
|
|
1399
|
+
msg = flowContext ? `context: ${flowContext}\n${msg}` : msg;
|
|
1372
1400
|
await agent.invoke(msg, env);
|
|
1373
1401
|
const r: string | undefined = env.getLastResult();
|
|
1374
1402
|
const isPlanner = agent.isPlanner();
|
|
@@ -1420,7 +1448,93 @@ async function handleAgentInvocation(agentEventInst: Instance, env: Environment)
|
|
|
1420
1448
|
await pushToAgent(agent.output, env.getLastResult(), env);
|
|
1421
1449
|
}
|
|
1422
1450
|
} else {
|
|
1423
|
-
|
|
1451
|
+
throw new Error(`Agent ${agent.name} failed to generate a response`);
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
async function handleAgentInvocation(agentEventInst: Instance, env: Environment): Promise<void> {
|
|
1456
|
+
const agent: AgentInstance = await findAgentByName(agentEventInst.name, env);
|
|
1457
|
+
const origMsg: any = agentEventInst.lookup('message');
|
|
1458
|
+
const msg: string = isString(origMsg) ? origMsg : agentInputAsString(origMsg);
|
|
1459
|
+
const flow = getAgentFlow(agent.name);
|
|
1460
|
+
if (flow) {
|
|
1461
|
+
await handleAgentInvocationWithFlow(agent, flow, msg, env);
|
|
1462
|
+
} else {
|
|
1463
|
+
await agentInvoke(agent, msg, env).catch((reason: any) => {
|
|
1464
|
+
logger.warn(reason);
|
|
1465
|
+
});
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
async function handleAgentInvocationWithFlow(
|
|
1470
|
+
rootAgent: AgentInstance,
|
|
1471
|
+
flow: FlowSpec,
|
|
1472
|
+
msg: string,
|
|
1473
|
+
env: Environment
|
|
1474
|
+
): Promise<void> {
|
|
1475
|
+
await iterateOnFlow(flow, rootAgent, msg, env);
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
async function saveFlowSuspension(
|
|
1479
|
+
agent: AgentInstance,
|
|
1480
|
+
context: string,
|
|
1481
|
+
step: FlowStep,
|
|
1482
|
+
env: Environment
|
|
1483
|
+
): Promise<void> {
|
|
1484
|
+
const suspId = await createSuspension(
|
|
1485
|
+
env.getSuspensionId(),
|
|
1486
|
+
[FlowSuspensionTag, agent.name, step, context],
|
|
1487
|
+
env
|
|
1488
|
+
);
|
|
1489
|
+
env.setLastResult({ suspension: suspId || 'null' });
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
export async function restartFlow(
|
|
1493
|
+
flowContext: string[],
|
|
1494
|
+
userData: string,
|
|
1495
|
+
env: Environment
|
|
1496
|
+
): Promise<void> {
|
|
1497
|
+
const [_, agentName, step, ctx] = flowContext;
|
|
1498
|
+
const flow = getAgentFlow(agentName);
|
|
1499
|
+
if (flow) {
|
|
1500
|
+
const rootAgent = await findAgentByName(agentName, env);
|
|
1501
|
+
const newCtx = `${ctx}\n${step} --> ${userData}\n`;
|
|
1502
|
+
await iterateOnFlow(flow, rootAgent, newCtx, env);
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
const MaxFlowSteps = 25;
|
|
1507
|
+
|
|
1508
|
+
async function iterateOnFlow(
|
|
1509
|
+
flow: FlowSpec,
|
|
1510
|
+
rootAgent: AgentInstance,
|
|
1511
|
+
msg: string,
|
|
1512
|
+
env: Environment
|
|
1513
|
+
): Promise<void> {
|
|
1514
|
+
rootAgent.disableSession();
|
|
1515
|
+
const s = `Now consider the following flowchart and context:\n${flow}\n\n${msg}`;
|
|
1516
|
+
await agentInvoke(rootAgent, s, env);
|
|
1517
|
+
let step = env.getLastResult();
|
|
1518
|
+
let context = msg;
|
|
1519
|
+
let stepc = 0;
|
|
1520
|
+
while (step != 'DONE') {
|
|
1521
|
+
if (stepc > MaxFlowSteps) {
|
|
1522
|
+
throw new Error(`Flow execution exceeded maximum steps limit`);
|
|
1523
|
+
}
|
|
1524
|
+
++stepc;
|
|
1525
|
+
const agent = AgentInstance.FromFlowStep(step, rootAgent);
|
|
1526
|
+
agent.disableSession();
|
|
1527
|
+
env.setFlowContext(context);
|
|
1528
|
+
await agentInvoke(agent, '', env);
|
|
1529
|
+
env.resetFlowContext();
|
|
1530
|
+
if (env.isSuspended()) {
|
|
1531
|
+
await saveFlowSuspension(rootAgent, context, step, env);
|
|
1532
|
+
return;
|
|
1533
|
+
}
|
|
1534
|
+
const r = env.getLastResult();
|
|
1535
|
+
context = `${context}\n${step} --> ${agentInputAsString(r)}\n`;
|
|
1536
|
+
await agentInvoke(rootAgent, `${s}\n${context}`, env);
|
|
1537
|
+
step = env.getLastResult();
|
|
1424
1538
|
}
|
|
1425
1539
|
}
|
|
1426
1540
|
|
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,
|
|
@@ -47,6 +52,7 @@ import {
|
|
|
47
52
|
import {
|
|
48
53
|
escapeSpecialChars,
|
|
49
54
|
findRbacSchema,
|
|
55
|
+
isFqName,
|
|
50
56
|
isString,
|
|
51
57
|
makeFqName,
|
|
52
58
|
maybeExtends,
|
|
@@ -61,7 +67,13 @@ import { maybeGetValidationErrors, parse, parseModule, parseWorkflow } from '../
|
|
|
61
67
|
import { logger } from './logger.js';
|
|
62
68
|
import { Environment, evaluateStatements, GlobalEnvironment } from './interpreter.js';
|
|
63
69
|
import { createPermission, createRole } from './modules/auth.js';
|
|
64
|
-
import {
|
|
70
|
+
import {
|
|
71
|
+
AgentEntityName,
|
|
72
|
+
CoreAIModuleName,
|
|
73
|
+
LlmEntityName,
|
|
74
|
+
registerAgentFlow,
|
|
75
|
+
registerFlow,
|
|
76
|
+
} from './modules/ai.js';
|
|
65
77
|
import { GenericResolver, GenericResolverMethods } from './resolvers/interface.js';
|
|
66
78
|
import { registerResolver, setResolver } from './resolvers/registry.js';
|
|
67
79
|
import { Config, ConfigSchema, setAppConfig } from './state.js';
|
|
@@ -288,6 +300,7 @@ export async function loadCoreModules() {
|
|
|
288
300
|
|
|
289
301
|
async function loadModule(fileName: string, fsOptions?: any, callback?: Function): Promise<Module> {
|
|
290
302
|
// Initialize filesystem if not already done
|
|
303
|
+
console.log(`loading ${fileName}`);
|
|
291
304
|
const fs = await getFileSystem(fsOptions);
|
|
292
305
|
|
|
293
306
|
const fsAdapter = getFsAdapter(fs);
|
|
@@ -455,45 +468,53 @@ 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
|
+
} else {
|
|
490
|
+
throw new Error(`Invalid flows list in agent ${name}`);
|
|
491
|
+
}
|
|
476
492
|
} else {
|
|
477
|
-
v =
|
|
493
|
+
let v: any = undefined;
|
|
494
|
+
if (apdef.value.array) {
|
|
495
|
+
v = processAgentArray(apdef.value.array, name);
|
|
496
|
+
} else {
|
|
497
|
+
v = apdef.value.str || apdef.value.id || apdef.value.ref || apdef.value.num;
|
|
498
|
+
if (v == undefined) {
|
|
499
|
+
v = apdef.value.bool;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
478
502
|
if (v == undefined) {
|
|
479
|
-
|
|
503
|
+
throw new Error(`Cannot initialize agent ${name}, only literals can be set for attributes`);
|
|
480
504
|
}
|
|
505
|
+
if (llmName == undefined && apdef.name == 'llm') {
|
|
506
|
+
llmName = v;
|
|
507
|
+
hasUserLlm = true;
|
|
508
|
+
}
|
|
509
|
+
const ov = v;
|
|
510
|
+
if (apdef.value.id || apdef.value.ref || apdef.value.array) {
|
|
511
|
+
v = `"${v}"`;
|
|
512
|
+
} else if (apdef.value.str) {
|
|
513
|
+
v = `"${escapeSpecialChars(v)}"`;
|
|
514
|
+
}
|
|
515
|
+
attrsStrs.push(`${apdef.name} ${v}`);
|
|
516
|
+
attrs.set(apdef.name, ov);
|
|
481
517
|
}
|
|
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
518
|
});
|
|
498
519
|
if (!attrs.has('llm')) {
|
|
499
520
|
llmName = `${name}_llm`;
|
|
@@ -513,6 +534,45 @@ async function addAgentDefinition(def: AgentDefinition, moduleName: string) {
|
|
|
513
534
|
addAgent(def.name, attrs, moduleName);
|
|
514
535
|
}
|
|
515
536
|
|
|
537
|
+
function processAgentArray(array: ArrayLiteral, attrName: string): string {
|
|
538
|
+
return array.vals
|
|
539
|
+
.map((stmt: Statement) => {
|
|
540
|
+
const expr = stmt.pattern.expr;
|
|
541
|
+
return processAgentArrayValue(expr, attrName);
|
|
542
|
+
})
|
|
543
|
+
.join(',');
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
function processAgentArrayValue(expr: Expr | undefined, attrName: string): string {
|
|
547
|
+
if (expr && isLiteral(expr)) {
|
|
548
|
+
const s = expr.str || expr.id || expr.ref || expr.bool;
|
|
549
|
+
if (s != undefined) {
|
|
550
|
+
return s;
|
|
551
|
+
}
|
|
552
|
+
if (expr.array) {
|
|
553
|
+
return processAgentArray(expr.array, attrName);
|
|
554
|
+
} else if (expr.map) {
|
|
555
|
+
const m = new Array<string>();
|
|
556
|
+
expr.map.entries.forEach((me: MapEntry) => {
|
|
557
|
+
m.push(
|
|
558
|
+
`${me.key.str || me.key.num || me.key.bool || ''}: ${processAgentArrayValue(me.value, attrName)}`
|
|
559
|
+
);
|
|
560
|
+
});
|
|
561
|
+
return `{${m.join(',')}}`;
|
|
562
|
+
} else {
|
|
563
|
+
throw new Error(`Type not supprted in agent-arrays - ${attrName}`);
|
|
564
|
+
}
|
|
565
|
+
} else {
|
|
566
|
+
throw new Error(`Invalid value in array passed to agent ${attrName}`);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
function addFlowDefinition(def: FlowDefinition, moduleName: string) {
|
|
571
|
+
if (def.body && def.$cstNode) {
|
|
572
|
+
registerFlow(`${moduleName}/${def.name}`, def.$cstNode.text);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
516
576
|
function addResolverDefinition(def: ResolverDefinition, moduleName: string) {
|
|
517
577
|
const resolverName = `${moduleName}/${def.name}`;
|
|
518
578
|
const paths = def.paths;
|
|
@@ -571,6 +631,7 @@ export async function addFromDef(def: Definition, moduleName: string) {
|
|
|
571
631
|
else if (isAgentDefinition(def)) await addAgentDefinition(def, moduleName);
|
|
572
632
|
else if (isStandaloneStatement(def)) addStandaloneStatement(def.stmt, moduleName);
|
|
573
633
|
else if (isResolverDefinition(def)) addResolverDefinition(def, moduleName);
|
|
634
|
+
else if (isFlowDefinition(def)) addFlowDefinition(def, moduleName);
|
|
574
635
|
}
|
|
575
636
|
|
|
576
637
|
export async function parseAndIntern(code: string, moduleName?: string) {
|
package/src/runtime/module.ts
CHANGED
|
@@ -850,8 +850,10 @@ export class Agent extends Record {
|
|
|
850
850
|
override toString(): string {
|
|
851
851
|
const attrs = new Array<string>();
|
|
852
852
|
this.attributes.forEach((value: any, key: string) => {
|
|
853
|
-
|
|
854
|
-
|
|
853
|
+
if (key != 'moduleName') {
|
|
854
|
+
const v = isString(value) ? `"${value}"` : value;
|
|
855
|
+
attrs.push(` ${key} ${v}`);
|
|
856
|
+
}
|
|
855
857
|
});
|
|
856
858
|
return `agent ${Agent.NormalizeName(this.name)}
|
|
857
859
|
{
|
|
@@ -2848,14 +2850,22 @@ export function assertInstance(obj: any) {
|
|
|
2848
2850
|
|
|
2849
2851
|
const IsAgentEventMeta = 'is-agent-event';
|
|
2850
2852
|
const EventAgentName = 'event-agent-name';
|
|
2853
|
+
const DocumentationMetaTag = 'documentation';
|
|
2851
2854
|
|
|
2852
|
-
export function defineAgentEvent(moduleName: string, agentName: string) {
|
|
2855
|
+
export function defineAgentEvent(moduleName: string, agentName: string, instruction?: string) {
|
|
2853
2856
|
const module = fetchModule(moduleName);
|
|
2854
2857
|
const event: Record = new Event(agentName, moduleName);
|
|
2855
2858
|
event.addAttribute('message', { type: 'Any' });
|
|
2856
2859
|
event.addAttribute('chatId', { type: 'String' });
|
|
2857
2860
|
event.addMeta(IsAgentEventMeta, 'y');
|
|
2858
2861
|
event.addMeta(EventAgentName, agentName);
|
|
2862
|
+
if (instruction) {
|
|
2863
|
+
event.addMeta(
|
|
2864
|
+
DocumentationMetaTag,
|
|
2865
|
+
`This event will trigger an agent which has the instruction - "${instruction}".
|
|
2866
|
+
So make sure to pass all relevant information in the 'message' attribute of this event.`
|
|
2867
|
+
);
|
|
2868
|
+
}
|
|
2859
2869
|
module.addEntry(event);
|
|
2860
2870
|
}
|
|
2861
2871
|
|