agentlang 0.0.8 → 0.0.11
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 +1 -1
- package/out/api/http.js.map +1 -1
- package/out/language/generated/ast.d.ts +11 -2
- package/out/language/generated/ast.d.ts.map +1 -1
- package/out/language/generated/ast.js +15 -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 +162 -119
- package/out/language/generated/grammar.js.map +1 -1
- package/out/language/main.cjs +174 -121
- package/out/language/main.cjs.map +2 -2
- package/out/language/parser.d.ts +1 -0
- package/out/language/parser.d.ts.map +1 -1
- package/out/language/parser.js +4 -0
- package/out/language/parser.js.map +1 -1
- package/out/language/syntax.js +2 -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 +10 -10
- package/out/runtime/interpreter.d.ts +20 -1
- package/out/runtime/interpreter.d.ts.map +1 -1
- package/out/runtime/interpreter.js +160 -13
- package/out/runtime/interpreter.js.map +1 -1
- package/out/runtime/jsmodules.d.ts +2 -2
- package/out/runtime/jsmodules.d.ts.map +1 -1
- package/out/runtime/jsmodules.js +12 -4
- package/out/runtime/jsmodules.js.map +1 -1
- package/out/runtime/loader.d.ts +1 -1
- package/out/runtime/loader.d.ts.map +1 -1
- package/out/runtime/loader.js +10 -7
- package/out/runtime/loader.js.map +1 -1
- package/out/runtime/module.d.ts +4 -1
- package/out/runtime/module.d.ts.map +1 -1
- package/out/runtime/module.js +56 -11
- 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 +17 -5
- 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 +21 -16
- package/out/runtime/modules/auth.js.map +1 -1
- package/out/runtime/modules/core.d.ts +9 -0
- package/out/runtime/modules/core.d.ts.map +1 -1
- package/out/runtime/modules/core.js +107 -2
- package/out/runtime/modules/core.js.map +1 -1
- package/out/runtime/resolvers/interface.d.ts +4 -3
- package/out/runtime/resolvers/interface.d.ts.map +1 -1
- package/out/runtime/resolvers/interface.js +4 -4
- package/out/runtime/resolvers/interface.js.map +1 -1
- package/out/runtime/resolvers/sqldb/impl.js +2 -2
- package/out/runtime/resolvers/sqldb/impl.js.map +1 -1
- package/out/runtime/util.d.ts.map +1 -1
- package/out/runtime/util.js +3 -2
- package/out/runtime/util.js.map +1 -1
- package/out/syntaxes/agentlang.monarch.js +1 -1
- package/out/syntaxes/agentlang.monarch.js.map +1 -1
- package/package.json +1 -1
- package/src/api/http.ts +1 -1
- package/src/language/agentlang.langium +7 -5
- package/src/language/generated/ast.ts +29 -5
- package/src/language/generated/grammar.ts +162 -119
- package/src/language/parser.ts +5 -0
- package/src/language/syntax.ts +2 -2
- package/src/runtime/agents/common.ts +10 -10
- package/src/runtime/interpreter.ts +177 -13
- package/src/runtime/jsmodules.ts +12 -4
- package/src/runtime/loader.ts +12 -6
- package/src/runtime/module.ts +61 -11
- package/src/runtime/modules/ai.ts +16 -5
- package/src/runtime/modules/auth.ts +21 -17
- package/src/runtime/modules/core.ts +144 -2
- package/src/runtime/resolvers/interface.ts +6 -6
- package/src/runtime/resolvers/sqldb/impl.ts +2 -2
- package/src/runtime/util.ts +4 -2
- package/src/syntaxes/agentlang.monarch.ts +1 -1
package/src/language/parser.ts
CHANGED
|
@@ -89,6 +89,11 @@ export async function parseStatement(stmt: string): Promise<Statement> {
|
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
export async function parseStatements(stmts: string[]): Promise<Statement[]> {
|
|
93
|
+
const wf = await parseWorkflow(`workflow W {${stmts.join(';\n')}}`);
|
|
94
|
+
return wf.statements;
|
|
95
|
+
}
|
|
96
|
+
|
|
92
97
|
export async function parseWorkflow(workflowDef: string): Promise<WorkflowDefinition> {
|
|
93
98
|
const mod = await parseModule(`module Temp ${workflowDef}`);
|
|
94
99
|
if (isWorkflowDefinition(mod.defs[0])) {
|
package/src/language/syntax.ts
CHANGED
|
@@ -39,9 +39,9 @@ export class BasePattern {
|
|
|
39
39
|
|
|
40
40
|
private aliasesAsString(): string | undefined {
|
|
41
41
|
if (this.alias) {
|
|
42
|
-
return ` as ${this.alias}`;
|
|
42
|
+
return ` @as ${this.alias}`;
|
|
43
43
|
} else if (this.aliases) {
|
|
44
|
-
return ` as [${this.aliases.join(',')}]`;
|
|
44
|
+
return ` @as [${this.aliases.join(',')}]`;
|
|
45
45
|
} else {
|
|
46
46
|
return undefined;
|
|
47
47
|
}
|
|
@@ -92,24 +92,24 @@ Note the value passed to the 'salary' attribute - it's an arithmetic expression.
|
|
|
92
92
|
A successful query pattern will return an array of instances. The 'for' pattern can be used to iterate over an array. An example follows:
|
|
93
93
|
|
|
94
94
|
workflow NotifyEmployees {
|
|
95
|
-
{Erp/Employee {salary?> 1000}} as employees;
|
|
95
|
+
{Erp/Employee {salary?> 1000}} @as employees;
|
|
96
96
|
for emp in employees {
|
|
97
97
|
{Erp/SendMail {email emp.email, body "You are selected for an increment!"}}
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
Also note the use of the 'as' keyword - this binds the result of a pattern to an 'alias'. Here the result of the query is bound to the
|
|
101
|
+
Also note the use of the '@as' keyword - this binds the result of a pattern to an 'alias'. Here the result of the query is bound to the
|
|
102
102
|
alias named 'employees'. Any pattern can have an alias, including 'if' and 'for'. An alias can be used to refer to the attributes of the instance,
|
|
103
103
|
via the dot(.) notation. Aliases can also be used to destructure a query result - here's an example:
|
|
104
104
|
|
|
105
105
|
workflow FindFirstTwoEmployees {
|
|
106
|
-
{Erp/Employee {salary?> 1000}} as [emp1, emp2];
|
|
106
|
+
{Erp/Employee {salary?> 1000}} @as [emp1, emp2];
|
|
107
107
|
[emp1, emp2]
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
This alias will bind the first two instances to 'a' and 'b' and the rest of the instances to an array named 'xs':
|
|
111
111
|
|
|
112
|
-
{SomeEntity {id?> 1}} as [a, b, _, xs]
|
|
112
|
+
{SomeEntity {id?> 1}} @as [a, b, _, xs]
|
|
113
113
|
|
|
114
114
|
Examples of binding aliases to 'if' and 'for':
|
|
115
115
|
|
|
@@ -117,11 +117,11 @@ if (IncrementSalary.percentage > 10) {
|
|
|
117
117
|
{Erp/Employee {employeeId IncrementSalary.employeeId, salary salary + salary * IncrementSalary.percentage}}
|
|
118
118
|
} else {
|
|
119
119
|
{Erp/Employee {employeeId IncrementSalary.employeeId, salary salary + 1500}}
|
|
120
|
-
} as emp
|
|
120
|
+
} @as emp
|
|
121
121
|
|
|
122
122
|
for emp in employees {
|
|
123
123
|
{Erp/SendMail {email emp.email, body "You are selected for an increment!"}}
|
|
124
|
-
} as emails
|
|
124
|
+
} @as emails
|
|
125
125
|
|
|
126
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
127
|
are invalid, because the alias 'employee' is not defined:
|
|
@@ -131,7 +131,7 @@ are invalid, because the alias 'employee' is not defined:
|
|
|
131
131
|
|
|
132
132
|
A fix for the reference-error is shown below:
|
|
133
133
|
|
|
134
|
-
{Employee {id? 101}} as employee;
|
|
134
|
+
{Employee {id? 101}} @as employee;
|
|
135
135
|
{SendEmail {to employee.email, body "hello"}}
|
|
136
136
|
|
|
137
137
|
Entities in a module can be connected together in relationships. There are two types of relationships - 'contains' and 'between'.
|
|
@@ -198,7 +198,7 @@ fill-in values from the available context. For example, if your instruction is "
|
|
|
198
198
|
'please call me as soon as possible'", the best workflow to return is:
|
|
199
199
|
|
|
200
200
|
workflow sendEmail {
|
|
201
|
-
{employee {id? 101}} as emp;
|
|
201
|
+
{employee {id? 101}} @as emp;
|
|
202
202
|
{email {to emp.email body "please call me as soon as possible"}}
|
|
203
203
|
}
|
|
204
204
|
|
|
@@ -206,7 +206,7 @@ because all the information needed is available in the context. If the instructi
|
|
|
206
206
|
'please call me as soon as possible'", then you can return:
|
|
207
207
|
|
|
208
208
|
workflow sendEmail {
|
|
209
|
-
{employee {id? sendEmail.employeeId}} as emp;
|
|
209
|
+
{employee {id? sendEmail.employeeId}} @as emp;
|
|
210
210
|
{email {to emp.email body "please call me as soon as possible"}}
|
|
211
211
|
}
|
|
212
212
|
|
|
@@ -215,7 +215,7 @@ The point is use the immediate context to fill-in values in generated patterns,
|
|
|
215
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
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
217
|
|
|
218
|
-
[{employee {id? 101}} as emp;
|
|
218
|
+
[{employee {id? 101}} @as emp;
|
|
219
219
|
{email {to emp.email, body "please call me as soon as possible"}}]
|
|
220
220
|
|
|
221
221
|
Note that each pattern in the array is separated by a ; and not a comma(,).
|
|
@@ -74,6 +74,7 @@ import {
|
|
|
74
74
|
addCreateAudit,
|
|
75
75
|
addDeleteAudit,
|
|
76
76
|
addUpdateAudit,
|
|
77
|
+
createSuspension,
|
|
77
78
|
maybeCancelTimer,
|
|
78
79
|
setTimerRunning,
|
|
79
80
|
} from './modules/core.js';
|
|
@@ -103,6 +104,8 @@ function mkEnvName(name: string | undefined, parent: Environment | undefined): s
|
|
|
103
104
|
}
|
|
104
105
|
}
|
|
105
106
|
|
|
107
|
+
type CatchHandlers = Map<string, Statement>;
|
|
108
|
+
|
|
106
109
|
export class Environment extends Instance {
|
|
107
110
|
parent: Environment | undefined;
|
|
108
111
|
|
|
@@ -111,6 +114,7 @@ export class Environment extends Instance {
|
|
|
111
114
|
private activeUser: string = AdminUserId;
|
|
112
115
|
private activeUserSet: boolean = false;
|
|
113
116
|
private lastResult: Result;
|
|
117
|
+
private returnFlag: boolean = false;
|
|
114
118
|
private parentPath: string | undefined;
|
|
115
119
|
private normalizedParentPath: string | undefined;
|
|
116
120
|
private betweenRelInfo: BetweenRelInfo | undefined;
|
|
@@ -119,6 +123,8 @@ export class Environment extends Instance {
|
|
|
119
123
|
private inUpsertMode: boolean = false;
|
|
120
124
|
private inDeleteMode: boolean = false;
|
|
121
125
|
private inKernelMode: boolean = false;
|
|
126
|
+
private suspensionId: string | undefined;
|
|
127
|
+
private activeCatchHandlers: Array<CatchHandlers>;
|
|
122
128
|
|
|
123
129
|
constructor(name?: string, parent?: Environment) {
|
|
124
130
|
super(
|
|
@@ -138,10 +144,13 @@ export class Environment extends Instance {
|
|
|
138
144
|
this.activeResolvers = parent.activeResolvers;
|
|
139
145
|
this.inUpsertMode = parent.inUpsertMode;
|
|
140
146
|
this.inKernelMode = parent.inKernelMode;
|
|
147
|
+
this.activeCatchHandlers = parent.activeCatchHandlers;
|
|
148
|
+
this.suspensionId = parent.suspensionId;
|
|
141
149
|
} else {
|
|
142
150
|
this.activeModule = DefaultModuleName;
|
|
143
151
|
this.activeResolvers = new Map<string, Resolver>();
|
|
144
152
|
this.activeTransactions = new Map<string, string>();
|
|
153
|
+
this.activeCatchHandlers = new Array<CatchHandlers>();
|
|
145
154
|
}
|
|
146
155
|
}
|
|
147
156
|
|
|
@@ -149,6 +158,47 @@ export class Environment extends Instance {
|
|
|
149
158
|
return new Environment(undefined, parent);
|
|
150
159
|
}
|
|
151
160
|
|
|
161
|
+
static fromInstance(inst: Instance): Environment {
|
|
162
|
+
const env = new Environment();
|
|
163
|
+
env.attributes = inst.attributes;
|
|
164
|
+
return env;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
override asSerializableObject(): object {
|
|
168
|
+
const obj: any = super.asSerializableObject();
|
|
169
|
+
obj.activeModule = this.activeModule;
|
|
170
|
+
if (this.activeEventInstance) {
|
|
171
|
+
obj.activeEventInstance = this.activeEventInstance.asSerializableObject();
|
|
172
|
+
}
|
|
173
|
+
obj.activeUser = this.activeUser;
|
|
174
|
+
obj.activeUserSet = this.activeUserSet;
|
|
175
|
+
obj.inUpsertMode = this.inUpsertMode;
|
|
176
|
+
obj.inDeleteMode = this.inDeleteMode;
|
|
177
|
+
obj.inKernelMode = this.inKernelMode;
|
|
178
|
+
if (this.parent) {
|
|
179
|
+
obj.parent = this.parent.asSerializableObject();
|
|
180
|
+
}
|
|
181
|
+
return obj;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
static override FromSerializableObject(obj: any): Environment {
|
|
185
|
+
const inst = Instance.FromSerializableObject(obj, PlaceholderRecordEntry);
|
|
186
|
+
const env = Environment.fromInstance(inst);
|
|
187
|
+
env.activeModule = obj.activeModule;
|
|
188
|
+
if (obj.activeEventInstance) {
|
|
189
|
+
env.activeEventInstance = Instance.FromSerializableObject(obj.activeEventInstance);
|
|
190
|
+
}
|
|
191
|
+
env.activeUser = obj.activeUser;
|
|
192
|
+
env.activeUserSet = obj.activeUserSet;
|
|
193
|
+
env.inUpsertMode = obj.inUpsertMode;
|
|
194
|
+
env.inDeleteMode = obj.inDeleteMode;
|
|
195
|
+
env.inKernelMode = obj.inKernelMode;
|
|
196
|
+
if (obj.parent) {
|
|
197
|
+
env.parent = Environment.FromSerializableObject(obj.parent);
|
|
198
|
+
}
|
|
199
|
+
return env;
|
|
200
|
+
}
|
|
201
|
+
|
|
152
202
|
override lookup(k: string): Result {
|
|
153
203
|
const v = this.attributes.get(k);
|
|
154
204
|
if (v == undefined) {
|
|
@@ -173,6 +223,17 @@ export class Environment extends Instance {
|
|
|
173
223
|
return this;
|
|
174
224
|
}
|
|
175
225
|
|
|
226
|
+
static SuspensionUserData = '^';
|
|
227
|
+
|
|
228
|
+
bindSuspensionUserData(userData: string): Environment {
|
|
229
|
+
this.bind(Environment.SuspensionUserData, userData);
|
|
230
|
+
return this;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
lookupSuspensionUserData(): string | undefined {
|
|
234
|
+
return this.lookup(Environment.SuspensionUserData);
|
|
235
|
+
}
|
|
236
|
+
|
|
176
237
|
maybeLookupAgentInstance(entryName: string): Instance | undefined {
|
|
177
238
|
const v = this.lookup(entryName);
|
|
178
239
|
if (v && isInstanceOfType(v, AgentFqName)) {
|
|
@@ -200,6 +261,47 @@ export class Environment extends Instance {
|
|
|
200
261
|
return this.activeEventInstance;
|
|
201
262
|
}
|
|
202
263
|
|
|
264
|
+
isSuspended(): boolean {
|
|
265
|
+
return this.suspensionId != undefined;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
suspend(): string {
|
|
269
|
+
if (this.suspensionId == undefined) {
|
|
270
|
+
const id = crypto.randomUUID();
|
|
271
|
+
this.propagateSuspension(id);
|
|
272
|
+
return id;
|
|
273
|
+
} else {
|
|
274
|
+
return this.suspensionId;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
markForReturn(): Environment {
|
|
279
|
+
if (this.parent) {
|
|
280
|
+
this.parent.markForReturn();
|
|
281
|
+
}
|
|
282
|
+
this.returnFlag = true;
|
|
283
|
+
return this;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
isMarkedForReturn(): boolean {
|
|
287
|
+
return this.returnFlag;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
protected propagateSuspension(suspId: string) {
|
|
291
|
+
this.suspensionId = suspId;
|
|
292
|
+
if (this.parent) {
|
|
293
|
+
this.parent.propagateSuspension(suspId);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
getSuspensionId(): string {
|
|
298
|
+
if (this.suspensionId) {
|
|
299
|
+
return this.suspensionId;
|
|
300
|
+
} else {
|
|
301
|
+
throw new Error('SuspensionId is not set');
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
203
305
|
getActiveAuthContext(): ActiveSessionInfo | undefined {
|
|
204
306
|
if (this.activeEventInstance) {
|
|
205
307
|
return this.activeEventInstance.getAuthContext();
|
|
@@ -285,7 +387,7 @@ export class Environment extends Instance {
|
|
|
285
387
|
getResolver(resolverName: string): Resolver | undefined {
|
|
286
388
|
const r: Resolver | undefined = this.getActiveResolvers().get(resolverName);
|
|
287
389
|
if (r) {
|
|
288
|
-
return r.
|
|
390
|
+
return r.setEnvironment(this);
|
|
289
391
|
}
|
|
290
392
|
return undefined;
|
|
291
393
|
}
|
|
@@ -293,7 +395,7 @@ export class Environment extends Instance {
|
|
|
293
395
|
async addResolver(resolver: Resolver): Promise<Environment> {
|
|
294
396
|
this.getActiveResolvers().set(resolver.getName(), resolver);
|
|
295
397
|
await this.ensureTransactionForResolver(resolver);
|
|
296
|
-
resolver.
|
|
398
|
+
resolver.setEnvironment(this);
|
|
297
399
|
return this;
|
|
298
400
|
}
|
|
299
401
|
|
|
@@ -393,6 +495,26 @@ export class Environment extends Instance {
|
|
|
393
495
|
isInKernelMode(): boolean {
|
|
394
496
|
return this.inKernelMode;
|
|
395
497
|
}
|
|
498
|
+
|
|
499
|
+
pushHandlers(handlers: CatchHandlers): boolean {
|
|
500
|
+
if (handlers.has('error')) {
|
|
501
|
+
this.activeCatchHandlers.push(handlers);
|
|
502
|
+
return true;
|
|
503
|
+
}
|
|
504
|
+
return false;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
hasHandlers(): boolean {
|
|
508
|
+
return this.activeCatchHandlers.length > 0;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
popHandlers(): CatchHandlers {
|
|
512
|
+
const r = this.activeCatchHandlers.pop();
|
|
513
|
+
if (r == undefined) {
|
|
514
|
+
throw new Error(`No more handlers to pop`);
|
|
515
|
+
}
|
|
516
|
+
return r;
|
|
517
|
+
}
|
|
396
518
|
}
|
|
397
519
|
|
|
398
520
|
export const GlobalEnvironment = new Environment();
|
|
@@ -402,7 +524,7 @@ export async function evaluate(
|
|
|
402
524
|
continuation?: Function,
|
|
403
525
|
activeEnv?: Environment,
|
|
404
526
|
kernelCall?: boolean
|
|
405
|
-
): Promise<
|
|
527
|
+
): Promise<Result> {
|
|
406
528
|
let env: Environment | undefined;
|
|
407
529
|
let txnRolledBack: boolean = false;
|
|
408
530
|
try {
|
|
@@ -415,17 +537,22 @@ export async function evaluate(
|
|
|
415
537
|
env.setInKernelMode(true);
|
|
416
538
|
}
|
|
417
539
|
await evaluateStatements(wf.statements, env, continuation);
|
|
540
|
+
return env.getLastResult();
|
|
418
541
|
}
|
|
419
542
|
} else {
|
|
420
543
|
throw new Error('Not an event - ' + eventInstance.name);
|
|
421
544
|
}
|
|
422
545
|
} catch (err) {
|
|
423
|
-
if (env
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
546
|
+
if (env && env.hasHandlers()) {
|
|
547
|
+
throw err;
|
|
548
|
+
} else {
|
|
549
|
+
if (env != undefined && activeEnv == undefined) {
|
|
550
|
+
await env.rollbackAllTransactions().then(() => {
|
|
551
|
+
txnRolledBack = true;
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
throw err;
|
|
427
555
|
}
|
|
428
|
-
throw err;
|
|
429
556
|
} finally {
|
|
430
557
|
if (!txnRolledBack && env != undefined && activeEnv == undefined) {
|
|
431
558
|
await env.commitAllTransactions();
|
|
@@ -466,6 +593,14 @@ export function makeEventEvaluator(moduleName: string): Function {
|
|
|
466
593
|
};
|
|
467
594
|
}
|
|
468
595
|
|
|
596
|
+
function statemtentString(stmt: Statement): string {
|
|
597
|
+
if (stmt.$cstNode) {
|
|
598
|
+
return stmt.$cstNode.text;
|
|
599
|
+
} else {
|
|
600
|
+
throw new Error(`Failed to fetch text for statement - ${stmt}`);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
469
604
|
export async function evaluateStatements(
|
|
470
605
|
stmts: Statement[],
|
|
471
606
|
env: Environment,
|
|
@@ -473,6 +608,22 @@ export async function evaluateStatements(
|
|
|
473
608
|
) {
|
|
474
609
|
for (let i = 0; i < stmts.length; ++i) {
|
|
475
610
|
await evaluateStatement(stmts[i], env);
|
|
611
|
+
if (env.isSuspended()) {
|
|
612
|
+
const cont = stmts.slice(i + 1, stmts.length);
|
|
613
|
+
if (cont.length > 0) {
|
|
614
|
+
const suspId = await createSuspension(
|
|
615
|
+
env.getSuspensionId(),
|
|
616
|
+
cont.map((stmt: Statement) => {
|
|
617
|
+
return statemtentString(stmt);
|
|
618
|
+
}),
|
|
619
|
+
env
|
|
620
|
+
);
|
|
621
|
+
env.setLastResult({ suspension: suspId || 'null' });
|
|
622
|
+
break;
|
|
623
|
+
}
|
|
624
|
+
} else if (env.isMarkedForReturn()) {
|
|
625
|
+
break;
|
|
626
|
+
}
|
|
476
627
|
}
|
|
477
628
|
if (continuation != undefined) {
|
|
478
629
|
continuation(env.getLastResult());
|
|
@@ -482,10 +633,12 @@ export async function evaluateStatements(
|
|
|
482
633
|
async function evaluateStatement(stmt: Statement, env: Environment): Promise<void> {
|
|
483
634
|
const hints = stmt.hints;
|
|
484
635
|
const hasHints = hints && hints.length > 0;
|
|
485
|
-
const handlers:
|
|
486
|
-
|
|
487
|
-
: undefined;
|
|
636
|
+
const handlers: CatchHandlers | undefined = hasHints ? maybeFindHandlers(hints) : undefined;
|
|
637
|
+
let handlersPushed = false;
|
|
488
638
|
try {
|
|
639
|
+
if (handlers) {
|
|
640
|
+
handlersPushed = env.pushHandlers(handlers);
|
|
641
|
+
}
|
|
489
642
|
await evaluatePattern(stmt.pattern, env);
|
|
490
643
|
if (hasHints) {
|
|
491
644
|
maybeBindStatementResultToAlias(hints, env);
|
|
@@ -508,6 +661,10 @@ async function evaluateStatement(stmt: Statement, env: Environment): Promise<voi
|
|
|
508
661
|
} else {
|
|
509
662
|
throw reason;
|
|
510
663
|
}
|
|
664
|
+
} finally {
|
|
665
|
+
if (handlersPushed && env.hasHandlers()) {
|
|
666
|
+
env.popHandlers();
|
|
667
|
+
}
|
|
511
668
|
}
|
|
512
669
|
}
|
|
513
670
|
|
|
@@ -604,6 +761,9 @@ async function evaluatePattern(pat: Pattern, env: Environment): Promise<void> {
|
|
|
604
761
|
await evaluatePurge(pat.purge, env);
|
|
605
762
|
} else if (pat.fullTextSearch) {
|
|
606
763
|
await evaluateFullTextSearch(pat.fullTextSearch, env);
|
|
764
|
+
} else if (pat.return) {
|
|
765
|
+
await evaluatePattern(pat.return.pat, env);
|
|
766
|
+
env.markForReturn();
|
|
607
767
|
}
|
|
608
768
|
}
|
|
609
769
|
|
|
@@ -652,7 +812,7 @@ function getMapKey(k: MapKey): Result {
|
|
|
652
812
|
else if (k.bool != undefined) k.bool == 'true' ? true : false;
|
|
653
813
|
}
|
|
654
814
|
|
|
655
|
-
const DefaultResolverName: string = '
|
|
815
|
+
const DefaultResolverName: string = '-';
|
|
656
816
|
|
|
657
817
|
async function getResolverForPath(
|
|
658
818
|
entryName: string,
|
|
@@ -1384,7 +1544,11 @@ async function runPrePostEvents(
|
|
|
1384
1544
|
logger.debug(`${prefix}: ${value}`);
|
|
1385
1545
|
};
|
|
1386
1546
|
const catchHandler = (reason: any) => {
|
|
1387
|
-
|
|
1547
|
+
if (env.hasHandlers()) {
|
|
1548
|
+
throw reason;
|
|
1549
|
+
} else {
|
|
1550
|
+
logger.error(`${prefix}: ${reason}`);
|
|
1551
|
+
}
|
|
1388
1552
|
};
|
|
1389
1553
|
if (trigInfo.async) {
|
|
1390
1554
|
evaluate(eventInst, callback).catch(catchHandler);
|
package/src/runtime/jsmodules.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { dirname, sep } from 'path';
|
|
1
2
|
import { logger } from './logger.js';
|
|
2
3
|
import { setSubscription } from './resolvers/registry.js';
|
|
3
4
|
import { now, splitRefs } from './util.js';
|
|
@@ -5,12 +6,19 @@ import { now, splitRefs } from './util.js';
|
|
|
5
6
|
const importedModules = new Map<string, any>();
|
|
6
7
|
|
|
7
8
|
// Usage: importModule("./mymodels/acme.js")
|
|
8
|
-
export async function importModule(path: string, name: string) {
|
|
9
|
+
export async function importModule(path: string, name: string, moduleFileName?: string) {
|
|
9
10
|
if (importedModules.has(name)) {
|
|
10
11
|
logger.warn(`Alias '${name}' will overwrite a previously imported module`);
|
|
11
12
|
}
|
|
12
|
-
if (
|
|
13
|
-
|
|
13
|
+
if (moduleFileName) {
|
|
14
|
+
let s: string = dirname(moduleFileName);
|
|
15
|
+
if (s.startsWith('./')) {
|
|
16
|
+
s = s.substring(2);
|
|
17
|
+
}
|
|
18
|
+
path = `${s}${sep}${path}`;
|
|
19
|
+
}
|
|
20
|
+
if ((path.startsWith(sep) || path.startsWith('.')) && moduleFileName) {
|
|
21
|
+
path = process.cwd() + sep + path;
|
|
14
22
|
}
|
|
15
23
|
const m = await import(/* @vite-ignore */ path);
|
|
16
24
|
importedModules.set(name, m);
|
|
@@ -26,7 +34,7 @@ export function moduleImported(moduleName: string): boolean {
|
|
|
26
34
|
|
|
27
35
|
const ReservedImports = new Set<string>(['resolvers']);
|
|
28
36
|
|
|
29
|
-
export function
|
|
37
|
+
export function validateImportName(n: string) {
|
|
30
38
|
if (ReservedImports.has(n)) {
|
|
31
39
|
throw new Error(`${n} is an import reserved by the runtime`);
|
|
32
40
|
}
|
package/src/runtime/loader.ts
CHANGED
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
addAgent,
|
|
46
46
|
} from './module.js';
|
|
47
47
|
import {
|
|
48
|
+
escapeSpecialChars,
|
|
48
49
|
findRbacSchema,
|
|
49
50
|
isString,
|
|
50
51
|
makeFqName,
|
|
@@ -64,7 +65,7 @@ import { AgentEntityName, CoreAIModuleName, LlmEntityName } from './modules/ai.j
|
|
|
64
65
|
import { GenericResolver, GenericResolverMethods } from './resolvers/interface.js';
|
|
65
66
|
import { registerResolver, setResolver, setSubscription } from './resolvers/registry.js';
|
|
66
67
|
import { ConfigSchema } from './state.js';
|
|
67
|
-
import { getModuleFn, importModule,
|
|
68
|
+
import { getModuleFn, importModule, validateImportName } from './jsmodules.js';
|
|
68
69
|
|
|
69
70
|
export async function extractDocument(
|
|
70
71
|
fileName: string,
|
|
@@ -258,7 +259,7 @@ async function loadModule(fileName: string, fsOptions?: any, callback?: Function
|
|
|
258
259
|
|
|
259
260
|
// Extract the AST node
|
|
260
261
|
const module = await extractAstNode<ModuleDefinition>(fileName, services);
|
|
261
|
-
const result: Module = await internModule(module);
|
|
262
|
+
const result: Module = await internModule(module, fileName);
|
|
262
263
|
console.log(chalk.green(`Module ${chalk.bold(result.name)} loaded`));
|
|
263
264
|
logger.info(`Module ${result.name} loaded`);
|
|
264
265
|
if (callback) {
|
|
@@ -446,8 +447,10 @@ async function addAgentDefinition(def: AgentDefinition, moduleName: string) {
|
|
|
446
447
|
hasUserLlm = true;
|
|
447
448
|
}
|
|
448
449
|
const ov = v;
|
|
449
|
-
if (apdef.value.
|
|
450
|
+
if (apdef.value.id || apdef.value.array) {
|
|
450
451
|
v = `"${v}"`;
|
|
452
|
+
} else if (apdef.value.str) {
|
|
453
|
+
v = `"${escapeSpecialChars(v)}"`;
|
|
451
454
|
}
|
|
452
455
|
attrsStrs.push(`${apdef.name} ${v}`);
|
|
453
456
|
attrs.set(apdef.name, ov);
|
|
@@ -544,12 +547,15 @@ export async function parseAndIntern(code: string, moduleName?: string) {
|
|
|
544
547
|
await internModule(r.parseResult.value);
|
|
545
548
|
}
|
|
546
549
|
|
|
547
|
-
export async function internModule(
|
|
550
|
+
export async function internModule(
|
|
551
|
+
module: ModuleDefinition,
|
|
552
|
+
moduleFileName?: string
|
|
553
|
+
): Promise<Module> {
|
|
548
554
|
const mn = module.name;
|
|
549
555
|
const r = addModule(mn);
|
|
550
556
|
module.imports.forEach(async (imp: Import) => {
|
|
551
|
-
|
|
552
|
-
await importModule(imp.path, imp.name);
|
|
557
|
+
validateImportName(imp.name);
|
|
558
|
+
await importModule(imp.path, imp.name, moduleFileName);
|
|
553
559
|
});
|
|
554
560
|
for (let i = 0; i < module.defs.length; ++i) {
|
|
555
561
|
const def = module.defs[i];
|
package/src/runtime/module.ts
CHANGED
|
@@ -469,6 +469,11 @@ export class Record extends ModuleEntry {
|
|
|
469
469
|
});
|
|
470
470
|
scms = `${scms},\n @rbac [${rbs.join(',\n')}]`;
|
|
471
471
|
}
|
|
472
|
+
if (this.meta && this.meta.size > 0) {
|
|
473
|
+
const metaObj = Object.fromEntries(this.meta);
|
|
474
|
+
const ms = `@meta ${JSON.stringify(metaObj)}`;
|
|
475
|
+
scms = `${scms},\n ${ms}`;
|
|
476
|
+
}
|
|
472
477
|
return s.concat('\n{', scms, '\n}\n');
|
|
473
478
|
}
|
|
474
479
|
|
|
@@ -2189,21 +2194,66 @@ export class Instance {
|
|
|
2189
2194
|
return this.lookup(PathAttributeName);
|
|
2190
2195
|
}
|
|
2191
2196
|
|
|
2197
|
+
asSerializableObject(): object {
|
|
2198
|
+
const obj = {
|
|
2199
|
+
AL_INSTANCE: true,
|
|
2200
|
+
name: this.name,
|
|
2201
|
+
moduleName: this.moduleName,
|
|
2202
|
+
attributes: this.attributesAsObject(true),
|
|
2203
|
+
queryAttributes: this.queryAttributesAsObject(),
|
|
2204
|
+
queryAttributeValues: this.queryAttributeValuesAsObject(),
|
|
2205
|
+
};
|
|
2206
|
+
return obj;
|
|
2207
|
+
}
|
|
2208
|
+
|
|
2209
|
+
static FromSerializableObject(obj: any, record?: Record): Instance {
|
|
2210
|
+
if (obj.AL_INSTANCE == true) {
|
|
2211
|
+
const m = fetchModule(obj.moduleName);
|
|
2212
|
+
return new Instance(
|
|
2213
|
+
record || (m.getEntry(obj.name) as Record),
|
|
2214
|
+
obj.moduleName,
|
|
2215
|
+
obj.name,
|
|
2216
|
+
new Map(Object.entries(obj.attributes)),
|
|
2217
|
+
new Map(Object.entries(obj.queryAttributes)),
|
|
2218
|
+
new Map(Object.entries(obj.queryAttributeValues))
|
|
2219
|
+
);
|
|
2220
|
+
} else {
|
|
2221
|
+
throw new Error(`Cannot deserialize ${JSON.stringify(obj)} to an Instance`);
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2192
2225
|
asObject(): object {
|
|
2193
2226
|
const result: Map<string, object> = new Map<string, object>();
|
|
2194
|
-
result.set(this.name,
|
|
2227
|
+
result.set(this.name, this.attributesAsObject());
|
|
2195
2228
|
return Object.fromEntries(result);
|
|
2196
2229
|
}
|
|
2197
2230
|
|
|
2198
|
-
attributesAsObject(
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
})
|
|
2205
|
-
|
|
2206
|
-
|
|
2231
|
+
attributesAsObject(forSerialization: boolean = false): object {
|
|
2232
|
+
const attrs = newInstanceAttributes();
|
|
2233
|
+
this.attributes.forEach((v: any, k: string) => {
|
|
2234
|
+
if (v instanceof Instance) {
|
|
2235
|
+
const inst = v as Instance;
|
|
2236
|
+
attrs.set(k, forSerialization ? inst.asSerializableObject() : inst.asObject());
|
|
2237
|
+
} else if (v instanceof Object) {
|
|
2238
|
+
const obj = v instanceof Map ? Object.fromEntries(v) : v;
|
|
2239
|
+
attrs.set(k, obj);
|
|
2240
|
+
} else {
|
|
2241
|
+
attrs.set(k, v);
|
|
2242
|
+
}
|
|
2243
|
+
});
|
|
2244
|
+
return Object.fromEntries(attrs);
|
|
2245
|
+
}
|
|
2246
|
+
|
|
2247
|
+
attributesWithStringifiedObjects(): object {
|
|
2248
|
+
const attrs = newInstanceAttributes();
|
|
2249
|
+
this.attributes.forEach((v: any, k: string) => {
|
|
2250
|
+
if (v instanceof Object) {
|
|
2251
|
+
attrs.set(k, JSON.stringify(v instanceof Map ? Object.fromEntries(v) : v));
|
|
2252
|
+
} else {
|
|
2253
|
+
attrs.set(k, v);
|
|
2254
|
+
}
|
|
2255
|
+
});
|
|
2256
|
+
return Object.fromEntries(attrs);
|
|
2207
2257
|
}
|
|
2208
2258
|
|
|
2209
2259
|
queryAttributesAsObject(): object {
|
|
@@ -2414,7 +2464,7 @@ export function makeInstance(
|
|
|
2414
2464
|
throw new Error(`Invalid attribute ${key} specified for ${moduleName}/${entryName}`);
|
|
2415
2465
|
}
|
|
2416
2466
|
const spec: AttributeSpec = getAttributeSpec(schema, key);
|
|
2417
|
-
validateType(key, value, spec);
|
|
2467
|
+
if (value != null && value != undefined) validateType(key, value, spec);
|
|
2418
2468
|
});
|
|
2419
2469
|
}
|
|
2420
2470
|
if (!queryAttributes && !queryAll) {
|
|
@@ -31,8 +31,9 @@ entity ${AgentEntityName} {
|
|
|
31
31
|
type @enum("chat", "planner") @default("chat"),
|
|
32
32
|
runWorkflows Boolean @default(true),
|
|
33
33
|
instruction String @optional,
|
|
34
|
-
tools String @optional, // comma-separated
|
|
35
|
-
documents String @optional, // comma-separated
|
|
34
|
+
tools String @optional, // comma-separated list of tool names
|
|
35
|
+
documents String @optional, // comma-separated list of document names
|
|
36
|
+
channels String @optional, // comma-separated list of channel names
|
|
36
37
|
llm String
|
|
37
38
|
}
|
|
38
39
|
|
|
@@ -42,7 +43,7 @@ entity agentChatSession {
|
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
workflow findAgentChatSession {
|
|
45
|
-
{agentChatSession {id? findAgentChatSession.id}} as [sess];
|
|
46
|
+
{agentChatSession {id? findAgentChatSession.id}} @as [sess];
|
|
46
47
|
sess
|
|
47
48
|
}
|
|
48
49
|
|
|
@@ -69,6 +70,7 @@ export class AgentInstance {
|
|
|
69
70
|
type: string = 'chat';
|
|
70
71
|
tools: string | undefined;
|
|
71
72
|
documents: string | undefined;
|
|
73
|
+
channels: string | undefined;
|
|
72
74
|
runWorkflows: boolean = true;
|
|
73
75
|
|
|
74
76
|
private constructor() {}
|
|
@@ -150,10 +152,19 @@ export class AgentInstance {
|
|
|
150
152
|
}
|
|
151
153
|
|
|
152
154
|
private toolsAsString(): string {
|
|
153
|
-
|
|
155
|
+
let finalTools: string | undefined = undefined;
|
|
156
|
+
if (this.tools) finalTools = this.tools;
|
|
157
|
+
if (this.channels) {
|
|
158
|
+
if (finalTools) {
|
|
159
|
+
finalTools = `${finalTools},${this.channels}`;
|
|
160
|
+
} else {
|
|
161
|
+
finalTools = this.channels;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (finalTools) {
|
|
154
165
|
const tooldefs = new Array<string>();
|
|
155
166
|
const slimModules = new Map<string, string[]>();
|
|
156
|
-
|
|
167
|
+
finalTools.split(',').forEach((n: string) => {
|
|
157
168
|
let moduleName: string | undefined;
|
|
158
169
|
let entryName: string | undefined;
|
|
159
170
|
if (isFqName(n)) {
|