agentlang 0.0.4 → 0.0.6
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.js +27 -19
- package/out/api/http.js.map +1 -1
- package/out/language/generated/ast.d.ts +27 -10
- package/out/language/generated/ast.d.ts.map +1 -1
- package/out/language/generated/ast.js +27 -2
- 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 +213 -111
- package/out/language/generated/grammar.js.map +1 -1
- package/out/language/main.cjs +234 -113
- package/out/language/main.cjs.map +2 -2
- package/out/language/parser.d.ts.map +1 -1
- package/out/language/parser.js +21 -5
- package/out/language/parser.js.map +1 -1
- package/out/language/syntax.d.ts +8 -2
- package/out/language/syntax.d.ts.map +1 -1
- package/out/language/syntax.js +42 -2
- package/out/language/syntax.js.map +1 -1
- package/out/runtime/agents/common.d.ts +1 -1
- package/out/runtime/agents/common.d.ts.map +1 -1
- package/out/runtime/agents/common.js +48 -0
- package/out/runtime/agents/common.js.map +1 -1
- package/out/runtime/agents/impl/openai.js +1 -1
- package/out/runtime/agents/impl/openai.js.map +1 -1
- package/out/runtime/auth/cognito.d.ts +2 -0
- package/out/runtime/auth/cognito.d.ts.map +1 -1
- package/out/runtime/auth/cognito.js +115 -15
- 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/interpreter.d.ts.map +1 -1
- package/out/runtime/interpreter.js +64 -16
- package/out/runtime/interpreter.js.map +1 -1
- package/out/runtime/jsmodules.d.ts +6 -0
- package/out/runtime/jsmodules.d.ts.map +1 -0
- package/out/runtime/jsmodules.js +138 -0
- package/out/runtime/jsmodules.js.map +1 -0
- package/out/runtime/loader.d.ts.map +1 -1
- package/out/runtime/loader.js +32 -16
- package/out/runtime/loader.js.map +1 -1
- package/out/runtime/module.d.ts +15 -1
- package/out/runtime/module.d.ts.map +1 -1
- package/out/runtime/module.js +110 -17
- package/out/runtime/module.js.map +1 -1
- package/out/runtime/modules/ai.d.ts +1 -0
- package/out/runtime/modules/ai.d.ts.map +1 -1
- package/out/runtime/modules/ai.js +20 -11
- package/out/runtime/modules/ai.js.map +1 -1
- package/out/runtime/modules/auth.d.ts +7 -3
- package/out/runtime/modules/auth.d.ts.map +1 -1
- package/out/runtime/modules/auth.js +142 -10
- package/out/runtime/modules/auth.js.map +1 -1
- package/out/runtime/resolvers/interface.d.ts +0 -1
- package/out/runtime/resolvers/interface.d.ts.map +1 -1
- package/out/runtime/resolvers/interface.js.map +1 -1
- package/out/runtime/resolvers/sqldb/database.d.ts +4 -2
- package/out/runtime/resolvers/sqldb/database.d.ts.map +1 -1
- package/out/runtime/resolvers/sqldb/database.js +43 -4
- package/out/runtime/resolvers/sqldb/database.js.map +1 -1
- package/out/runtime/resolvers/sqldb/impl.d.ts.map +1 -1
- package/out/runtime/resolvers/sqldb/impl.js +16 -6
- package/out/runtime/resolvers/sqldb/impl.js.map +1 -1
- package/out/runtime/util.d.ts +1 -4
- package/out/runtime/util.d.ts.map +1 -1
- package/out/runtime/util.js +11 -78
- package/out/runtime/util.js.map +1 -1
- package/package.json +1 -1
- package/src/api/http.ts +26 -17
- package/src/language/agentlang.langium +8 -5
- package/src/language/generated/ast.ts +56 -12
- package/src/language/generated/grammar.ts +213 -111
- package/src/language/parser.ts +24 -5
- package/src/language/syntax.ts +50 -5
- package/src/runtime/agents/common.ts +48 -0
- package/src/runtime/agents/impl/openai.ts +1 -1
- package/src/runtime/auth/cognito.ts +152 -22
- package/src/runtime/auth/interface.ts +7 -0
- package/src/runtime/interpreter.ts +63 -18
- package/src/runtime/jsmodules.ts +123 -0
- package/src/runtime/loader.ts +31 -17
- package/src/runtime/module.ts +127 -18
- package/src/runtime/modules/ai.ts +22 -14
- package/src/runtime/modules/auth.ts +169 -10
- package/src/runtime/resolvers/interface.ts +0 -1
- package/src/runtime/resolvers/sqldb/database.ts +55 -4
- package/src/runtime/resolvers/sqldb/impl.ts +16 -10
- package/src/runtime/util.ts +12 -70
package/src/language/parser.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
Group,
|
|
9
9
|
Handler,
|
|
10
10
|
If,
|
|
11
|
+
isExpr,
|
|
11
12
|
isGroup,
|
|
12
13
|
isLiteral,
|
|
13
14
|
isNegExpr,
|
|
@@ -21,6 +22,8 @@ import {
|
|
|
21
22
|
Pattern,
|
|
22
23
|
PrimExpr,
|
|
23
24
|
RelationshipPattern,
|
|
25
|
+
SelectIntoEntry,
|
|
26
|
+
SelectIntoSpec,
|
|
24
27
|
SetAttribute,
|
|
25
28
|
Statement,
|
|
26
29
|
WorkflowDefinition,
|
|
@@ -91,7 +94,7 @@ export async function parseWorkflow(workflowDef: string): Promise<WorkflowDefini
|
|
|
91
94
|
if (isWorkflowDefinition(mod.defs[0])) {
|
|
92
95
|
return mod.defs[0] as WorkflowDefinition;
|
|
93
96
|
} else {
|
|
94
|
-
throw new Error(`Failed to
|
|
97
|
+
throw new Error(`Failed to generate workflow from ${workflowDef}`);
|
|
95
98
|
}
|
|
96
99
|
}
|
|
97
100
|
|
|
@@ -172,8 +175,11 @@ function introspectPattern(pat: Pattern): BasePattern {
|
|
|
172
175
|
} else {
|
|
173
176
|
r = introspectCreatePattern(pat.crudMap);
|
|
174
177
|
}
|
|
175
|
-
|
|
176
|
-
|
|
178
|
+
if (pat.crudMap.into) {
|
|
179
|
+
r = introspectInto(pat.crudMap.into, r as CrudPattern);
|
|
180
|
+
}
|
|
181
|
+
} else if (pat.expr) {
|
|
182
|
+
r = introspectExpression(pat.expr);
|
|
177
183
|
} else if (pat.forEach) {
|
|
178
184
|
r = introspectForEach(pat.forEach);
|
|
179
185
|
} else if (pat.if) {
|
|
@@ -187,6 +193,13 @@ function introspectPattern(pat: Pattern): BasePattern {
|
|
|
187
193
|
}
|
|
188
194
|
}
|
|
189
195
|
|
|
196
|
+
function introspectInto(intoSpec: SelectIntoSpec, p: CrudPattern): CrudPattern {
|
|
197
|
+
intoSpec.entries.forEach((se: SelectIntoEntry) => {
|
|
198
|
+
p.addInto(se.alias, se.attribute);
|
|
199
|
+
});
|
|
200
|
+
return p;
|
|
201
|
+
}
|
|
202
|
+
|
|
190
203
|
function isQueryPattern(pat: Pattern): boolean {
|
|
191
204
|
if (pat.crudMap) {
|
|
192
205
|
const crudMap: CrudMap = pat.crudMap;
|
|
@@ -250,6 +263,7 @@ function introspectQueryPattern(crudMap: CrudMap): CrudPattern {
|
|
|
250
263
|
crudMap.relationships.forEach((rp: RelationshipPattern) => {
|
|
251
264
|
cp.addRelationship(rp.name, introspectPattern(rp.pattern) as CrudPattern | CrudPattern[]);
|
|
252
265
|
});
|
|
266
|
+
cp.isCreate = false;
|
|
253
267
|
cp.isQuery = true;
|
|
254
268
|
return cp;
|
|
255
269
|
}
|
|
@@ -259,6 +273,7 @@ function introspectQueryPattern(crudMap: CrudMap): CrudPattern {
|
|
|
259
273
|
function introspectCreatePattern(crudMap: CrudMap): CrudPattern {
|
|
260
274
|
if (crudMap) {
|
|
261
275
|
const cp: CrudPattern = new CrudPattern(crudMap.name);
|
|
276
|
+
cp.isCreate = false;
|
|
262
277
|
crudMap.body?.attributes.forEach((sa: SetAttribute) => {
|
|
263
278
|
if (!cp.isQueryUpdate && sa.name.endsWith(QuerySuffix)) {
|
|
264
279
|
cp.isQueryUpdate = true;
|
|
@@ -290,8 +305,12 @@ function introspectLiteral(lit: Literal): BasePattern {
|
|
|
290
305
|
} else if (lit.fnCall) {
|
|
291
306
|
return new FunctionCallPattern(
|
|
292
307
|
lit.fnCall.name,
|
|
293
|
-
lit.fnCall.args.map((v: Literal) => {
|
|
294
|
-
|
|
308
|
+
lit.fnCall.args.map((v: Literal | Expr) => {
|
|
309
|
+
if (isExpr(v)) {
|
|
310
|
+
return introspectExpression(v);
|
|
311
|
+
} else {
|
|
312
|
+
return introspectLiteral(v);
|
|
313
|
+
}
|
|
295
314
|
})
|
|
296
315
|
);
|
|
297
316
|
} else if (lit.array) {
|
package/src/language/syntax.ts
CHANGED
|
@@ -344,6 +344,7 @@ export class CrudPattern extends BasePattern {
|
|
|
344
344
|
recordName: string;
|
|
345
345
|
attributes: Array<AttributePattern>;
|
|
346
346
|
relationships: Map<string, CrudPattern[] | CrudPattern> | undefined;
|
|
347
|
+
into: Map<string, string> | undefined;
|
|
347
348
|
isQuery: boolean = false;
|
|
348
349
|
isQueryUpdate: boolean = false;
|
|
349
350
|
isCreate: boolean = false;
|
|
@@ -359,7 +360,7 @@ export class CrudPattern extends BasePattern {
|
|
|
359
360
|
}
|
|
360
361
|
}
|
|
361
362
|
|
|
362
|
-
addAttribute(n: string, p: BasePattern, op?: string) {
|
|
363
|
+
addAttribute(n: string, p: BasePattern, op?: string): CrudPattern {
|
|
363
364
|
this.attributes.push({ name: n, op: op, value: p });
|
|
364
365
|
if (this.recordName.endsWith('?')) {
|
|
365
366
|
this.recordName = this.recordName.substring(0, this.recordName.length - 1);
|
|
@@ -368,7 +369,7 @@ export class CrudPattern extends BasePattern {
|
|
|
368
369
|
return this;
|
|
369
370
|
}
|
|
370
371
|
|
|
371
|
-
removeAttribute(n: string) {
|
|
372
|
+
removeAttribute(n: string): CrudPattern {
|
|
372
373
|
const idx: number = this.attributes.findIndex((ap: AttributePattern) => {
|
|
373
374
|
return n == ap.name;
|
|
374
375
|
});
|
|
@@ -379,6 +380,34 @@ export class CrudPattern extends BasePattern {
|
|
|
379
380
|
return this;
|
|
380
381
|
}
|
|
381
382
|
|
|
383
|
+
addInto(alias: string, attr: string): CrudPattern {
|
|
384
|
+
if (this.into == undefined) {
|
|
385
|
+
this.into = new Map();
|
|
386
|
+
}
|
|
387
|
+
this.into.set(alias, attr);
|
|
388
|
+
return this;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
removeInto(alias: string): CrudPattern {
|
|
392
|
+
if (this.into) {
|
|
393
|
+
this.into.delete(alias);
|
|
394
|
+
}
|
|
395
|
+
return this;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
resetInto(into?: Map<string, string>): CrudPattern {
|
|
399
|
+
this.into = into;
|
|
400
|
+
return this;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
hasInto(): boolean {
|
|
404
|
+
if (this.into && this.into.size > 0) {
|
|
405
|
+
return true;
|
|
406
|
+
} else {
|
|
407
|
+
return false;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
382
411
|
private flagType() {
|
|
383
412
|
let hasq = false;
|
|
384
413
|
let hasc = false;
|
|
@@ -421,7 +450,7 @@ export class CrudPattern extends BasePattern {
|
|
|
421
450
|
return `{${s}}`;
|
|
422
451
|
}
|
|
423
452
|
|
|
424
|
-
private relationshipsAsString(): string {
|
|
453
|
+
private relationshipsAsString(): string | undefined {
|
|
425
454
|
if (this.relationships != undefined) {
|
|
426
455
|
const result: Array<string> = [];
|
|
427
456
|
this.relationships.forEach((p: CrudPattern | CrudPattern[], n: string) => {
|
|
@@ -430,7 +459,7 @@ export class CrudPattern extends BasePattern {
|
|
|
430
459
|
});
|
|
431
460
|
return result.join(',');
|
|
432
461
|
} else {
|
|
433
|
-
return
|
|
462
|
+
return undefined;
|
|
434
463
|
}
|
|
435
464
|
}
|
|
436
465
|
|
|
@@ -438,12 +467,27 @@ export class CrudPattern extends BasePattern {
|
|
|
438
467
|
return escapeQueryName(this.recordName);
|
|
439
468
|
}
|
|
440
469
|
|
|
470
|
+
private intoAsString(): string | undefined {
|
|
471
|
+
if (this.into) {
|
|
472
|
+
const ss = new Array<string>();
|
|
473
|
+
this.into.forEach((attr: string, alias: string) => {
|
|
474
|
+
ss.push(`${alias} ${attr}`);
|
|
475
|
+
});
|
|
476
|
+
return `into { ${ss.join(',\n')} }`;
|
|
477
|
+
}
|
|
478
|
+
return undefined;
|
|
479
|
+
}
|
|
480
|
+
|
|
441
481
|
override toString(): string {
|
|
442
482
|
let s = `{${this.recordName} ${this.attributesAsString()}`;
|
|
443
483
|
const rs = this.relationshipsAsString();
|
|
444
|
-
if (rs
|
|
484
|
+
if (rs) {
|
|
445
485
|
s = s.concat(`,${rs}`);
|
|
446
486
|
}
|
|
487
|
+
const ins = this.intoAsString();
|
|
488
|
+
if (ins) {
|
|
489
|
+
s = s.concat(`,${ins}`);
|
|
490
|
+
}
|
|
447
491
|
return s.concat('}', this.hintsAsString());
|
|
448
492
|
}
|
|
449
493
|
}
|
|
@@ -603,6 +647,7 @@ export function newCreatePattern(recName: string): CrudPattern {
|
|
|
603
647
|
export function newQueryPattern(recName: string, forQueryUpdate: boolean = false): CrudPattern {
|
|
604
648
|
recName = recName.charAt(recName.length - 1) == '?' ? recName : recName + '?';
|
|
605
649
|
const cp: CrudPattern = new CrudPattern(recName);
|
|
650
|
+
cp.isCreate = false;
|
|
606
651
|
if (forQueryUpdate) {
|
|
607
652
|
cp.isQueryUpdate = true;
|
|
608
653
|
} else {
|
|
@@ -15,6 +15,16 @@ entity Employee {
|
|
|
15
15
|
The Empoyee entity is part of the "Erp" module and it has four attributes: employeeId, firstName, lastName, salary and email. The employeeId uniquely identifies an
|
|
16
16
|
Employee and it's automatically filled-in by the system by calling the "uuid()" function. (In the place of the keyword 'entity', the keyword 'record' may also be used.
|
|
17
17
|
The difference between an entity and a record is that, instances of an entity is persisted to the database, instances of records are not).
|
|
18
|
+
|
|
19
|
+
This is an example of a record:
|
|
20
|
+
|
|
21
|
+
record EmailMessage {
|
|
22
|
+
to Email,
|
|
23
|
+
from Email,
|
|
24
|
+
subject String,
|
|
25
|
+
body String
|
|
26
|
+
}
|
|
27
|
+
|
|
18
28
|
Workflows contains JSON "patterns" that perform CRUD operations on entities. For example, here's is a workflow that creates a new instance of the Employee entity:
|
|
19
29
|
|
|
20
30
|
workflow CreateEmployee {
|
|
@@ -113,6 +123,17 @@ for emp in employees {
|
|
|
113
123
|
{Erp/SendMail {email emp.email, body "You are selected for an increment!"}}
|
|
114
124
|
} as emails
|
|
115
125
|
|
|
126
|
+
Make sure all references based on a preceding pattern is based either on an actual alias or the name of the workflow. For example, the following sequence of patterns
|
|
127
|
+
are invalid, because the alias 'employee' is not defined:
|
|
128
|
+
|
|
129
|
+
{Employee {id? 101}};
|
|
130
|
+
{SendEmail {to employee.email, body "hello"}}
|
|
131
|
+
|
|
132
|
+
A fix for the reference-error is shown below:
|
|
133
|
+
|
|
134
|
+
{Employee {id? 101}} as employee;
|
|
135
|
+
{SendEmail {to employee.email, body "hello"}}
|
|
136
|
+
|
|
116
137
|
Entities in a module can be connected together in relationships. There are two types of relationships - 'contains' and 'between'.
|
|
117
138
|
'Contains' relationship is for hierarchical data, as in a Library entity containing Books. 'Between' relationship is for graph-like data,
|
|
118
139
|
like two Profiles in a social media app is connected as friends. A 'between' relationship can be one of the following three types - 'one_one' (one-to-one),
|
|
@@ -172,6 +193,33 @@ workflow GetEmployeeTaskAssignments {
|
|
|
172
193
|
Erp/EmployeeTaskAssignment {Erp/TaskAssignment? {}}}
|
|
173
194
|
}
|
|
174
195
|
|
|
196
|
+
A general rule regarding generating workflows - as much as possible, do not include references to the workflow event in the patterns. Try to
|
|
197
|
+
fill-in values from the available context. For example, if your instruction is "create a workflow to send an email to employee 101 with this message -
|
|
198
|
+
'please call me as soon as possible'", the best workflow to return is:
|
|
199
|
+
|
|
200
|
+
workflow sendEmail {
|
|
201
|
+
{employee {id? 101}} as emp;
|
|
202
|
+
{email {to emp.email body "please call me as soon as possible"}}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
because all the information needed is available in the context. If the instruction is "create a workflow to send an email by employee-id with this message -
|
|
206
|
+
'please call me as soon as possible'", then you can return:
|
|
207
|
+
|
|
208
|
+
workflow sendEmail {
|
|
209
|
+
{employee {id? sendEmail.employeeId}} as emp;
|
|
210
|
+
{email {to emp.email body "please call me as soon as possible"}}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
The point is use the immediate context to fill-in values in generated patterns, as much as possible.
|
|
214
|
+
|
|
215
|
+
Also generate a workflow only if required explicitly by the user or the contextual information is incomplete. Otherwise, just return an array of patterns.
|
|
216
|
+
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:
|
|
217
|
+
|
|
218
|
+
[{employee {id? 101}} as emp;
|
|
219
|
+
{email {to emp.email, body "please call me as soon as possible"}}]
|
|
220
|
+
|
|
221
|
+
Note that each pattern in the array is separated by a ; and not a comma(,).
|
|
222
|
+
|
|
175
223
|
Now consider the following module definition and generate appropriate patterns in response to the user instructions. You must return only valid patterns or workflows,
|
|
176
224
|
no other descriptive text or comments are needed.
|
|
177
225
|
`;
|
|
@@ -6,7 +6,7 @@ export class OpenAIProvider implements AgentServiceProvider {
|
|
|
6
6
|
private model: ChatOpenAI;
|
|
7
7
|
|
|
8
8
|
constructor(config?: Map<string, any>) {
|
|
9
|
-
let modelName = 'gpt-4';
|
|
9
|
+
let modelName = 'gpt-4.1-2025-04-14';
|
|
10
10
|
if (config) {
|
|
11
11
|
modelName = config.get('model') || modelName;
|
|
12
12
|
}
|
|
@@ -6,14 +6,7 @@ import {
|
|
|
6
6
|
SignUpCallback,
|
|
7
7
|
UserInfo,
|
|
8
8
|
} from './interface.js';
|
|
9
|
-
import {
|
|
10
|
-
ensureUser,
|
|
11
|
-
ensureUserSession,
|
|
12
|
-
findUser,
|
|
13
|
-
findUserByEmail,
|
|
14
|
-
findUserSession,
|
|
15
|
-
removeSession,
|
|
16
|
-
} from '../modules/auth.js';
|
|
9
|
+
import { ensureUser, ensureUserSession, findUser, findUserByEmail } from '../modules/auth.js';
|
|
17
10
|
import { logger } from '../logger.js';
|
|
18
11
|
import { sleepMilliseconds } from '../util.js';
|
|
19
12
|
import { Instance } from '../module.js';
|
|
@@ -36,9 +29,14 @@ let fromEnv: any = undefined;
|
|
|
36
29
|
let CognitoIdentityProviderClient: any = undefined;
|
|
37
30
|
let SignUpCommand: any = undefined;
|
|
38
31
|
let AdminGetUserCommand: any = undefined;
|
|
32
|
+
let InitiateAuthCommand: any = undefined;
|
|
39
33
|
let AuthenticationDetails: any = undefined;
|
|
40
34
|
let CognitoUser: any = undefined;
|
|
41
35
|
let CognitoUserPool: any = undefined;
|
|
36
|
+
let CognitoUserSession: any = undefined;
|
|
37
|
+
let CognitoIdToken: any = undefined;
|
|
38
|
+
let CognitoAccessToken: any = undefined;
|
|
39
|
+
let CognitoRefreshToken: any = undefined;
|
|
42
40
|
|
|
43
41
|
if (isNodeEnv) {
|
|
44
42
|
const cp = await import('@aws-sdk/credential-providers');
|
|
@@ -48,11 +46,16 @@ if (isNodeEnv) {
|
|
|
48
46
|
CognitoIdentityProviderClient = cip.CognitoIdentityProviderClient;
|
|
49
47
|
SignUpCommand = cip.SignUpCommand;
|
|
50
48
|
AdminGetUserCommand = cip.AdminGetUserCommand;
|
|
49
|
+
InitiateAuthCommand = cip.InitiateAuthCommand;
|
|
51
50
|
|
|
52
51
|
const ci = await import('amazon-cognito-identity-js');
|
|
53
52
|
AuthenticationDetails = ci.AuthenticationDetails;
|
|
54
53
|
CognitoUser = ci.CognitoUser;
|
|
55
54
|
CognitoUserPool = ci.CognitoUserPool;
|
|
55
|
+
CognitoUserSession = ci.CognitoUserSession;
|
|
56
|
+
CognitoIdToken = ci.CognitoIdToken;
|
|
57
|
+
CognitoAccessToken = ci.CognitoAccessToken;
|
|
58
|
+
CognitoRefreshToken = ci.CognitoRefreshToken;
|
|
56
59
|
}
|
|
57
60
|
|
|
58
61
|
const defaultConfig = isNodeEnv
|
|
@@ -441,7 +444,13 @@ export class CognitoAuth implements AgentlangAuth {
|
|
|
441
444
|
const idToken = result.getIdToken().getJwtToken();
|
|
442
445
|
const accessToken = result.getAccessToken().getJwtToken();
|
|
443
446
|
const refreshToken = result.getRefreshToken().getToken();
|
|
444
|
-
const localSess: Instance = await ensureUserSession(
|
|
447
|
+
const localSess: Instance = await ensureUserSession(
|
|
448
|
+
userid,
|
|
449
|
+
idToken,
|
|
450
|
+
accessToken,
|
|
451
|
+
refreshToken,
|
|
452
|
+
env
|
|
453
|
+
);
|
|
445
454
|
const sessInfo: SessionInfo = {
|
|
446
455
|
sessionId: localSess.lookup('id'),
|
|
447
456
|
userId: userid,
|
|
@@ -513,7 +522,13 @@ export class CognitoAuth implements AgentlangAuth {
|
|
|
513
522
|
const idToken = result.getIdToken().getJwtToken();
|
|
514
523
|
const accessToken = result.getAccessToken().getJwtToken();
|
|
515
524
|
const refreshToken = result.getRefreshToken().getToken();
|
|
516
|
-
const localSess: Instance = await ensureUserSession(
|
|
525
|
+
const localSess: Instance = await ensureUserSession(
|
|
526
|
+
userid,
|
|
527
|
+
idToken,
|
|
528
|
+
accessToken,
|
|
529
|
+
refreshToken,
|
|
530
|
+
env
|
|
531
|
+
);
|
|
517
532
|
const sessInfo: SessionInfo = {
|
|
518
533
|
sessionId: localSess.lookup('id'),
|
|
519
534
|
userId: userid,
|
|
@@ -540,25 +555,33 @@ export class CognitoAuth implements AgentlangAuth {
|
|
|
540
555
|
return;
|
|
541
556
|
}
|
|
542
557
|
const user = new CognitoUser({
|
|
543
|
-
Username: localUser.email,
|
|
558
|
+
Username: localUser.lookup('email'),
|
|
544
559
|
Pool: this.fetchUserPool(),
|
|
545
560
|
});
|
|
561
|
+
|
|
546
562
|
let done = false;
|
|
547
563
|
let logoutError: any;
|
|
548
|
-
|
|
549
|
-
|
|
564
|
+
|
|
565
|
+
const session = new CognitoUserSession({
|
|
566
|
+
IdToken: new CognitoIdToken({ IdToken: sessionInfo.idToken }),
|
|
567
|
+
AccessToken: new CognitoAccessToken({ AccessToken: sessionInfo.accessToken }),
|
|
568
|
+
RefreshToken: new CognitoRefreshToken({ RefreshToken: sessionInfo.refreshToken }),
|
|
550
569
|
});
|
|
551
|
-
|
|
552
|
-
user.
|
|
553
|
-
|
|
570
|
+
user.setSignInUserSession(session);
|
|
571
|
+
user.globalSignOut({
|
|
572
|
+
onSuccess: function () {
|
|
573
|
+
done = true;
|
|
574
|
+
},
|
|
575
|
+
onFailure: function (err: any) {
|
|
576
|
+
done = true;
|
|
554
577
|
logger.error(`Cognito signOut error for user ${sessionInfo.userId}:`, {
|
|
555
578
|
errorName: err.name,
|
|
556
579
|
errorMessage: sanitizeErrorMessage(err.message),
|
|
557
580
|
});
|
|
558
581
|
logoutError = err;
|
|
559
|
-
}
|
|
560
|
-
done = true;
|
|
582
|
+
},
|
|
561
583
|
});
|
|
584
|
+
|
|
562
585
|
while (!done) {
|
|
563
586
|
await sleepMilliseconds(100);
|
|
564
587
|
}
|
|
@@ -568,10 +591,6 @@ export class CognitoAuth implements AgentlangAuth {
|
|
|
568
591
|
);
|
|
569
592
|
// Continue with local session cleanup even if Cognito logout fails
|
|
570
593
|
}
|
|
571
|
-
const sess = await findUserSession(localUser.id, env);
|
|
572
|
-
if (sess) {
|
|
573
|
-
await removeSession(sess.id, env);
|
|
574
|
-
}
|
|
575
594
|
logger.debug(`Successfully logged out user ${sessionInfo.userId}`);
|
|
576
595
|
if (cb) cb(true);
|
|
577
596
|
} catch (err: any) {
|
|
@@ -581,6 +600,50 @@ export class CognitoAuth implements AgentlangAuth {
|
|
|
581
600
|
}
|
|
582
601
|
}
|
|
583
602
|
|
|
603
|
+
async changePassword(
|
|
604
|
+
sessionInfo: SessionInfo,
|
|
605
|
+
newPassword: string,
|
|
606
|
+
oldPassword: string,
|
|
607
|
+
env: Environment
|
|
608
|
+
): Promise<boolean> {
|
|
609
|
+
const localUser = await findUser(sessionInfo.userId, env);
|
|
610
|
+
if (!localUser) {
|
|
611
|
+
logger.warn(`User ${sessionInfo.userId} not found for password-change`);
|
|
612
|
+
return false;
|
|
613
|
+
}
|
|
614
|
+
const email = localUser.lookup('email');
|
|
615
|
+
const user = new CognitoUser({
|
|
616
|
+
Username: email,
|
|
617
|
+
Pool: this.fetchUserPool(),
|
|
618
|
+
});
|
|
619
|
+
const session = new CognitoUserSession({
|
|
620
|
+
IdToken: new CognitoIdToken({ IdToken: sessionInfo.idToken }),
|
|
621
|
+
AccessToken: new CognitoAccessToken({ AccessToken: sessionInfo.accessToken }),
|
|
622
|
+
RefreshToken: new CognitoRefreshToken({ RefreshToken: sessionInfo.refreshToken }),
|
|
623
|
+
});
|
|
624
|
+
user.setSignInUserSession(session);
|
|
625
|
+
let done = false;
|
|
626
|
+
let cpErr: any = undefined;
|
|
627
|
+
user.changePassword(oldPassword, newPassword, (err: any, _: any) => {
|
|
628
|
+
if (err) {
|
|
629
|
+
done = true;
|
|
630
|
+
cpErr = err;
|
|
631
|
+
} else {
|
|
632
|
+
done = true;
|
|
633
|
+
}
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
while (!done) {
|
|
637
|
+
await sleepMilliseconds(100);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
if (cpErr) {
|
|
641
|
+
logger.warn(`Failed to change the password for ${email} - ${cpErr.message}`);
|
|
642
|
+
return false;
|
|
643
|
+
}
|
|
644
|
+
return true;
|
|
645
|
+
}
|
|
646
|
+
|
|
584
647
|
private fetchUserPool() {
|
|
585
648
|
if (this.userPool) {
|
|
586
649
|
return this.userPool;
|
|
@@ -753,4 +816,71 @@ export class CognitoAuth implements AgentlangAuth {
|
|
|
753
816
|
};
|
|
754
817
|
}
|
|
755
818
|
}
|
|
819
|
+
|
|
820
|
+
async refreshToken(refreshTokenString: string, env: Environment): Promise<SessionInfo> {
|
|
821
|
+
try {
|
|
822
|
+
// Use InitiateAuth with REFRESH_TOKEN_AUTH flow
|
|
823
|
+
const client = new CognitoIdentityProviderClient({
|
|
824
|
+
region: process.env.AWS_REGION || 'us-west-2',
|
|
825
|
+
credentials: fromEnv(),
|
|
826
|
+
});
|
|
827
|
+
|
|
828
|
+
const command = new InitiateAuthCommand({
|
|
829
|
+
AuthFlow: 'REFRESH_TOKEN_AUTH',
|
|
830
|
+
ClientId: this.fetchClientId(),
|
|
831
|
+
AuthParameters: {
|
|
832
|
+
REFRESH_TOKEN: refreshTokenString,
|
|
833
|
+
},
|
|
834
|
+
});
|
|
835
|
+
|
|
836
|
+
const response = await client.send(command);
|
|
837
|
+
|
|
838
|
+
if (!response.AuthenticationResult) {
|
|
839
|
+
throw new UnauthorisedError('Token refresh failed');
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
const newIdToken = response.AuthenticationResult.IdToken!;
|
|
843
|
+
const newAccessToken = response.AuthenticationResult.AccessToken!;
|
|
844
|
+
const newRefreshToken = response.AuthenticationResult.RefreshToken || refreshTokenString;
|
|
845
|
+
|
|
846
|
+
// Extract user info from the new ID token
|
|
847
|
+
const idTokenPayload = JSON.parse(atob(newIdToken.split('.')[1]));
|
|
848
|
+
const userEmail = idTokenPayload.email;
|
|
849
|
+
|
|
850
|
+
// Find or create local user
|
|
851
|
+
let localUser = await findUserByEmail(userEmail, env);
|
|
852
|
+
if (!localUser) {
|
|
853
|
+
localUser = await ensureUser(userEmail, '', '', env);
|
|
854
|
+
}
|
|
855
|
+
const userId = localUser.lookup('id');
|
|
856
|
+
|
|
857
|
+
// Update local session
|
|
858
|
+
const updatedSession = await ensureUserSession(
|
|
859
|
+
userId,
|
|
860
|
+
newIdToken,
|
|
861
|
+
newAccessToken,
|
|
862
|
+
newRefreshToken,
|
|
863
|
+
env
|
|
864
|
+
);
|
|
865
|
+
|
|
866
|
+
const sessInfo: SessionInfo = {
|
|
867
|
+
sessionId: updatedSession.lookup('id'),
|
|
868
|
+
userId: userId,
|
|
869
|
+
authToken: newIdToken,
|
|
870
|
+
idToken: newIdToken,
|
|
871
|
+
accessToken: newAccessToken,
|
|
872
|
+
refreshToken: newRefreshToken,
|
|
873
|
+
systemSesionInfo: response.AuthenticationResult,
|
|
874
|
+
};
|
|
875
|
+
|
|
876
|
+
return sessInfo;
|
|
877
|
+
} catch (err: any) {
|
|
878
|
+
logger.error(`Refresh token operation failed: ${err.message}`);
|
|
879
|
+
if (err.name === 'NotAuthorizedException') {
|
|
880
|
+
throw new UnauthorisedError('Invalid or expired refresh token');
|
|
881
|
+
}
|
|
882
|
+
handleCognitoError(err, 'refreshToken');
|
|
883
|
+
throw err; // This line won't be reached due to handleCognitoError throwing
|
|
884
|
+
}
|
|
885
|
+
}
|
|
756
886
|
}
|
|
@@ -33,4 +33,11 @@ export interface AgentlangAuth {
|
|
|
33
33
|
verifyToken(token: string, env?: Environment): any;
|
|
34
34
|
getUser(userId: string, env: Environment): Promise<UserInfo>;
|
|
35
35
|
getUserByEmail(email: string, env: Environment): Promise<UserInfo>;
|
|
36
|
+
changePassword(
|
|
37
|
+
sessionInfo: SessionInfo,
|
|
38
|
+
newPassword: string,
|
|
39
|
+
oldPassword: string,
|
|
40
|
+
env: Environment
|
|
41
|
+
): Promise<boolean>;
|
|
42
|
+
refreshToken(refreshToken: string, env: Environment): Promise<SessionInfo>;
|
|
36
43
|
}
|
|
@@ -54,7 +54,6 @@ import {
|
|
|
54
54
|
escapeFqName,
|
|
55
55
|
escapeQueryName,
|
|
56
56
|
fqNameFromPath,
|
|
57
|
-
invokeModuleFn,
|
|
58
57
|
isFqName,
|
|
59
58
|
isPath,
|
|
60
59
|
isString,
|
|
@@ -78,6 +77,7 @@ import {
|
|
|
78
77
|
maybeCancelTimer,
|
|
79
78
|
setTimerRunning,
|
|
80
79
|
} from './modules/core.js';
|
|
80
|
+
import { invokeModuleFn } from './jsmodules.js';
|
|
81
81
|
|
|
82
82
|
export type Result = any;
|
|
83
83
|
|
|
@@ -590,8 +590,8 @@ export async function parseAndEvaluateStatement(
|
|
|
590
590
|
}
|
|
591
591
|
|
|
592
592
|
async function evaluatePattern(pat: Pattern, env: Environment): Promise<void> {
|
|
593
|
-
if (pat.
|
|
594
|
-
await
|
|
593
|
+
if (pat.expr) {
|
|
594
|
+
await evaluateExpression(pat.expr, env);
|
|
595
595
|
} else if (pat.crudMap) {
|
|
596
596
|
await evaluateCrudMap(pat.crudMap, env);
|
|
597
597
|
} else if (pat.forEach) {
|
|
@@ -1047,21 +1047,61 @@ async function walkJoinQueryPattern(
|
|
|
1047
1047
|
async function handleAgentInvocation(agentEventInst: Instance, env: Environment): Promise<void> {
|
|
1048
1048
|
const agent: AgentInstance = await findAgentByName(agentEventInst.name, env);
|
|
1049
1049
|
await agent.invoke(agentEventInst.lookup('message'), env);
|
|
1050
|
-
const result: string = env.getLastResult();
|
|
1051
|
-
if (
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1050
|
+
const result: string | undefined = cleanupAgentResponse(env.getLastResult());
|
|
1051
|
+
if (result) {
|
|
1052
|
+
if (agent.isPlanner()) {
|
|
1053
|
+
logger.debug(`Agent ${agent.name} generated pattern: ${result}`);
|
|
1054
|
+
try {
|
|
1055
|
+
let rs = result.trim();
|
|
1056
|
+
if (rs.startsWith('[')) {
|
|
1057
|
+
const stmts = rs.substring(1, rs.length - 1);
|
|
1058
|
+
rs = `workflow T {${stmts}}`;
|
|
1059
|
+
}
|
|
1060
|
+
if (rs.startsWith('workflow')) {
|
|
1061
|
+
const wf = await parseWorkflow(rs);
|
|
1062
|
+
if (agent.runWorkflows) {
|
|
1063
|
+
await evaluateStatements(wf.statements, env);
|
|
1064
|
+
}
|
|
1065
|
+
} else {
|
|
1066
|
+
env.setLastResult(await parseAndEvaluateStatement(rs, undefined, env));
|
|
1067
|
+
}
|
|
1068
|
+
} catch (err: any) {
|
|
1069
|
+
logger.error(
|
|
1070
|
+
`Failed to evaluate pattern generated by agent ${agent.name} - ${result}, ${err}`
|
|
1071
|
+
);
|
|
1059
1072
|
}
|
|
1060
|
-
} catch (err: any) {
|
|
1061
|
-
logger.error(
|
|
1062
|
-
`Failed to evaluate pattern generated by agent ${agent.name} - ${result}, ${err}`
|
|
1063
|
-
);
|
|
1064
1073
|
}
|
|
1074
|
+
} else {
|
|
1075
|
+
logger.warn(`Agent ${agent.name} failed to generate a response`);
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
function cleanupAgentResponse(response: string | undefined): string | undefined {
|
|
1080
|
+
if (response) {
|
|
1081
|
+
const resp = response.trim();
|
|
1082
|
+
if (resp.startsWith('[') && resp.endsWith(']')) {
|
|
1083
|
+
return resp;
|
|
1084
|
+
}
|
|
1085
|
+
const parts = resp.split('\n');
|
|
1086
|
+
const validated = parts.filter((s: string) => {
|
|
1087
|
+
const stmt = s.trim();
|
|
1088
|
+
const r =
|
|
1089
|
+
stmt.startsWith('{') ||
|
|
1090
|
+
stmt.startsWith('}') ||
|
|
1091
|
+
stmt.startsWith('if') ||
|
|
1092
|
+
stmt.startsWith('for') ||
|
|
1093
|
+
stmt.startsWith('delete') ||
|
|
1094
|
+
stmt.startsWith('workflow');
|
|
1095
|
+
if (!r) {
|
|
1096
|
+
const i = stmt.indexOf('(');
|
|
1097
|
+
return i > 0 && stmt.indexOf(')') > i;
|
|
1098
|
+
} else {
|
|
1099
|
+
return r;
|
|
1100
|
+
}
|
|
1101
|
+
});
|
|
1102
|
+
return validated.join('\n');
|
|
1103
|
+
} else {
|
|
1104
|
+
return response;
|
|
1065
1105
|
}
|
|
1066
1106
|
}
|
|
1067
1107
|
|
|
@@ -1263,7 +1303,12 @@ async function applyFn(fnCall: FnCall, env: Environment, isAsync: boolean): Prom
|
|
|
1263
1303
|
if (fnCall.args != undefined) {
|
|
1264
1304
|
args = new Array<Result>();
|
|
1265
1305
|
for (let i = 0; i < fnCall.args.length; ++i) {
|
|
1266
|
-
|
|
1306
|
+
const arg = fnCall.args[i];
|
|
1307
|
+
if (isLiteral(arg)) {
|
|
1308
|
+
await evaluateLiteral(arg, env);
|
|
1309
|
+
} else {
|
|
1310
|
+
await evaluateExpression(arg, env);
|
|
1311
|
+
}
|
|
1267
1312
|
args.push(env.getLastResult());
|
|
1268
1313
|
}
|
|
1269
1314
|
args.push(env);
|
|
@@ -1287,7 +1332,7 @@ async function realizeMap(mapLiteral: MapLiteral, env: Environment): Promise<voi
|
|
|
1287
1332
|
for (let i = 0; i < mapLiteral.entries.length; ++i) {
|
|
1288
1333
|
const entry = mapLiteral.entries[i];
|
|
1289
1334
|
const k = getMapKey(entry.key);
|
|
1290
|
-
await
|
|
1335
|
+
await evaluateExpression(entry.value, env);
|
|
1291
1336
|
result.set(k, env.getLastResult());
|
|
1292
1337
|
}
|
|
1293
1338
|
env.setLastResult(Object.fromEntries(result.entries()));
|