agentlang 0.9.11 → 0.10.1
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/language/generated/ast.d.ts +60 -42
- package/out/language/generated/ast.d.ts.map +1 -1
- package/out/language/generated/ast.js +45 -31
- 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 +294 -327
- package/out/language/generated/grammar.js.map +1 -1
- package/out/language/main.cjs +336 -358
- package/out/language/main.cjs.map +2 -2
- package/out/language/parser.d.ts +11 -1
- package/out/language/parser.d.ts.map +1 -1
- package/out/language/parser.js +56 -6
- package/out/language/parser.js.map +1 -1
- package/out/language/syntax.d.ts +8 -0
- package/out/language/syntax.d.ts.map +1 -1
- package/out/language/syntax.js +11 -2
- package/out/language/syntax.js.map +1 -1
- package/out/runtime/agents/common.d.ts +2 -2
- package/out/runtime/agents/common.js +1 -1
- package/out/runtime/interpreter.d.ts.map +1 -1
- package/out/runtime/interpreter.js +104 -87
- package/out/runtime/interpreter.js.map +1 -1
- package/out/runtime/modules/ai.d.ts +2 -5
- package/out/runtime/modules/ai.d.ts.map +1 -1
- package/out/runtime/modules/ai.js +28 -19
- package/out/runtime/modules/ai.js.map +1 -1
- package/out/runtime/services/documentFetcher.js +2 -2
- package/out/runtime/services/documentFetcher.js.map +1 -1
- package/out/runtime/util.d.ts +10 -0
- package/out/runtime/util.d.ts.map +1 -1
- package/out/runtime/util.js +27 -2
- package/out/runtime/util.js.map +1 -1
- package/out/utils/fs/index.d.ts +12 -2
- package/out/utils/fs/index.d.ts.map +1 -1
- package/out/utils/fs/index.js +27 -6
- package/out/utils/fs/index.js.map +1 -1
- package/package.json +1 -1
- package/src/language/agentlang.langium +6 -9
- package/src/language/generated/ast.ts +66 -43
- package/src/language/generated/grammar.ts +294 -327
- package/src/language/parser.ts +65 -4
- package/src/language/syntax.ts +21 -2
- package/src/runtime/agents/common.ts +1 -1
- package/src/runtime/interpreter.ts +111 -84
- package/src/runtime/modules/ai.ts +35 -25
- package/src/runtime/services/documentFetcher.ts +2 -2
- package/src/runtime/util.ts +45 -2
- package/src/utils/fs/index.ts +30 -6
package/src/language/parser.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
ForEach,
|
|
9
9
|
FullTextSearch,
|
|
10
10
|
Group,
|
|
11
|
+
GroupByClause,
|
|
11
12
|
Handler,
|
|
12
13
|
If,
|
|
13
14
|
isExpr,
|
|
@@ -17,20 +18,24 @@ import {
|
|
|
17
18
|
isNotExpr,
|
|
18
19
|
isPrimExpr,
|
|
19
20
|
isWorkflowDefinition,
|
|
21
|
+
JoinSpec,
|
|
20
22
|
Literal,
|
|
21
23
|
MapEntry,
|
|
22
24
|
MapLiteral,
|
|
23
25
|
ModuleDefinition,
|
|
24
26
|
NegExpr,
|
|
25
27
|
NotExpr,
|
|
28
|
+
OrderByClause,
|
|
26
29
|
Pattern,
|
|
27
30
|
PrimExpr,
|
|
31
|
+
QueryOption,
|
|
28
32
|
RelationshipPattern,
|
|
29
33
|
Return,
|
|
30
34
|
SelectIntoEntry,
|
|
31
35
|
SelectIntoSpec,
|
|
32
36
|
SetAttribute,
|
|
33
37
|
Statement,
|
|
38
|
+
WhereSpec,
|
|
34
39
|
WorkflowDefinition,
|
|
35
40
|
} from './generated/ast.js';
|
|
36
41
|
import { firstAliasSpec, firstCatchSpec, isString, QuerySuffix } from '../runtime/util.js';
|
|
@@ -44,6 +49,7 @@ import {
|
|
|
44
49
|
FunctionCallPattern,
|
|
45
50
|
GroupExpressionPattern,
|
|
46
51
|
IfPattern,
|
|
52
|
+
JoinPattern,
|
|
47
53
|
LiteralPattern,
|
|
48
54
|
NegExpressionPattern,
|
|
49
55
|
NotExpressionPattern,
|
|
@@ -267,8 +273,9 @@ function introspectPattern(pat: Pattern): BasePattern {
|
|
|
267
273
|
} else {
|
|
268
274
|
r = introspectCreatePattern(pat.crudMap);
|
|
269
275
|
}
|
|
270
|
-
|
|
271
|
-
|
|
276
|
+
const opts = extractQueryOptions(pat.crudMap);
|
|
277
|
+
if (opts.into) {
|
|
278
|
+
r = introspectInto(opts.into, r as CrudPattern);
|
|
272
279
|
}
|
|
273
280
|
} else if (pat.expr) {
|
|
274
281
|
r = introspectExpression(pat.expr);
|
|
@@ -358,9 +365,20 @@ function introspectQueryPattern(crudMap: CrudMap): CrudPattern {
|
|
|
358
365
|
crudMap.body?.attributes.forEach((sa: SetAttribute) => {
|
|
359
366
|
cp.addAttribute(sa.name, introspectExpression(sa.value), sa.op);
|
|
360
367
|
});
|
|
361
|
-
|
|
368
|
+
const opts = extractQueryOptions(crudMap);
|
|
369
|
+
crudMap.relationships?.forEach((rp: RelationshipPattern) => {
|
|
362
370
|
cp.addRelationship(rp.name, introspectPattern(rp.pattern) as CrudPattern | CrudPattern[]);
|
|
363
371
|
});
|
|
372
|
+
opts.joins?.forEach((js: JoinSpec) => {
|
|
373
|
+
const jp: JoinPattern = {
|
|
374
|
+
type: js.type,
|
|
375
|
+
targetEntity: js.name,
|
|
376
|
+
conditionLhs: js.lhs,
|
|
377
|
+
conditionOperator: js.op ? js.op : '=',
|
|
378
|
+
conditionRhs: js.rhs,
|
|
379
|
+
};
|
|
380
|
+
cp.joins.push(jp);
|
|
381
|
+
});
|
|
364
382
|
cp.isCreate = false;
|
|
365
383
|
cp.isQueryUpdate = false;
|
|
366
384
|
cp.isQuery = true;
|
|
@@ -369,6 +387,49 @@ function introspectQueryPattern(crudMap: CrudMap): CrudPattern {
|
|
|
369
387
|
throw new Error(`Failed to introspect query-pattern: ${crudMap}`);
|
|
370
388
|
}
|
|
371
389
|
|
|
390
|
+
export type ExtractedQueryOptions = {
|
|
391
|
+
joins: JoinSpec[] | undefined;
|
|
392
|
+
into: SelectIntoSpec | undefined;
|
|
393
|
+
where: WhereSpec | undefined;
|
|
394
|
+
groupByClause: GroupByClause | undefined;
|
|
395
|
+
orderByClause: OrderByClause | undefined;
|
|
396
|
+
upsert: '@upsert' | undefined;
|
|
397
|
+
distinct: '@distinct' | undefined;
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
export function extractQueryOptions(crudMap: CrudMap): ExtractedQueryOptions {
|
|
401
|
+
const r: ExtractedQueryOptions = {
|
|
402
|
+
joins: undefined,
|
|
403
|
+
into: undefined,
|
|
404
|
+
where: undefined,
|
|
405
|
+
groupByClause: undefined,
|
|
406
|
+
orderByClause: undefined,
|
|
407
|
+
upsert: undefined,
|
|
408
|
+
distinct: undefined,
|
|
409
|
+
};
|
|
410
|
+
crudMap.queryOptions.forEach((qo: QueryOption) => {
|
|
411
|
+
if (qo.join) {
|
|
412
|
+
if (r.joins === undefined) {
|
|
413
|
+
r.joins = new Array<JoinSpec>();
|
|
414
|
+
}
|
|
415
|
+
r.joins.push(qo.join);
|
|
416
|
+
} else if (qo.into) {
|
|
417
|
+
r.into = qo.into;
|
|
418
|
+
} else if (qo.where) {
|
|
419
|
+
r.where = qo.where;
|
|
420
|
+
} else if (qo.groupByClause) {
|
|
421
|
+
r.groupByClause = qo.groupByClause;
|
|
422
|
+
} else if (qo.orderByClause) {
|
|
423
|
+
r.orderByClause = qo.orderByClause;
|
|
424
|
+
} else if (qo.upsert) {
|
|
425
|
+
r.upsert = qo.upsert;
|
|
426
|
+
} else if (qo.distinct) {
|
|
427
|
+
r.distinct = qo.distinct;
|
|
428
|
+
}
|
|
429
|
+
});
|
|
430
|
+
return r;
|
|
431
|
+
}
|
|
432
|
+
|
|
372
433
|
function introspectCreatePattern(crudMap: CrudMap): CrudPattern {
|
|
373
434
|
if (crudMap) {
|
|
374
435
|
const cp: CrudPattern = new CrudPattern(crudMap.name);
|
|
@@ -381,7 +442,7 @@ function introspectCreatePattern(crudMap: CrudMap): CrudPattern {
|
|
|
381
442
|
}
|
|
382
443
|
cp.addAttribute(sa.name, introspectExpression(sa.value), sa.op);
|
|
383
444
|
});
|
|
384
|
-
crudMap.relationships
|
|
445
|
+
crudMap.relationships?.forEach((rp: RelationshipPattern) => {
|
|
385
446
|
cp.addRelationship(rp.name, introspectPattern(rp.pattern) as CrudPattern | CrudPattern[]);
|
|
386
447
|
});
|
|
387
448
|
cp.isQueryUpdate = qup;
|
package/src/language/syntax.ts
CHANGED
|
@@ -373,10 +373,24 @@ export type AttributePattern = {
|
|
|
373
373
|
value: BasePattern;
|
|
374
374
|
};
|
|
375
375
|
|
|
376
|
+
export type JoinPattern = {
|
|
377
|
+
type: '@join' | '@inner_join' | '@left_join' | '@right_join' | '@full_join';
|
|
378
|
+
targetEntity: string;
|
|
379
|
+
conditionLhs: string;
|
|
380
|
+
conditionOperator: string;
|
|
381
|
+
conditionRhs: string;
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
function joinPatternToString(jp: JoinPattern): string {
|
|
385
|
+
const opr = jp.conditionOperator === '=' ? '' : jp.conditionOperator;
|
|
386
|
+
return `${jp.type} ${jp.targetEntity} {${jp.conditionLhs}${opr} ${jp.conditionRhs}}`;
|
|
387
|
+
}
|
|
388
|
+
|
|
376
389
|
export class CrudPattern extends BasePattern {
|
|
377
390
|
recordName: string;
|
|
378
391
|
attributes: Array<AttributePattern>;
|
|
379
392
|
relationships: Map<string, CrudPattern[] | CrudPattern> | undefined;
|
|
393
|
+
joins: JoinPattern[];
|
|
380
394
|
into: Map<string, string> | undefined;
|
|
381
395
|
isQuery: boolean = false;
|
|
382
396
|
isQueryUpdate: boolean = false;
|
|
@@ -391,6 +405,7 @@ export class CrudPattern extends BasePattern {
|
|
|
391
405
|
} else {
|
|
392
406
|
this.isCreate = true;
|
|
393
407
|
}
|
|
408
|
+
this.joins = new Array<JoinPattern>();
|
|
394
409
|
}
|
|
395
410
|
|
|
396
411
|
addAttribute(n: string, p: BasePattern, op?: string): CrudPattern {
|
|
@@ -521,11 +536,15 @@ export class CrudPattern extends BasePattern {
|
|
|
521
536
|
let s = `{${this.recordName} ${this.attributesAsString()}`;
|
|
522
537
|
const rs = this.relationshipsAsString();
|
|
523
538
|
if (rs) {
|
|
524
|
-
s = s.concat(
|
|
539
|
+
s = s.concat(`,\n${rs}`);
|
|
540
|
+
}
|
|
541
|
+
if (this.joins.length > 0) {
|
|
542
|
+
const js = this.joins.map(joinPatternToString);
|
|
543
|
+
s = s.concat(`,\n${js.join(',\n')}`);
|
|
525
544
|
}
|
|
526
545
|
const ins = this.intoAsString();
|
|
527
546
|
if (ins) {
|
|
528
|
-
s = s.concat(
|
|
547
|
+
s = s.concat(`,\n${ins}`);
|
|
529
548
|
}
|
|
530
549
|
return s.concat('}', this.hintsAsString());
|
|
531
550
|
}
|
|
@@ -209,7 +209,7 @@ A pattern may execute asynchronously and its eventual result can be handled by p
|
|
|
209
209
|
If you are instructed that a particular event will be called asynchronously, always provide the patterns that follows in its '@then' clause. You must add the
|
|
210
210
|
'@then' clause only if an event's documentation or instruction explicitly requires to do so.
|
|
211
211
|
|
|
212
|
-
Earlier we discussed
|
|
212
|
+
Earlier we discussed the concept of 'between' relationship. Here's the 'CreateEmployee' workflow updated to create the Employee with the his/her Profile attached:
|
|
213
213
|
|
|
214
214
|
workflow CreateEmployee {
|
|
215
215
|
{Erp/Employee {firstName CreateEmployee.firstName,
|
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
WhereSpec,
|
|
33
33
|
} from '../language/generated/ast.js';
|
|
34
34
|
import {
|
|
35
|
+
Agent,
|
|
35
36
|
defineAgentEvent,
|
|
36
37
|
Event,
|
|
37
38
|
getOneOfRef,
|
|
@@ -79,7 +80,12 @@ import {
|
|
|
79
80
|
splitRefs,
|
|
80
81
|
} from './util.js';
|
|
81
82
|
import { getResolver, getResolverNameForPath } from './resolvers/registry.js';
|
|
82
|
-
import {
|
|
83
|
+
import {
|
|
84
|
+
ExtractedQueryOptions,
|
|
85
|
+
extractQueryOptions,
|
|
86
|
+
parseStatement,
|
|
87
|
+
parseWorkflow,
|
|
88
|
+
} from '../language/parser.js';
|
|
83
89
|
import { ActiveSessionInfo, AdminSession, AdminUserId } from './auth/defs.js';
|
|
84
90
|
import {
|
|
85
91
|
AgentEntityName,
|
|
@@ -1496,17 +1502,18 @@ async function maybeValidateOneOfRefs(inst: Instance, env: Environment) {
|
|
|
1496
1502
|
}
|
|
1497
1503
|
}
|
|
1498
1504
|
|
|
1499
|
-
function maybeSetQueryClauses(inst: Instance,
|
|
1500
|
-
if (
|
|
1501
|
-
inst.setGroupBy(
|
|
1505
|
+
function maybeSetQueryClauses(inst: Instance, qopts: ExtractedQueryOptions) {
|
|
1506
|
+
if (qopts.groupByClause) {
|
|
1507
|
+
inst.setGroupBy(qopts.groupByClause.colNames);
|
|
1502
1508
|
}
|
|
1503
|
-
if (
|
|
1504
|
-
inst.setOrderBy(
|
|
1509
|
+
if (qopts.orderByClause) {
|
|
1510
|
+
inst.setOrderBy(qopts.orderByClause.colNames, qopts.orderByClause.order === '@desc');
|
|
1505
1511
|
}
|
|
1506
1512
|
}
|
|
1507
1513
|
|
|
1508
1514
|
async function evaluateCrudMap(crud: CrudMap, env: Environment): Promise<void> {
|
|
1509
|
-
|
|
1515
|
+
const qopts = extractQueryOptions(crud);
|
|
1516
|
+
if (!env.isInUpsertMode() && qopts.upsert !== undefined) {
|
|
1510
1517
|
return await evaluateUpsert(crud, env);
|
|
1511
1518
|
}
|
|
1512
1519
|
const inst: Instance = crud.source
|
|
@@ -1518,12 +1525,12 @@ async function evaluateCrudMap(crud: CrudMap, env: Environment): Promise<void> {
|
|
|
1518
1525
|
const qattrs = inst.queryAttributes;
|
|
1519
1526
|
const onlyAggregates = inst.aggregates !== undefined && qattrs === undefined;
|
|
1520
1527
|
const isQueryAll = onlyAggregates || crud.name.endsWith(QuerySuffix);
|
|
1521
|
-
const distinct: boolean =
|
|
1522
|
-
maybeSetQueryClauses(inst,
|
|
1528
|
+
const distinct: boolean = qopts.distinct !== undefined;
|
|
1529
|
+
maybeSetQueryClauses(inst, qopts);
|
|
1523
1530
|
if (attrs.size > 0) {
|
|
1524
1531
|
await maybeValidateOneOfRefs(inst, env);
|
|
1525
1532
|
}
|
|
1526
|
-
if (
|
|
1533
|
+
if (qopts.into) {
|
|
1527
1534
|
if (attrs.size > 0) {
|
|
1528
1535
|
throw new Error(
|
|
1529
1536
|
`Query pattern for ${entryName} with 'into' clause cannot be used to update attributes`
|
|
@@ -1532,10 +1539,16 @@ async function evaluateCrudMap(crud: CrudMap, env: Environment): Promise<void> {
|
|
|
1532
1539
|
if (qattrs === undefined && !isQueryAll) {
|
|
1533
1540
|
throw new Error(`Pattern for ${entryName} with 'into' clause must be a query`);
|
|
1534
1541
|
}
|
|
1535
|
-
if (
|
|
1536
|
-
await evaluateJoinQuery(
|
|
1542
|
+
if (qopts.joins && qopts.joins.length > 0) {
|
|
1543
|
+
await evaluateJoinQuery(qopts.joins, qopts.into, qopts.where, inst, distinct, env);
|
|
1537
1544
|
} else {
|
|
1538
|
-
await evaluateJoinQueryWithRelationships(
|
|
1545
|
+
await evaluateJoinQueryWithRelationships(
|
|
1546
|
+
qopts.into,
|
|
1547
|
+
inst,
|
|
1548
|
+
crud.relationships || [],
|
|
1549
|
+
distinct,
|
|
1550
|
+
env
|
|
1551
|
+
);
|
|
1539
1552
|
}
|
|
1540
1553
|
return;
|
|
1541
1554
|
}
|
|
@@ -2081,7 +2094,7 @@ async function agentInvoke(agent: AgentInstance, msg: string, env: Environment):
|
|
|
2081
2094
|
const obj = agent.maybeValidateJsonResponse(result);
|
|
2082
2095
|
if (obj !== undefined) {
|
|
2083
2096
|
env.setLastResult(obj);
|
|
2084
|
-
env.addToScratchPad(agent.getFqName(), obj);
|
|
2097
|
+
env.addToScratchPad(Agent.NormalizeName(agent.getFqName()), obj);
|
|
2085
2098
|
}
|
|
2086
2099
|
break;
|
|
2087
2100
|
} catch (err: any) {
|
|
@@ -2187,6 +2200,7 @@ export async function restartFlow(
|
|
|
2187
2200
|
}
|
|
2188
2201
|
|
|
2189
2202
|
const MaxFlowSteps = 25;
|
|
2203
|
+
const MaxFlowRetries = 10;
|
|
2190
2204
|
|
|
2191
2205
|
async function iterateOnFlow(
|
|
2192
2206
|
flow: FlowSpec,
|
|
@@ -2195,88 +2209,101 @@ async function iterateOnFlow(
|
|
|
2195
2209
|
env: Environment
|
|
2196
2210
|
): Promise<void> {
|
|
2197
2211
|
rootAgent.disableSession();
|
|
2198
|
-
const
|
|
2199
|
-
const
|
|
2212
|
+
const chatId = env.getActiveEventInstance()?.lookup('chatId');
|
|
2213
|
+
const iterId = chatId || crypto.randomUUID();
|
|
2214
|
+
let step = '';
|
|
2215
|
+
let fullFlowRetries = 0;
|
|
2216
|
+
while (true) {
|
|
2217
|
+
try {
|
|
2218
|
+
const initContext = msg;
|
|
2219
|
+
const s = `Now consider the following flowchart and return the next step:\n${flow}\n
|
|
2200
2220
|
If you understand from the context that a step with no further possible steps has been evaluated,
|
|
2201
2221
|
terminate the flowchart by returning DONE. Never return to the top or root step of the flowchart, instead return DONE.
|
|
2202
2222
|
Important: Return only the next flow-step or DONE. Do not return any additional description, like your thinking process.\n`;
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
env.flagMonitorEntryAsFlow().incrementMonitor();
|
|
2218
|
-
}
|
|
2219
|
-
let isfxc = false;
|
|
2220
|
-
try {
|
|
2221
|
-
while (step != 'DONE' && !executedSteps.has(step)) {
|
|
2222
|
-
if (stepc > MaxFlowSteps) {
|
|
2223
|
-
throw new Error(`Flow execution exceeded maximum steps limit`);
|
|
2223
|
+
env.setFlowContext(initContext);
|
|
2224
|
+
await agentInvoke(rootAgent, s, env);
|
|
2225
|
+
const rootModuleName = rootAgent.moduleName;
|
|
2226
|
+
let preprocResult = await preprocessStep(env.getLastResult(), rootModuleName, env);
|
|
2227
|
+
step = preprocResult.step;
|
|
2228
|
+
let needAgentProcessing = preprocResult.needAgentProcessing;
|
|
2229
|
+
let context = initContext;
|
|
2230
|
+
let stepc = 0;
|
|
2231
|
+
console.debug(`Starting iteration ${iterId} on flow: ${flow}`);
|
|
2232
|
+
const executedSteps = new Set<string>();
|
|
2233
|
+
const monitoringEnabled = isMonitoringEnabled();
|
|
2234
|
+
let isfxc = false;
|
|
2235
|
+
if (monitoringEnabled) {
|
|
2236
|
+
env.flagMonitorEntryAsFlow().incrementMonitor();
|
|
2224
2237
|
}
|
|
2225
|
-
executedSteps.
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2238
|
+
while (step != 'DONE' && !executedSteps.has(step)) {
|
|
2239
|
+
if (stepc > MaxFlowSteps) {
|
|
2240
|
+
throw new Error(`Flow execution exceeded maximum steps limit`);
|
|
2241
|
+
}
|
|
2242
|
+
executedSteps.add(step);
|
|
2243
|
+
++stepc;
|
|
2244
|
+
const agent = needAgentProcessing
|
|
2245
|
+
? AgentInstance.FromFlowStep(step, rootAgent, context)
|
|
2246
|
+
: undefined;
|
|
2247
|
+
if (agent) {
|
|
2248
|
+
console.debug(
|
|
2249
|
+
`Starting to execute flow step ${step} with agent ${agent.name} with iteration ID ${iterId} and context: \n${context}`
|
|
2250
|
+
);
|
|
2251
|
+
isfxc = agent.isFlowExecutor();
|
|
2252
|
+
const isdec = agent.isDecisionExecutor();
|
|
2253
|
+
if (isfxc || isdec) env.setFlowContext(context);
|
|
2254
|
+
else env.setFlowContext(initContext);
|
|
2255
|
+
if (monitoringEnabled) {
|
|
2256
|
+
env.appendEntryToMonitor(step);
|
|
2257
|
+
}
|
|
2258
|
+
const inst = agent.swapInstruction('');
|
|
2259
|
+
await agentInvoke(agent, inst, env);
|
|
2260
|
+
} else {
|
|
2261
|
+
rootAgent.maybeAddScratchData(env);
|
|
2262
|
+
}
|
|
2263
|
+
if (monitoringEnabled) env.setMonitorEntryResult(env.getLastResult());
|
|
2264
|
+
if (env.isSuspended()) {
|
|
2265
|
+
console.debug(`${iterId} suspending iteration on step ${step}`);
|
|
2266
|
+
await saveFlowSuspension(rootAgent, context, step, env);
|
|
2267
|
+
env.releaseSuspension();
|
|
2268
|
+
return;
|
|
2269
|
+
}
|
|
2270
|
+
const r = env.getLastResult();
|
|
2271
|
+
const rs = maybeInstanceAsString(r);
|
|
2232
2272
|
console.debug(
|
|
2233
|
-
|
|
2273
|
+
`\n----> Completed execution of step ${step}, iteration id ${iterId} with result:\n${rs}`
|
|
2234
2274
|
);
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2275
|
+
context = `${context}\n${step} --> ${rs}\n`;
|
|
2276
|
+
if (chatId) {
|
|
2277
|
+
const suspEnv = new Environment(env.name, env);
|
|
2278
|
+
suspEnv.softSuspend();
|
|
2279
|
+
await saveFlowSuspension(rootAgent, context, step, suspEnv);
|
|
2280
|
+
await saveFlowStepResult(chatId, step, rs, suspEnv.getSuspensionId(), env);
|
|
2241
2281
|
}
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
env.releaseSuspension();
|
|
2252
|
-
return;
|
|
2253
|
-
}
|
|
2254
|
-
const r = env.getLastResult();
|
|
2255
|
-
const rs = maybeInstanceAsString(r);
|
|
2256
|
-
console.debug(
|
|
2257
|
-
`\n----> Completed execution of step ${step}, iteration id ${iterId} with result:\n${rs}`
|
|
2258
|
-
);
|
|
2259
|
-
context = `${context}\n${step} --> ${rs}\n`;
|
|
2260
|
-
if (chatId) {
|
|
2261
|
-
const suspEnv = new Environment(env.name, env);
|
|
2262
|
-
suspEnv.softSuspend();
|
|
2263
|
-
await saveFlowSuspension(rootAgent, context, step, suspEnv);
|
|
2264
|
-
await saveFlowStepResult(chatId, step, rs, suspEnv.getSuspensionId(), env);
|
|
2282
|
+
if (isfxc) {
|
|
2283
|
+
preprocResult = await preprocessStep(rs, rootModuleName, env);
|
|
2284
|
+
} else {
|
|
2285
|
+
env.setFlowContext(context);
|
|
2286
|
+
await agentInvoke(rootAgent, `${s}\n${context}`, env);
|
|
2287
|
+
preprocResult = await preprocessStep(env.getLastResult(), rootModuleName, env);
|
|
2288
|
+
}
|
|
2289
|
+
step = preprocResult.step;
|
|
2290
|
+
needAgentProcessing = preprocResult.needAgentProcessing;
|
|
2265
2291
|
}
|
|
2266
|
-
|
|
2267
|
-
|
|
2292
|
+
} catch (reason: any) {
|
|
2293
|
+
if (fullFlowRetries < MaxFlowRetries) {
|
|
2294
|
+
msg = `The previous attempt failed at step ${step} with the error ${reason}. Restart the flow the appropriate step
|
|
2295
|
+
(maybe even from the first step) and try to fix the issue.`;
|
|
2296
|
+
++fullFlowRetries;
|
|
2297
|
+
continue;
|
|
2268
2298
|
} else {
|
|
2269
|
-
|
|
2270
|
-
await agentInvoke(rootAgent, `${s}\n${context}`, env);
|
|
2271
|
-
preprocResult = await preprocessStep(env.getLastResult(), rootModuleName, env);
|
|
2299
|
+
throw new Error(reason);
|
|
2272
2300
|
}
|
|
2273
|
-
|
|
2274
|
-
|
|
2301
|
+
} finally {
|
|
2302
|
+
env.decrementMonitor().revokeLastResult().setMonitorFlowResult();
|
|
2275
2303
|
}
|
|
2276
|
-
|
|
2277
|
-
|
|
2304
|
+
console.debug(`No more flow steps, completed iteration ${iterId} on flow:\n${flow}`);
|
|
2305
|
+
break;
|
|
2278
2306
|
}
|
|
2279
|
-
console.debug(`No more flow steps, completed iteration ${iterId} on flow:\n${flow}`);
|
|
2280
2307
|
}
|
|
2281
2308
|
|
|
2282
2309
|
type PreprocStepResult = {
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DefaultModuleName,
|
|
3
3
|
escapeSpecialChars,
|
|
4
|
+
extractAndRemoveAllXmlTaggedText,
|
|
5
|
+
ExtractedCode,
|
|
6
|
+
ExtractedText,
|
|
7
|
+
extractFencedCodeBlocks,
|
|
4
8
|
isFqName,
|
|
5
9
|
isString,
|
|
6
10
|
makeCoreModuleName,
|
|
@@ -17,6 +21,7 @@ import {
|
|
|
17
21
|
parseAndEvaluateStatement,
|
|
18
22
|
} from '../interpreter.js';
|
|
19
23
|
import {
|
|
24
|
+
Agent,
|
|
20
25
|
AgentEvaluator,
|
|
21
26
|
asJSONSchema,
|
|
22
27
|
Decision,
|
|
@@ -579,7 +584,7 @@ export class AgentInstance {
|
|
|
579
584
|
}
|
|
580
585
|
}
|
|
581
586
|
|
|
582
|
-
private async
|
|
587
|
+
private async getFullInstructionsHelper(
|
|
583
588
|
env: Environment,
|
|
584
589
|
activator: AgentInstructionActivator
|
|
585
590
|
): Promise<string> {
|
|
@@ -651,6 +656,20 @@ Only return a pure JSON object with no extra text, annotations etc.`;
|
|
|
651
656
|
}
|
|
652
657
|
}
|
|
653
658
|
|
|
659
|
+
private static UserTag = 'user';
|
|
660
|
+
|
|
661
|
+
private async getFullInstructions(
|
|
662
|
+
env: Environment,
|
|
663
|
+
activator: AgentInstructionActivator
|
|
664
|
+
): Promise<ExtractedText> {
|
|
665
|
+
const finalInstruction = await this.getFullInstructionsHelper(env, activator);
|
|
666
|
+
if (finalInstruction.indexOf(`<${AgentInstance.UserTag}>`) > 0) {
|
|
667
|
+
return extractAndRemoveAllXmlTaggedText(finalInstruction, AgentInstance.UserTag);
|
|
668
|
+
} else {
|
|
669
|
+
return { extracted: undefined, updatedText: finalInstruction };
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
654
673
|
private static maybeRewriteTemplatePatterns(
|
|
655
674
|
scratchPad: any,
|
|
656
675
|
instruction: string,
|
|
@@ -709,7 +728,7 @@ Only return a pure JSON object with no extra text, annotations etc.`;
|
|
|
709
728
|
) {
|
|
710
729
|
r = obj;
|
|
711
730
|
} else {
|
|
712
|
-
env.addToScratchPad(this.name, obj);
|
|
731
|
+
env.addToScratchPad(Agent.NormalizeName(this.name), obj);
|
|
713
732
|
return this;
|
|
714
733
|
}
|
|
715
734
|
const scratchNames = this.getScratchNames();
|
|
@@ -819,6 +838,7 @@ Only return a pure JSON object with no extra text, annotations etc.`;
|
|
|
819
838
|
const sess: Instance | null = this.withSession ? await findAgentChatSession(chatId, env) : null;
|
|
820
839
|
let msgs: BaseMessage[] | undefined;
|
|
821
840
|
let cachedMsg: string | undefined = undefined;
|
|
841
|
+
let extractedText: ExtractedText | undefined;
|
|
822
842
|
const activator: AgentInstructionActivator = {
|
|
823
843
|
provider: p,
|
|
824
844
|
userMessage: message,
|
|
@@ -828,7 +848,8 @@ Only return a pure JSON object with no extra text, annotations etc.`;
|
|
|
828
848
|
if (sess) {
|
|
829
849
|
msgs = sess.lookup('messages');
|
|
830
850
|
} else {
|
|
831
|
-
|
|
851
|
+
extractedText = await this.getFullInstructions(env, activator);
|
|
852
|
+
cachedMsg = extractedText.updatedText;
|
|
832
853
|
msgs = [systemMessage(cachedMsg || '')];
|
|
833
854
|
}
|
|
834
855
|
if (msgs) {
|
|
@@ -843,12 +864,21 @@ Only return a pure JSON object with no extra text, annotations etc.`;
|
|
|
843
864
|
? EvalInstructions
|
|
844
865
|
: LearnerAgentInstructions;
|
|
845
866
|
const ts = this.toolsAsString();
|
|
846
|
-
|
|
867
|
+
let tmpMsg = cachedMsg;
|
|
868
|
+
if (!tmpMsg) {
|
|
869
|
+
extractedText = await this.getFullInstructions(env, activator);
|
|
870
|
+
tmpMsg = extractedText.updatedText;
|
|
871
|
+
}
|
|
872
|
+
const msg = `${s}\n${ts}\n${tmpMsg}`;
|
|
847
873
|
const newSysMsg = systemMessage(msg);
|
|
848
874
|
msgs[0] = newSysMsg;
|
|
849
875
|
}
|
|
876
|
+
let tmpMsg = message;
|
|
877
|
+
if (extractedText?.extracted) {
|
|
878
|
+
tmpMsg = `${tmpMsg}\n${extractedText.extracted.join('\n')}`;
|
|
879
|
+
}
|
|
850
880
|
const hmsg = await this.maybeAddRelevantDocuments(
|
|
851
|
-
this.maybeAddFlowContext(
|
|
881
|
+
this.maybeAddFlowContext(tmpMsg, env),
|
|
852
882
|
env
|
|
853
883
|
);
|
|
854
884
|
if (hmsg.length > 0) {
|
|
@@ -1298,26 +1328,6 @@ function processScenarioResponse(resp: string): string {
|
|
|
1298
1328
|
return resp;
|
|
1299
1329
|
}
|
|
1300
1330
|
|
|
1301
|
-
type ExtractedCode = {
|
|
1302
|
-
language: string | null;
|
|
1303
|
-
code: string;
|
|
1304
|
-
};
|
|
1305
|
-
|
|
1306
|
-
export function extractFencedCodeBlocks(markdown: string): ExtractedCode[] {
|
|
1307
|
-
const codeBlockRegex = /```(\w+)?\n([\s\S]*?)```/g;
|
|
1308
|
-
const blocks: ExtractedCode[] = [];
|
|
1309
|
-
let match;
|
|
1310
|
-
|
|
1311
|
-
while ((match = codeBlockRegex.exec(markdown)) !== null) {
|
|
1312
|
-
blocks.push({
|
|
1313
|
-
language: match[1] || null,
|
|
1314
|
-
code: match[2],
|
|
1315
|
-
});
|
|
1316
|
-
}
|
|
1317
|
-
|
|
1318
|
-
return blocks;
|
|
1319
|
-
}
|
|
1320
|
-
|
|
1321
1331
|
export function normalizeGeneratedCode(code: string | undefined): string {
|
|
1322
1332
|
if (code !== undefined) {
|
|
1323
1333
|
const blocks = extractFencedCodeBlocks(code);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3';
|
|
2
|
-
import { readFile } from '
|
|
2
|
+
import { readFile } from '../../utils/fs-utils.js';
|
|
3
3
|
import { logger } from '../logger.js';
|
|
4
4
|
import { parseAndEvaluateStatement } from '../interpreter.js';
|
|
5
5
|
import { CoreAIModuleName } from '../modules/ai.js';
|
|
@@ -443,7 +443,7 @@ class DocumentFetcherService {
|
|
|
443
443
|
|
|
444
444
|
private async fetchFromLocal(filePath: string): Promise<string> {
|
|
445
445
|
try {
|
|
446
|
-
const content = await readFile(filePath
|
|
446
|
+
const content = await readFile(filePath);
|
|
447
447
|
const lowerPath = filePath.toLowerCase();
|
|
448
448
|
const isMarkdown = lowerPath.endsWith('.md') || lowerPath.endsWith('.markdown');
|
|
449
449
|
|
package/src/runtime/util.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isNodeEnv } from '../utils/runtime.js';
|
|
1
|
+
import { isNodeEnv, path } from '../utils/runtime.js';
|
|
2
2
|
import {
|
|
3
3
|
AliasSpec,
|
|
4
4
|
CatchSpec,
|
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
} from '../language/generated/ast.js';
|
|
16
16
|
import { readFile } from '../utils/fs-utils.js';
|
|
17
17
|
import bcrypt from 'bcryptjs';
|
|
18
|
-
import path from 'node:path';
|
|
19
18
|
|
|
20
19
|
export const QuerySuffix = '?';
|
|
21
20
|
|
|
@@ -665,3 +664,47 @@ export function objectAsString(obj: any, keyAsString: boolean = false) {
|
|
|
665
664
|
});
|
|
666
665
|
return `{${entries.join(', ')}}`;
|
|
667
666
|
}
|
|
667
|
+
|
|
668
|
+
export type ExtractedText = {
|
|
669
|
+
extracted: string[] | undefined;
|
|
670
|
+
updatedText: string;
|
|
671
|
+
};
|
|
672
|
+
|
|
673
|
+
// extract all data between a given xml tag from within an arbitray text.
|
|
674
|
+
export function extractAndRemoveAllXmlTaggedText(text: string, tagName: string): ExtractedText {
|
|
675
|
+
const pattern = `<${tagName}\\b[^>]*>([\\s\\S]*?)</${tagName}>`;
|
|
676
|
+
const regex = new RegExp(pattern, 'gi');
|
|
677
|
+
|
|
678
|
+
const extracted = [];
|
|
679
|
+
let updatedText = text;
|
|
680
|
+
|
|
681
|
+
let match;
|
|
682
|
+
while ((match = regex.exec(text)) !== null) {
|
|
683
|
+
extracted.push(match[1]);
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
updatedText = text.replace(regex, '');
|
|
687
|
+
|
|
688
|
+
return { extracted, updatedText };
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
export type ExtractedCode = {
|
|
692
|
+
language: string | null;
|
|
693
|
+
code: string;
|
|
694
|
+
};
|
|
695
|
+
|
|
696
|
+
// extract tick-quoted code from markdown-formatted text.
|
|
697
|
+
export function extractFencedCodeBlocks(markdown: string): ExtractedCode[] {
|
|
698
|
+
const codeBlockRegex = /```(\w+)?\n([\s\S]*?)```/g;
|
|
699
|
+
const blocks: ExtractedCode[] = [];
|
|
700
|
+
let match;
|
|
701
|
+
|
|
702
|
+
while ((match = codeBlockRegex.exec(markdown)) !== null) {
|
|
703
|
+
blocks.push({
|
|
704
|
+
language: match[1] || null,
|
|
705
|
+
code: match[2],
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
return blocks;
|
|
710
|
+
}
|