agentlang 0.10.0 → 0.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/api/http.d.ts.map +1 -1
- package/out/api/http.js +136 -0
- package/out/api/http.js.map +1 -1
- package/out/language/generated/ast.d.ts +87 -44
- package/out/language/generated/ast.d.ts.map +1 -1
- package/out/language/generated/ast.js +65 -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 +337 -330
- package/out/language/generated/grammar.js.map +1 -1
- package/out/language/main.cjs +396 -361
- 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 +74 -8
- package/out/language/parser.js.map +1 -1
- package/out/language/syntax.d.ts +14 -0
- package/out/language/syntax.d.ts.map +1 -1
- package/out/language/syntax.js +60 -27
- 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/api.d.ts +2 -0
- package/out/runtime/api.d.ts.map +1 -1
- package/out/runtime/api.js +3 -0
- package/out/runtime/api.js.map +1 -1
- package/out/runtime/datefns.d.ts +34 -0
- package/out/runtime/datefns.d.ts.map +1 -0
- package/out/runtime/datefns.js +82 -0
- package/out/runtime/datefns.js.map +1 -0
- package/out/runtime/exec-graph.d.ts.map +1 -1
- package/out/runtime/exec-graph.js +22 -3
- package/out/runtime/exec-graph.js.map +1 -1
- package/out/runtime/interpreter.d.ts +9 -0
- package/out/runtime/interpreter.d.ts.map +1 -1
- package/out/runtime/interpreter.js +85 -20
- package/out/runtime/interpreter.js.map +1 -1
- package/out/runtime/module.d.ts +8 -0
- package/out/runtime/module.d.ts.map +1 -1
- package/out/runtime/module.js +23 -0
- package/out/runtime/module.js.map +1 -1
- package/out/runtime/modules/ai.d.ts +9 -8
- package/out/runtime/modules/ai.d.ts.map +1 -1
- package/out/runtime/modules/ai.js +92 -37
- package/out/runtime/modules/ai.js.map +1 -1
- package/out/runtime/modules/core.d.ts.map +1 -1
- package/out/runtime/modules/core.js +5 -1
- package/out/runtime/modules/core.js.map +1 -1
- package/out/runtime/monitor.d.ts +6 -0
- package/out/runtime/monitor.d.ts.map +1 -1
- package/out/runtime/monitor.js +21 -1
- package/out/runtime/monitor.js.map +1 -1
- package/out/runtime/relgraph.d.ts.map +1 -1
- package/out/runtime/relgraph.js +7 -3
- package/out/runtime/relgraph.js.map +1 -1
- package/out/runtime/resolvers/interface.d.ts +3 -2
- package/out/runtime/resolvers/interface.d.ts.map +1 -1
- package/out/runtime/resolvers/interface.js +3 -2
- package/out/runtime/resolvers/interface.js.map +1 -1
- package/out/runtime/resolvers/sqldb/dbutil.d.ts.map +1 -1
- package/out/runtime/resolvers/sqldb/dbutil.js +17 -4
- package/out/runtime/resolvers/sqldb/dbutil.js.map +1 -1
- package/out/runtime/resolvers/sqldb/impl.d.ts +1 -1
- package/out/runtime/resolvers/sqldb/impl.d.ts.map +1 -1
- package/out/runtime/resolvers/sqldb/impl.js +17 -7
- package/out/runtime/resolvers/sqldb/impl.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 +12 -1
- package/out/runtime/util.d.ts.map +1 -1
- package/out/runtime/util.js +38 -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/out/test-harness.d.ts +36 -0
- package/out/test-harness.d.ts.map +1 -0
- package/out/test-harness.js +341 -0
- package/out/test-harness.js.map +1 -0
- 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 +4 -1
- package/src/api/http.ts +138 -0
- package/src/language/agentlang.langium +9 -10
- package/src/language/generated/ast.ts +98 -44
- package/src/language/generated/grammar.ts +337 -330
- package/src/language/parser.ts +87 -6
- package/src/language/syntax.ts +71 -24
- package/src/runtime/agents/common.ts +1 -1
- package/src/runtime/api.ts +5 -0
- package/src/runtime/datefns.ts +112 -0
- package/src/runtime/exec-graph.ts +23 -2
- package/src/runtime/interpreter.ts +107 -19
- package/src/runtime/module.ts +26 -0
- package/src/runtime/modules/ai.ts +110 -54
- package/src/runtime/modules/core.ts +5 -1
- package/src/runtime/monitor.ts +27 -1
- package/src/runtime/relgraph.ts +7 -3
- package/src/runtime/resolvers/interface.ts +4 -2
- package/src/runtime/resolvers/sqldb/dbutil.ts +20 -6
- package/src/runtime/resolvers/sqldb/impl.ts +17 -7
- package/src/runtime/services/documentFetcher.ts +2 -2
- package/src/runtime/util.ts +62 -2
- package/src/syntaxes/agentlang.monarch.ts +1 -1
- package/src/test-harness.ts +423 -0
- package/src/utils/fs/index.ts +30 -6
|
@@ -80,7 +80,12 @@ import {
|
|
|
80
80
|
splitRefs,
|
|
81
81
|
} from './util.js';
|
|
82
82
|
import { getResolver, getResolverNameForPath } from './resolvers/registry.js';
|
|
83
|
-
import {
|
|
83
|
+
import {
|
|
84
|
+
ExtractedQueryOptions,
|
|
85
|
+
extractQueryOptions,
|
|
86
|
+
parseStatement,
|
|
87
|
+
parseWorkflow,
|
|
88
|
+
} from '../language/parser.js';
|
|
84
89
|
import { ActiveSessionInfo, AdminSession, AdminUserId } from './auth/defs.js';
|
|
85
90
|
import {
|
|
86
91
|
AgentEntityName,
|
|
@@ -114,6 +119,7 @@ import { Monitor, MonitorEntry } from './monitor.js';
|
|
|
114
119
|
import { detailedDiff } from 'deep-object-diff';
|
|
115
120
|
import { callMcpTool, mcpClientNameFromToolEvent } from './mcpclient.js';
|
|
116
121
|
import { isNodeEnv } from '../utils/runtime.js';
|
|
122
|
+
import Handlebars from 'handlebars';
|
|
117
123
|
|
|
118
124
|
export type Result = any;
|
|
119
125
|
|
|
@@ -126,6 +132,7 @@ export function isEmptyResult(r: Result): boolean {
|
|
|
126
132
|
type BetweenRelInfo = {
|
|
127
133
|
relationship: Relationship;
|
|
128
134
|
connectedInstance: Instance;
|
|
135
|
+
connectedAlias?: string;
|
|
129
136
|
};
|
|
130
137
|
|
|
131
138
|
function mkEnvName(name: string | undefined, parent: Environment | undefined): string {
|
|
@@ -150,6 +157,7 @@ export class Environment extends Instance {
|
|
|
150
157
|
private activeUserSet: boolean = false;
|
|
151
158
|
private lastResult: Result;
|
|
152
159
|
private trashedResult: Result = undefined;
|
|
160
|
+
private lastPattern: string | undefined;
|
|
153
161
|
private returnFlag: boolean = false;
|
|
154
162
|
private parentPath: string | undefined;
|
|
155
163
|
private normalizedParentPath: string | undefined;
|
|
@@ -169,6 +177,7 @@ export class Environment extends Instance {
|
|
|
169
177
|
private agentChatId: string | undefined = undefined;
|
|
170
178
|
private monitor: Monitor | undefined = undefined;
|
|
171
179
|
private escalatedRole: string | undefined;
|
|
180
|
+
private activeChatId: string | undefined;
|
|
172
181
|
|
|
173
182
|
private activeUserData: any = undefined;
|
|
174
183
|
|
|
@@ -196,6 +205,7 @@ export class Environment extends Instance {
|
|
|
196
205
|
this.agentChatId = parent.agentChatId;
|
|
197
206
|
this.monitor = parent.monitor;
|
|
198
207
|
this.escalatedRole = parent.escalatedRole;
|
|
208
|
+
this.activeChatId = parent.activeChatId;
|
|
199
209
|
} else {
|
|
200
210
|
this.activeModule = DefaultModuleName;
|
|
201
211
|
this.activeResolvers = new Map<string, Resolver>();
|
|
@@ -322,6 +332,15 @@ export class Environment extends Instance {
|
|
|
322
332
|
return this.attributes.get(Environment.FlowContextTag);
|
|
323
333
|
}
|
|
324
334
|
|
|
335
|
+
setActiveChatId(chatId: string): Environment {
|
|
336
|
+
this.activeChatId = chatId;
|
|
337
|
+
return this;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
getActiveChatId(): string | undefined {
|
|
341
|
+
return this.activeChatId;
|
|
342
|
+
}
|
|
343
|
+
|
|
325
344
|
addToScratchPad(k: string, data: any): Environment {
|
|
326
345
|
if (this.scratchPad === undefined) {
|
|
327
346
|
this.scratchPad = {};
|
|
@@ -392,6 +411,11 @@ export class Environment extends Instance {
|
|
|
392
411
|
return this;
|
|
393
412
|
}
|
|
394
413
|
|
|
414
|
+
maybeRewriteTemplatePatterns(instruction: string, scratchPad?: any): string {
|
|
415
|
+
const templ = Handlebars.compile(this.rewriteTemplateMappings(instruction));
|
|
416
|
+
return templ(scratchPad);
|
|
417
|
+
}
|
|
418
|
+
|
|
395
419
|
static SuspensionUserData = '^';
|
|
396
420
|
|
|
397
421
|
bindSuspensionUserData(userData: string): Environment {
|
|
@@ -549,6 +573,15 @@ export class Environment extends Instance {
|
|
|
549
573
|
return this.lastResult;
|
|
550
574
|
}
|
|
551
575
|
|
|
576
|
+
setLastPattern(pattern: string | undefined): Environment {
|
|
577
|
+
this.lastPattern = pattern;
|
|
578
|
+
return this;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
getLastPattern(): string | undefined {
|
|
582
|
+
return this.lastPattern;
|
|
583
|
+
}
|
|
584
|
+
|
|
552
585
|
getActiveModuleName(): string {
|
|
553
586
|
return this.activeModule;
|
|
554
587
|
}
|
|
@@ -886,6 +919,13 @@ export class Environment extends Instance {
|
|
|
886
919
|
return this;
|
|
887
920
|
}
|
|
888
921
|
|
|
922
|
+
setMonitorEntryLlmTokenUsage(input: number, output: number, total: number): Environment {
|
|
923
|
+
if (this.monitor !== undefined) {
|
|
924
|
+
this.monitor.setEntryLlmTokenUsage(input, output, total);
|
|
925
|
+
}
|
|
926
|
+
return this;
|
|
927
|
+
}
|
|
928
|
+
|
|
889
929
|
incrementMonitor(): Environment {
|
|
890
930
|
if (this.monitor !== undefined) {
|
|
891
931
|
this.monitor = this.monitor.increment();
|
|
@@ -934,7 +974,13 @@ export let evaluate = async function (
|
|
|
934
974
|
} else if (isAgentEventInstance(eventInstance)) {
|
|
935
975
|
env = new Environment(eventInstance.name + '.env', activeEnv);
|
|
936
976
|
await handleAgentInvocation(eventInstance, env);
|
|
937
|
-
if (continuation)
|
|
977
|
+
if (continuation) {
|
|
978
|
+
if (env.getLastPattern()) {
|
|
979
|
+
continuation({ result: env.getLastResult(), pattern: env.getLastPattern() });
|
|
980
|
+
} else {
|
|
981
|
+
continuation(env.getLastResult());
|
|
982
|
+
}
|
|
983
|
+
}
|
|
938
984
|
} else if (isOpenApiEventInstance(eventInstance)) {
|
|
939
985
|
env = new Environment(eventInstance.name + '.env', activeEnv);
|
|
940
986
|
await handleOpenApiEvent(eventInstance, env);
|
|
@@ -1087,6 +1133,9 @@ export async function evaluateStatement(stmt: Statement, env: Environment): Prom
|
|
|
1087
1133
|
handlersPushed = env.pushHandlers(handlers);
|
|
1088
1134
|
}
|
|
1089
1135
|
await evaluatePattern(stmt.pattern, env);
|
|
1136
|
+
if (hasHints) {
|
|
1137
|
+
await maybeHandleEmpty(hints, env);
|
|
1138
|
+
}
|
|
1090
1139
|
if (hasHints) {
|
|
1091
1140
|
maybeBindStatementResultToAlias(hints, env);
|
|
1092
1141
|
}
|
|
@@ -1116,6 +1165,24 @@ async function maybeHandleNotFound(handlers: CatchHandlers | undefined, env: Env
|
|
|
1116
1165
|
}
|
|
1117
1166
|
}
|
|
1118
1167
|
|
|
1168
|
+
async function maybeHandleEmpty(hints: RuntimeHint[], env: Environment) {
|
|
1169
|
+
const lastResult: Result = env.getLastResult();
|
|
1170
|
+
if (
|
|
1171
|
+
lastResult === null ||
|
|
1172
|
+
lastResult === undefined ||
|
|
1173
|
+
(lastResult instanceof Array && lastResult.length == 0)
|
|
1174
|
+
) {
|
|
1175
|
+
for (const rh of hints) {
|
|
1176
|
+
if (rh.emptySpec) {
|
|
1177
|
+
const newEnv = new Environment('empty-env', env).unsetEventExecutor();
|
|
1178
|
+
await evaluateStatement(rh.emptySpec.stmt, newEnv);
|
|
1179
|
+
env.setLastResult(newEnv.getLastResult());
|
|
1180
|
+
break;
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1119
1186
|
async function maybeHandleError(
|
|
1120
1187
|
handlers: CatchHandlers | undefined,
|
|
1121
1188
|
reason: any,
|
|
@@ -1497,17 +1564,18 @@ async function maybeValidateOneOfRefs(inst: Instance, env: Environment) {
|
|
|
1497
1564
|
}
|
|
1498
1565
|
}
|
|
1499
1566
|
|
|
1500
|
-
function maybeSetQueryClauses(inst: Instance,
|
|
1501
|
-
if (
|
|
1502
|
-
inst.setGroupBy(
|
|
1567
|
+
function maybeSetQueryClauses(inst: Instance, qopts: ExtractedQueryOptions) {
|
|
1568
|
+
if (qopts.groupByClause) {
|
|
1569
|
+
inst.setGroupBy(qopts.groupByClause.colNames);
|
|
1503
1570
|
}
|
|
1504
|
-
if (
|
|
1505
|
-
inst.setOrderBy(
|
|
1571
|
+
if (qopts.orderByClause) {
|
|
1572
|
+
inst.setOrderBy(qopts.orderByClause.colNames, qopts.orderByClause.order === '@desc');
|
|
1506
1573
|
}
|
|
1507
1574
|
}
|
|
1508
1575
|
|
|
1509
1576
|
async function evaluateCrudMap(crud: CrudMap, env: Environment): Promise<void> {
|
|
1510
|
-
|
|
1577
|
+
const qopts = extractQueryOptions(crud);
|
|
1578
|
+
if (!env.isInUpsertMode() && qopts.upsert !== undefined) {
|
|
1511
1579
|
return await evaluateUpsert(crud, env);
|
|
1512
1580
|
}
|
|
1513
1581
|
const inst: Instance = crud.source
|
|
@@ -1519,12 +1587,12 @@ async function evaluateCrudMap(crud: CrudMap, env: Environment): Promise<void> {
|
|
|
1519
1587
|
const qattrs = inst.queryAttributes;
|
|
1520
1588
|
const onlyAggregates = inst.aggregates !== undefined && qattrs === undefined;
|
|
1521
1589
|
const isQueryAll = onlyAggregates || crud.name.endsWith(QuerySuffix);
|
|
1522
|
-
const distinct: boolean =
|
|
1523
|
-
maybeSetQueryClauses(inst,
|
|
1590
|
+
const distinct: boolean = qopts.distinct !== undefined;
|
|
1591
|
+
maybeSetQueryClauses(inst, qopts);
|
|
1524
1592
|
if (attrs.size > 0) {
|
|
1525
1593
|
await maybeValidateOneOfRefs(inst, env);
|
|
1526
1594
|
}
|
|
1527
|
-
if (
|
|
1595
|
+
if (qopts.into) {
|
|
1528
1596
|
if (attrs.size > 0) {
|
|
1529
1597
|
throw new Error(
|
|
1530
1598
|
`Query pattern for ${entryName} with 'into' clause cannot be used to update attributes`
|
|
@@ -1533,10 +1601,16 @@ async function evaluateCrudMap(crud: CrudMap, env: Environment): Promise<void> {
|
|
|
1533
1601
|
if (qattrs === undefined && !isQueryAll) {
|
|
1534
1602
|
throw new Error(`Pattern for ${entryName} with 'into' clause must be a query`);
|
|
1535
1603
|
}
|
|
1536
|
-
if (
|
|
1537
|
-
await evaluateJoinQuery(
|
|
1604
|
+
if (qopts.joins && qopts.joins.length > 0) {
|
|
1605
|
+
await evaluateJoinQuery(qopts.joins, qopts.into, qopts.where, inst, distinct, env);
|
|
1538
1606
|
} else {
|
|
1539
|
-
await evaluateJoinQueryWithRelationships(
|
|
1607
|
+
await evaluateJoinQueryWithRelationships(
|
|
1608
|
+
qopts.into,
|
|
1609
|
+
inst,
|
|
1610
|
+
crud.relationships || [],
|
|
1611
|
+
distinct,
|
|
1612
|
+
env
|
|
1613
|
+
);
|
|
1540
1614
|
}
|
|
1541
1615
|
return;
|
|
1542
1616
|
}
|
|
@@ -1634,7 +1708,8 @@ async function evaluateCrudMap(crud: CrudMap, env: Environment): Promise<void> {
|
|
|
1634
1708
|
const insts: Instance[] = await res.queryConnectedInstances(
|
|
1635
1709
|
betRelInfo.relationship,
|
|
1636
1710
|
betRelInfo.connectedInstance,
|
|
1637
|
-
inst
|
|
1711
|
+
inst,
|
|
1712
|
+
betRelInfo.connectedAlias
|
|
1638
1713
|
);
|
|
1639
1714
|
env.setLastResult(insts);
|
|
1640
1715
|
} else {
|
|
@@ -1659,7 +1734,7 @@ async function evaluateCrudMap(crud: CrudMap, env: Environment): Promise<void> {
|
|
|
1659
1734
|
false,
|
|
1660
1735
|
true
|
|
1661
1736
|
);
|
|
1662
|
-
env.setLastResult(inst);
|
|
1737
|
+
env.setLastResult([inst]);
|
|
1663
1738
|
} else {
|
|
1664
1739
|
const insts: Instance[] = await res.queryInstances(inst, isQueryAll, distinct);
|
|
1665
1740
|
env.setLastResult(insts);
|
|
@@ -1686,7 +1761,12 @@ async function evaluateCrudMap(crud: CrudMap, env: Environment): Promise<void> {
|
|
|
1686
1761
|
await evaluatePattern(rel.pattern, newEnv);
|
|
1687
1762
|
lastRes[j].attachRelatedInstances(rel.name, newEnv.getLastResult());
|
|
1688
1763
|
} else if (isBetweenRelationship(rel.name, moduleName)) {
|
|
1689
|
-
|
|
1764
|
+
const connAlias = relEntry.isSelfReferencing() ? relEntry.node1.alias : undefined;
|
|
1765
|
+
newEnv.setBetweenRelInfo({
|
|
1766
|
+
relationship: relEntry,
|
|
1767
|
+
connectedInstance: lastRes[j],
|
|
1768
|
+
connectedAlias: connAlias,
|
|
1769
|
+
});
|
|
1690
1770
|
await evaluatePattern(rel.pattern, newEnv);
|
|
1691
1771
|
lastRes[j].attachRelatedInstances(rel.name, newEnv.getLastResult());
|
|
1692
1772
|
}
|
|
@@ -1722,7 +1802,7 @@ async function evaluateCrudMap(crud: CrudMap, env: Environment): Promise<void> {
|
|
|
1722
1802
|
await runPreUpdateEvents(lastRes, env);
|
|
1723
1803
|
const finalInst: Instance = await res.updateInstance(lastRes, attrs);
|
|
1724
1804
|
await runPostUpdateEvents(finalInst, lastRes, env);
|
|
1725
|
-
env.setLastResult(finalInst);
|
|
1805
|
+
env.setLastResult([finalInst]);
|
|
1726
1806
|
}
|
|
1727
1807
|
}
|
|
1728
1808
|
}
|
|
@@ -2023,6 +2103,11 @@ async function agentInvoke(agent: AgentInstance, msg: string, env: Environment):
|
|
|
2023
2103
|
while (true) {
|
|
2024
2104
|
try {
|
|
2025
2105
|
let rs: string = result ? normalizeGeneratedCode(result) : '';
|
|
2106
|
+
if (agent.tools) {
|
|
2107
|
+
env.setLastPattern(rs);
|
|
2108
|
+
} else {
|
|
2109
|
+
env.setLastPattern(undefined);
|
|
2110
|
+
}
|
|
2026
2111
|
let isWf = rs.startsWith('workflow');
|
|
2027
2112
|
if (isWf && !agent.runWorkflows) {
|
|
2028
2113
|
await parseWorkflow(rs);
|
|
@@ -2116,6 +2201,10 @@ export async function handleAgentInvocation(
|
|
|
2116
2201
|
env: Environment
|
|
2117
2202
|
): Promise<void> {
|
|
2118
2203
|
const agent: AgentInstance = await findAgentByName(agentEventInst.name, env);
|
|
2204
|
+
const chatId = agentEventInst.lookup('chatId');
|
|
2205
|
+
if (chatId) {
|
|
2206
|
+
env.setActiveChatId(chatId);
|
|
2207
|
+
}
|
|
2119
2208
|
const origMsg: any =
|
|
2120
2209
|
agentEventInst.lookup('message') || JSON.stringify(agentEventInst.asObject());
|
|
2121
2210
|
const msg: string = isString(origMsg) ? origMsg : maybeInstanceAsString(origMsg);
|
|
@@ -2125,7 +2214,6 @@ export async function handleAgentInvocation(
|
|
|
2125
2214
|
} else {
|
|
2126
2215
|
const mode = agentEventInst.lookup('mode');
|
|
2127
2216
|
let activeEnv = env;
|
|
2128
|
-
const chatId = agentEventInst.lookup('chatId');
|
|
2129
2217
|
if (chatId !== undefined) {
|
|
2130
2218
|
activeEnv.setAgentChatId(chatId);
|
|
2131
2219
|
}
|
package/src/runtime/module.ts
CHANGED
|
@@ -1409,6 +1409,10 @@ export class Relationship extends Record {
|
|
|
1409
1409
|
return this.relType == RelType.BETWEEN;
|
|
1410
1410
|
}
|
|
1411
1411
|
|
|
1412
|
+
isSelfReferencing(): boolean {
|
|
1413
|
+
return this.node1.path.asFqName() === this.node2.path.asFqName();
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1412
1416
|
parentNode(): RelationshipNode {
|
|
1413
1417
|
return this.node1;
|
|
1414
1418
|
}
|
|
@@ -1502,6 +1506,28 @@ export class Relationship extends Record {
|
|
|
1502
1506
|
}
|
|
1503
1507
|
}
|
|
1504
1508
|
|
|
1509
|
+
/**
|
|
1510
|
+
* For self-referencing relationships, resolve the alias for the connected instance
|
|
1511
|
+
* based on an explicit connectedAlias. Falls back to fqName-based lookup for
|
|
1512
|
+
* non-self-referencing relationships.
|
|
1513
|
+
*/
|
|
1514
|
+
getAliasForConnected(inst: Instance, connectedAlias?: string): string {
|
|
1515
|
+
if (connectedAlias && this.isSelfReferencing()) {
|
|
1516
|
+
return connectedAlias;
|
|
1517
|
+
}
|
|
1518
|
+
return this.getAliasFor(inst);
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
getInverseAliasForConnected(inst: Instance, connectedAlias?: string): string {
|
|
1522
|
+
if (connectedAlias && this.isSelfReferencing()) {
|
|
1523
|
+
if (connectedAlias === this.node1.alias) {
|
|
1524
|
+
return this.node2.alias;
|
|
1525
|
+
}
|
|
1526
|
+
return this.node1.alias;
|
|
1527
|
+
}
|
|
1528
|
+
return this.getInverseAliasFor(inst);
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1505
1531
|
isParent(inst: Instance): boolean {
|
|
1506
1532
|
return inst.getFqName() == this.node1.path.asFqName();
|
|
1507
1533
|
}
|
|
@@ -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,
|
|
@@ -66,7 +70,6 @@ import {
|
|
|
66
70
|
} from '../agents/common.js';
|
|
67
71
|
import { logger } from '../logger.js';
|
|
68
72
|
import { FlowStep } from '../agents/flows.js';
|
|
69
|
-
import Handlebars from 'handlebars';
|
|
70
73
|
import { Statement } from '../../language/generated/ast.js';
|
|
71
74
|
import { isMonitoringEnabled, TtlCache } from '../state.js';
|
|
72
75
|
import { isNodeEnv } from '../../utils/runtime.js';
|
|
@@ -103,6 +106,7 @@ entity ${AgentEntityName} {
|
|
|
103
106
|
flows String @optional,
|
|
104
107
|
validate String @optional,
|
|
105
108
|
retry String @optional,
|
|
109
|
+
saveResponseAs String @optional,
|
|
106
110
|
llm String
|
|
107
111
|
}
|
|
108
112
|
|
|
@@ -319,6 +323,7 @@ export class AgentInstance {
|
|
|
319
323
|
flows: string | undefined;
|
|
320
324
|
validate: string | undefined;
|
|
321
325
|
retry: string | undefined;
|
|
326
|
+
saveResponseAs: string | undefined;
|
|
322
327
|
stateless: boolean = false;
|
|
323
328
|
private toolsArray: string[] | undefined = undefined;
|
|
324
329
|
private hasModuleTools = false;
|
|
@@ -580,7 +585,7 @@ export class AgentInstance {
|
|
|
580
585
|
}
|
|
581
586
|
}
|
|
582
587
|
|
|
583
|
-
private async
|
|
588
|
+
private async getFullInstructionsHelper(
|
|
584
589
|
env: Environment,
|
|
585
590
|
activator: AgentInstructionActivator
|
|
586
591
|
): Promise<string> {
|
|
@@ -641,7 +646,7 @@ Only return a pure JSON object with no extra text, annotations etc.`;
|
|
|
641
646
|
const spad = env.getScratchPad();
|
|
642
647
|
if (spad !== undefined && Object.keys(spad).length > 0) {
|
|
643
648
|
if (finalInstruction.indexOf('{{') > 0) {
|
|
644
|
-
return
|
|
649
|
+
return env.maybeRewriteTemplatePatterns(finalInstruction, spad);
|
|
645
650
|
} else {
|
|
646
651
|
const ctx = JSON.stringify(spad);
|
|
647
652
|
return `${finalInstruction}\nSome additional context:\n${ctx}`;
|
|
@@ -652,13 +657,36 @@ Only return a pure JSON object with no extra text, annotations etc.`;
|
|
|
652
657
|
}
|
|
653
658
|
}
|
|
654
659
|
|
|
655
|
-
private static
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
660
|
+
private static UserTag = 'user';
|
|
661
|
+
private static FileTag = 'file';
|
|
662
|
+
|
|
663
|
+
private async getFullInstructions(
|
|
664
|
+
env: Environment,
|
|
665
|
+
activator: AgentInstructionActivator
|
|
666
|
+
): Promise<ExtractedText> {
|
|
667
|
+
const finalInstruction = await this.getFullInstructionsHelper(env, activator);
|
|
668
|
+
if (finalInstruction.indexOf(`<${AgentInstance.UserTag}>`) > 0) {
|
|
669
|
+
return extractAndRemoveAllXmlTaggedText(finalInstruction, AgentInstance.UserTag);
|
|
670
|
+
} else {
|
|
671
|
+
return { extracted: undefined, updatedText: finalInstruction };
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
private async maybeFillInFileContents(instructions: string, env: Environment): Promise<string> {
|
|
676
|
+
const chatId = env.getActiveChatId();
|
|
677
|
+
const FC = '$FC';
|
|
678
|
+
if (chatId && instructions.indexOf(`<${AgentInstance.FileTag}>`) > 0) {
|
|
679
|
+
const ext = extractAndRemoveAllXmlTaggedText(instructions, AgentInstance.FileTag, FC);
|
|
680
|
+
if (ext.extracted) {
|
|
681
|
+
instructions = ext.updatedText;
|
|
682
|
+
for (let i = 0; i < ext.extracted.length; ++i) {
|
|
683
|
+
const fileName = ext.extracted[i];
|
|
684
|
+
const contents = await loadLocalAgentResult(chatId, fileName);
|
|
685
|
+
if (contents) instructions = instructions.replace(FC, contents);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
return instructions;
|
|
662
690
|
}
|
|
663
691
|
|
|
664
692
|
maybeValidateJsonResponse(response: string | undefined): object | undefined {
|
|
@@ -820,6 +848,7 @@ Only return a pure JSON object with no extra text, annotations etc.`;
|
|
|
820
848
|
const sess: Instance | null = this.withSession ? await findAgentChatSession(chatId, env) : null;
|
|
821
849
|
let msgs: BaseMessage[] | undefined;
|
|
822
850
|
let cachedMsg: string | undefined = undefined;
|
|
851
|
+
let extractedText: ExtractedText | undefined;
|
|
823
852
|
const activator: AgentInstructionActivator = {
|
|
824
853
|
provider: p,
|
|
825
854
|
userMessage: message,
|
|
@@ -829,7 +858,8 @@ Only return a pure JSON object with no extra text, annotations etc.`;
|
|
|
829
858
|
if (sess) {
|
|
830
859
|
msgs = sess.lookup('messages');
|
|
831
860
|
} else {
|
|
832
|
-
|
|
861
|
+
extractedText = await this.getFullInstructions(env, activator);
|
|
862
|
+
cachedMsg = extractedText.updatedText;
|
|
833
863
|
msgs = [systemMessage(cachedMsg || '')];
|
|
834
864
|
}
|
|
835
865
|
if (msgs) {
|
|
@@ -844,12 +874,22 @@ Only return a pure JSON object with no extra text, annotations etc.`;
|
|
|
844
874
|
? EvalInstructions
|
|
845
875
|
: LearnerAgentInstructions;
|
|
846
876
|
const ts = this.toolsAsString();
|
|
847
|
-
|
|
877
|
+
let tmpMsg = cachedMsg;
|
|
878
|
+
if (!tmpMsg) {
|
|
879
|
+
extractedText = await this.getFullInstructions(env, activator);
|
|
880
|
+
tmpMsg = extractedText.updatedText;
|
|
881
|
+
}
|
|
882
|
+
const msg = `${s}\n${ts}\n${tmpMsg}`;
|
|
848
883
|
const newSysMsg = systemMessage(msg);
|
|
849
884
|
msgs[0] = newSysMsg;
|
|
850
885
|
}
|
|
886
|
+
let tmpMsg = message;
|
|
887
|
+
if (extractedText?.extracted) {
|
|
888
|
+
const s = await this.maybeFillInFileContents(extractedText.extracted.join('\n'), env);
|
|
889
|
+
tmpMsg = `${tmpMsg}\n${s}`;
|
|
890
|
+
}
|
|
851
891
|
const hmsg = await this.maybeAddRelevantDocuments(
|
|
852
|
-
this.maybeAddFlowContext(
|
|
892
|
+
this.maybeAddFlowContext(tmpMsg, env),
|
|
853
893
|
env
|
|
854
894
|
);
|
|
855
895
|
if (hmsg.length > 0) {
|
|
@@ -898,6 +938,13 @@ Only return a pure JSON object with no extra text, annotations etc.`;
|
|
|
898
938
|
await saveAgentChatSession(chatId, msgs, env);
|
|
899
939
|
}
|
|
900
940
|
if (monitoringEnabled) env.setMonitorEntryLlmResponse(response.content);
|
|
941
|
+
if (monitoringEnabled && response.sysMsg.usage_metadata) {
|
|
942
|
+
const u = response.sysMsg.usage_metadata;
|
|
943
|
+
env.setMonitorEntryLlmTokenUsage(u.input_tokens, u.output_tokens, u.total_tokens);
|
|
944
|
+
}
|
|
945
|
+
if (this.saveResponseAs) {
|
|
946
|
+
await saveAgentResponse(this.saveResponseAs, response.content, env);
|
|
947
|
+
}
|
|
901
948
|
env.setLastResult(response.content);
|
|
902
949
|
} catch (err: any) {
|
|
903
950
|
logger.error(`Error while invoking ${agentName} - ${err}`);
|
|
@@ -1299,26 +1346,6 @@ function processScenarioResponse(resp: string): string {
|
|
|
1299
1346
|
return resp;
|
|
1300
1347
|
}
|
|
1301
1348
|
|
|
1302
|
-
type ExtractedCode = {
|
|
1303
|
-
language: string | null;
|
|
1304
|
-
code: string;
|
|
1305
|
-
};
|
|
1306
|
-
|
|
1307
|
-
export function extractFencedCodeBlocks(markdown: string): ExtractedCode[] {
|
|
1308
|
-
const codeBlockRegex = /```(\w+)?\n([\s\S]*?)```/g;
|
|
1309
|
-
const blocks: ExtractedCode[] = [];
|
|
1310
|
-
let match;
|
|
1311
|
-
|
|
1312
|
-
while ((match = codeBlockRegex.exec(markdown)) !== null) {
|
|
1313
|
-
blocks.push({
|
|
1314
|
-
language: match[1] || null,
|
|
1315
|
-
code: match[2],
|
|
1316
|
-
});
|
|
1317
|
-
}
|
|
1318
|
-
|
|
1319
|
-
return blocks;
|
|
1320
|
-
}
|
|
1321
|
-
|
|
1322
1349
|
export function normalizeGeneratedCode(code: string | undefined): string {
|
|
1323
1350
|
if (code !== undefined) {
|
|
1324
1351
|
const blocks = extractFencedCodeBlocks(code);
|
|
@@ -1439,15 +1466,9 @@ export async function saveFlowStepResultLocally(
|
|
|
1439
1466
|
chatId: string,
|
|
1440
1467
|
step: string,
|
|
1441
1468
|
result: string,
|
|
1442
|
-
suspensionId
|
|
1443
|
-
): Promise<
|
|
1469
|
+
suspensionId?: string | undefined
|
|
1470
|
+
): Promise<string> {
|
|
1444
1471
|
const fs = await getFileSystem();
|
|
1445
|
-
const attrs = newInstanceAttributes()
|
|
1446
|
-
.set('chatId', chatId)
|
|
1447
|
-
.set('step', step)
|
|
1448
|
-
.set('result', result)
|
|
1449
|
-
.set('suspensionId', suspensionId);
|
|
1450
|
-
const inst = makeInstance(CoreAIModuleName, AgentFlowStep, attrs);
|
|
1451
1472
|
const rootDirName = LocalFlowStepsRootDirName;
|
|
1452
1473
|
if (!(await fs.exists(rootDirName))) {
|
|
1453
1474
|
await fs.mkdir(rootDirName);
|
|
@@ -1460,8 +1481,18 @@ export async function saveFlowStepResultLocally(
|
|
|
1460
1481
|
if (await fs.exists(fileName)) {
|
|
1461
1482
|
await fs.unlink(fileName);
|
|
1462
1483
|
}
|
|
1463
|
-
|
|
1464
|
-
|
|
1484
|
+
let s = result;
|
|
1485
|
+
if (suspensionId) {
|
|
1486
|
+
const attrs = newInstanceAttributes()
|
|
1487
|
+
.set('chatId', chatId)
|
|
1488
|
+
.set('step', step)
|
|
1489
|
+
.set('result', result)
|
|
1490
|
+
.set('suspensionId', suspensionId);
|
|
1491
|
+
const inst = makeInstance(CoreAIModuleName, AgentFlowStep, attrs);
|
|
1492
|
+
s = JSON.stringify(inst.attributesAsObject(true));
|
|
1493
|
+
}
|
|
1494
|
+
await fs.writeFile(fileName, s);
|
|
1495
|
+
return s;
|
|
1465
1496
|
}
|
|
1466
1497
|
|
|
1467
1498
|
export async function saveFlowStepResult(
|
|
@@ -1470,9 +1501,10 @@ export async function saveFlowStepResult(
|
|
|
1470
1501
|
result: string,
|
|
1471
1502
|
suspensionId: string,
|
|
1472
1503
|
env: Environment
|
|
1473
|
-
): Promise<
|
|
1504
|
+
): Promise<boolean> {
|
|
1474
1505
|
if (LocalAgentgFlow) {
|
|
1475
|
-
|
|
1506
|
+
await saveFlowStepResultLocally(chatId, step, result, suspensionId);
|
|
1507
|
+
return true;
|
|
1476
1508
|
} else {
|
|
1477
1509
|
const t = `${CoreAIModuleName}/${AgentFlowStep}`;
|
|
1478
1510
|
try {
|
|
@@ -1486,11 +1518,11 @@ export async function saveFlowStepResult(
|
|
|
1486
1518
|
undefined,
|
|
1487
1519
|
env
|
|
1488
1520
|
);
|
|
1489
|
-
if (isInstanceOfType(inst, t)) return
|
|
1490
|
-
else return
|
|
1521
|
+
if (isInstanceOfType(inst, t)) return true;
|
|
1522
|
+
else return false;
|
|
1491
1523
|
} catch (reason: any) {
|
|
1492
1524
|
logger.error(`failed to save flow result for step ${step} - ${reason}`);
|
|
1493
|
-
return
|
|
1525
|
+
return false;
|
|
1494
1526
|
}
|
|
1495
1527
|
}
|
|
1496
1528
|
}
|
|
@@ -1528,10 +1560,10 @@ export async function loadFlowStepResults(chatId: string): Promise<Instance[]> {
|
|
|
1528
1560
|
}
|
|
1529
1561
|
}
|
|
1530
1562
|
|
|
1531
|
-
export async function
|
|
1563
|
+
export async function loadLocalAgentResult(
|
|
1532
1564
|
chatId: string,
|
|
1533
1565
|
step: string
|
|
1534
|
-
): Promise<
|
|
1566
|
+
): Promise<string | undefined> {
|
|
1535
1567
|
const fs = await getFileSystem();
|
|
1536
1568
|
const dirName = `${LocalFlowStepsRootDirName}/${chatId}`;
|
|
1537
1569
|
if (await fs.exists(dirName)) {
|
|
@@ -1539,10 +1571,7 @@ export async function loadLocalFlowStep(
|
|
|
1539
1571
|
for (let i = 0; i < fileNames.length; ++i) {
|
|
1540
1572
|
const fileName = fileNames[i];
|
|
1541
1573
|
if (fileName === step) {
|
|
1542
|
-
|
|
1543
|
-
JSON.parse(await fs.readFile(`${dirName}/${fileName}`))
|
|
1544
|
-
);
|
|
1545
|
-
return makeInstance(CoreAIModuleName, AgentFlowStep, attrs);
|
|
1574
|
+
return await fs.readFile(`${dirName}/${fileName}`);
|
|
1546
1575
|
}
|
|
1547
1576
|
}
|
|
1548
1577
|
return undefined;
|
|
@@ -1551,6 +1580,19 @@ export async function loadLocalFlowStep(
|
|
|
1551
1580
|
}
|
|
1552
1581
|
}
|
|
1553
1582
|
|
|
1583
|
+
export async function loadLocalFlowStep(
|
|
1584
|
+
chatId: string,
|
|
1585
|
+
step: string
|
|
1586
|
+
): Promise<Instance | undefined> {
|
|
1587
|
+
const contents = await loadLocalAgentResult(chatId, step);
|
|
1588
|
+
if (contents) {
|
|
1589
|
+
const attrs = objectToInstanceAttributes(JSON.parse(contents));
|
|
1590
|
+
return makeInstance(CoreAIModuleName, AgentFlowStep, attrs);
|
|
1591
|
+
} else {
|
|
1592
|
+
return undefined;
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1554
1596
|
export async function loadFlowStep(chatId: string, step: string): Promise<Instance | undefined> {
|
|
1555
1597
|
if (LocalAgentgFlow) {
|
|
1556
1598
|
return await loadLocalFlowStep(chatId, step);
|
|
@@ -1630,3 +1672,17 @@ export async function fetchAndCreateDocument(
|
|
|
1630
1672
|
throw new Error(`Failed to fetch document: ${title} from ${url}`);
|
|
1631
1673
|
}
|
|
1632
1674
|
}
|
|
1675
|
+
|
|
1676
|
+
export async function saveAgentResponse(
|
|
1677
|
+
fileName: string,
|
|
1678
|
+
response: string,
|
|
1679
|
+
env: Environment
|
|
1680
|
+
): Promise<string> {
|
|
1681
|
+
const chatId = env.getActiveChatId();
|
|
1682
|
+
if (chatId) {
|
|
1683
|
+
await saveFlowStepResultLocally(chatId, fileName, response);
|
|
1684
|
+
} else {
|
|
1685
|
+
logger.warn(`No chatId set, ${fileName} was not saved.`);
|
|
1686
|
+
}
|
|
1687
|
+
return response;
|
|
1688
|
+
}
|
|
@@ -749,5 +749,9 @@ export function migrationDowns(inst: Instance): string[] | undefined {
|
|
|
749
749
|
|
|
750
750
|
export async function doRawQuery(q: any): Promise<any> {
|
|
751
751
|
const qs = objectToQueryPattern(q);
|
|
752
|
-
|
|
752
|
+
const result = await parseAndEvaluateStatement(qs);
|
|
753
|
+
return {
|
|
754
|
+
query: qs,
|
|
755
|
+
result: result.map((res: any) => (res.attributes ? Object.fromEntries(res.attributes) : res)),
|
|
756
|
+
};
|
|
753
757
|
}
|