agentlang 0.10.1 → 0.10.3
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/README.md +7 -14
- package/out/api/http.d.ts +4 -0
- package/out/api/http.d.ts.map +1 -1
- package/out/api/http.js +307 -26
- package/out/api/http.js.map +1 -1
- package/out/cli/main.d.ts.map +1 -1
- package/out/cli/main.js +3 -0
- package/out/cli/main.js.map +1 -1
- package/out/extension/main.cjs +250 -250
- package/out/extension/main.cjs.map +2 -2
- package/out/language/agentlang-validator.d.ts.map +1 -1
- package/out/language/agentlang-validator.js +4 -0
- package/out/language/agentlang-validator.js.map +1 -1
- package/out/language/error-reporter.d.ts +53 -0
- package/out/language/error-reporter.d.ts.map +1 -0
- package/out/language/error-reporter.js +879 -0
- package/out/language/error-reporter.js.map +1 -0
- package/out/language/generated/ast.d.ts +77 -2
- package/out/language/generated/ast.d.ts.map +1 -1
- package/out/language/generated/ast.js +60 -0
- 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 +342 -206
- package/out/language/generated/grammar.js.map +1 -1
- package/out/language/main.cjs +901 -710
- package/out/language/main.cjs.map +3 -3
- package/out/language/parser.d.ts +4 -2
- package/out/language/parser.d.ts.map +1 -1
- package/out/language/parser.js +58 -99
- package/out/language/parser.js.map +1 -1
- package/out/language/syntax.d.ts +16 -0
- package/out/language/syntax.d.ts.map +1 -1
- package/out/language/syntax.js +66 -27
- package/out/language/syntax.js.map +1 -1
- package/out/runtime/api.d.ts +2 -0
- package/out/runtime/api.d.ts.map +1 -1
- package/out/runtime/api.js +25 -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/defs.d.ts +1 -0
- package/out/runtime/defs.d.ts.map +1 -1
- package/out/runtime/defs.js +2 -1
- package/out/runtime/defs.js.map +1 -1
- package/out/runtime/document-retriever.d.ts +24 -0
- package/out/runtime/document-retriever.d.ts.map +1 -0
- package/out/runtime/document-retriever.js +258 -0
- package/out/runtime/document-retriever.js.map +1 -0
- package/out/runtime/embeddings/chunker.d.ts +18 -0
- package/out/runtime/embeddings/chunker.d.ts.map +1 -1
- package/out/runtime/embeddings/chunker.js +47 -15
- package/out/runtime/embeddings/chunker.js.map +1 -1
- package/out/runtime/embeddings/openai.d.ts.map +1 -1
- package/out/runtime/embeddings/openai.js +22 -9
- package/out/runtime/embeddings/openai.js.map +1 -1
- package/out/runtime/embeddings/provider.d.ts +1 -0
- package/out/runtime/embeddings/provider.d.ts.map +1 -1
- package/out/runtime/embeddings/provider.js +20 -1
- package/out/runtime/embeddings/provider.js.map +1 -1
- 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/integration-client.d.ts +21 -0
- package/out/runtime/integration-client.d.ts.map +1 -0
- package/out/runtime/integration-client.js +112 -0
- package/out/runtime/integration-client.js.map +1 -0
- package/out/runtime/integrations.d.ts.map +1 -1
- package/out/runtime/integrations.js +20 -9
- package/out/runtime/integrations.js.map +1 -1
- package/out/runtime/interpreter.d.ts +10 -0
- package/out/runtime/interpreter.d.ts.map +1 -1
- package/out/runtime/interpreter.js +221 -22
- package/out/runtime/interpreter.js.map +1 -1
- package/out/runtime/loader.d.ts.map +1 -1
- package/out/runtime/loader.js +70 -7
- package/out/runtime/loader.js.map +1 -1
- package/out/runtime/logger.d.ts.map +1 -1
- package/out/runtime/logger.js +8 -1
- package/out/runtime/logger.js.map +1 -1
- package/out/runtime/module.d.ts +18 -0
- package/out/runtime/module.d.ts.map +1 -1
- package/out/runtime/module.js +91 -3
- package/out/runtime/module.js.map +1 -1
- package/out/runtime/modules/ai.d.ts +16 -5
- package/out/runtime/modules/ai.d.ts.map +1 -1
- package/out/runtime/modules/ai.js +286 -88
- 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 +7 -2
- package/out/runtime/resolvers/interface.d.ts.map +1 -1
- package/out/runtime/resolvers/interface.js +17 -3
- package/out/runtime/resolvers/interface.js.map +1 -1
- package/out/runtime/resolvers/sqldb/database.d.ts +2 -0
- package/out/runtime/resolvers/sqldb/database.d.ts.map +1 -1
- package/out/runtime/resolvers/sqldb/database.js +142 -126
- package/out/runtime/resolvers/sqldb/database.js.map +1 -1
- package/out/runtime/resolvers/sqldb/dbutil.d.ts.map +1 -1
- package/out/runtime/resolvers/sqldb/dbutil.js +25 -4
- package/out/runtime/resolvers/sqldb/dbutil.js.map +1 -1
- package/out/runtime/resolvers/sqldb/impl.d.ts +2 -1
- package/out/runtime/resolvers/sqldb/impl.d.ts.map +1 -1
- package/out/runtime/resolvers/sqldb/impl.js +24 -7
- package/out/runtime/resolvers/sqldb/impl.js.map +1 -1
- package/out/runtime/resolvers/vector/lancedb-store.d.ts +16 -0
- package/out/runtime/resolvers/vector/lancedb-store.d.ts.map +1 -0
- package/out/runtime/resolvers/vector/lancedb-store.js +159 -0
- package/out/runtime/resolvers/vector/lancedb-store.js.map +1 -0
- package/out/runtime/resolvers/vector/types.d.ts +32 -0
- package/out/runtime/resolvers/vector/types.d.ts.map +1 -0
- package/out/runtime/resolvers/vector/types.js +2 -0
- package/out/runtime/resolvers/vector/types.js.map +1 -0
- package/out/runtime/services/documentFetcher.d.ts.map +1 -1
- package/out/runtime/services/documentFetcher.js +21 -6
- package/out/runtime/services/documentFetcher.js.map +1 -1
- package/out/runtime/state.d.ts +19 -1
- package/out/runtime/state.d.ts.map +1 -1
- package/out/runtime/state.js +36 -1
- package/out/runtime/state.js.map +1 -1
- package/out/runtime/util.d.ts +3 -2
- package/out/runtime/util.d.ts.map +1 -1
- package/out/runtime/util.js +13 -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/package.json +22 -19
- package/src/api/http.ts +336 -38
- package/src/cli/main.ts +3 -0
- package/src/language/agentlang-validator.ts +3 -0
- package/src/language/agentlang.langium +6 -2
- package/src/language/error-reporter.ts +1028 -0
- package/src/language/generated/ast.ts +94 -1
- package/src/language/generated/grammar.ts +342 -206
- package/src/language/parser.ts +64 -101
- package/src/language/syntax.ts +79 -24
- package/src/runtime/api.ts +36 -0
- package/src/runtime/datefns.ts +112 -0
- package/src/runtime/defs.ts +2 -1
- package/src/runtime/document-retriever.ts +311 -0
- package/src/runtime/embeddings/chunker.ts +52 -14
- package/src/runtime/embeddings/openai.ts +27 -9
- package/src/runtime/embeddings/provider.ts +22 -1
- package/src/runtime/exec-graph.ts +23 -2
- package/src/runtime/integration-client.ts +158 -0
- package/src/runtime/integrations.ts +20 -11
- package/src/runtime/interpreter.ts +221 -15
- package/src/runtime/loader.ts +83 -5
- package/src/runtime/logger.ts +12 -1
- package/src/runtime/module.ts +104 -3
- package/src/runtime/modules/ai.ts +341 -107
- 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 +23 -3
- package/src/runtime/resolvers/sqldb/database.ts +158 -130
- package/src/runtime/resolvers/sqldb/dbutil.ts +28 -6
- package/src/runtime/resolvers/sqldb/impl.ts +25 -7
- package/src/runtime/resolvers/vector/lancedb-store.ts +187 -0
- package/src/runtime/resolvers/vector/types.ts +39 -0
- package/src/runtime/services/documentFetcher.ts +21 -6
- package/src/runtime/state.ts +40 -1
- package/src/runtime/util.ts +19 -2
- package/src/syntaxes/agentlang.monarch.ts +1 -1
- package/src/test-harness.ts +423 -0
package/src/language/parser.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createAgentlangServices } from '../language/agentlang-module.js';
|
|
2
2
|
import { AstNode, EmptyFileSystem, LangiumCoreServices, LangiumDocument, URI } from 'langium';
|
|
3
|
+
import { getFormattedErrors, collectErrors, formatErrors } from './error-reporter.js';
|
|
3
4
|
import {
|
|
4
5
|
CrudMap,
|
|
5
6
|
Delete,
|
|
@@ -19,12 +20,14 @@ import {
|
|
|
19
20
|
isPrimExpr,
|
|
20
21
|
isWorkflowDefinition,
|
|
21
22
|
JoinSpec,
|
|
23
|
+
LimitClause,
|
|
22
24
|
Literal,
|
|
23
25
|
MapEntry,
|
|
24
26
|
MapLiteral,
|
|
25
27
|
ModuleDefinition,
|
|
26
28
|
NegExpr,
|
|
27
29
|
NotExpr,
|
|
30
|
+
OffsetClause,
|
|
28
31
|
OrderByClause,
|
|
29
32
|
Pattern,
|
|
30
33
|
PrimExpr,
|
|
@@ -36,9 +39,16 @@ import {
|
|
|
36
39
|
SetAttribute,
|
|
37
40
|
Statement,
|
|
38
41
|
WhereSpec,
|
|
42
|
+
WhereSpecClause,
|
|
39
43
|
WorkflowDefinition,
|
|
40
44
|
} from './generated/ast.js';
|
|
41
|
-
import {
|
|
45
|
+
import {
|
|
46
|
+
firstAliasSpec,
|
|
47
|
+
firstCatchSpec,
|
|
48
|
+
firstEmptySpec,
|
|
49
|
+
isString,
|
|
50
|
+
QuerySuffix,
|
|
51
|
+
} from '../runtime/util.js';
|
|
42
52
|
import {
|
|
43
53
|
BasePattern,
|
|
44
54
|
CrudPattern,
|
|
@@ -54,6 +64,7 @@ import {
|
|
|
54
64
|
NegExpressionPattern,
|
|
55
65
|
NotExpressionPattern,
|
|
56
66
|
ReturnPattern,
|
|
67
|
+
WhereSpecClausePattern,
|
|
57
68
|
} from './syntax.js';
|
|
58
69
|
|
|
59
70
|
let nextDocumentId = 1;
|
|
@@ -116,113 +127,25 @@ export async function parseWorkflow(workflowDef: string): Promise<WorkflowDefini
|
|
|
116
127
|
}
|
|
117
128
|
}
|
|
118
129
|
|
|
119
|
-
const ErrorIndicator = '<-- ERROR';
|
|
120
|
-
|
|
121
130
|
export function maybeGetValidationErrors(
|
|
122
131
|
document: LangiumDocument,
|
|
123
|
-
|
|
124
|
-
): string
|
|
125
|
-
if (lines === undefined) {
|
|
126
|
-
lines = document.textDocument.getText().split('\n');
|
|
127
|
-
}
|
|
132
|
+
_lines?: string[]
|
|
133
|
+
): string | undefined {
|
|
128
134
|
const validationErrors = (document.diagnostics ?? []).filter(e => e.severity === 1);
|
|
135
|
+
if (validationErrors.length === 0) return undefined;
|
|
129
136
|
|
|
130
|
-
|
|
131
|
-
const
|
|
132
|
-
if (
|
|
133
|
-
for (const validationError of validationErrors) {
|
|
134
|
-
if (
|
|
135
|
-
!sls.has(validationError.range.start.line) &&
|
|
136
|
-
!scs.has(validationError.range.start.character)
|
|
137
|
-
) {
|
|
138
|
-
const t = document.textDocument.getText(validationError.range);
|
|
139
|
-
const s = `(${validationError.range.start.line + 1}:${validationError.range.start.character + 1}) unexpected token(s) '${t}'`;
|
|
140
|
-
const ln = lines[validationError.range.start.line];
|
|
141
|
-
if (ln.indexOf(ErrorIndicator) > 0) {
|
|
142
|
-
lines[validationError.range.start.line] = `${ln}, ${s}`;
|
|
143
|
-
} else {
|
|
144
|
-
lines[validationError.range.start.line] = `${ln} ${ErrorIndicator} ${s}`;
|
|
145
|
-
}
|
|
146
|
-
sls.add(validationError.range.start.line);
|
|
147
|
-
scs.add(validationError.range.start.character);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
return trimErrorLines(lines);
|
|
151
|
-
} else {
|
|
152
|
-
return undefined;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
137
|
+
// Collect only validation errors (not lexer/parser)
|
|
138
|
+
const errors = collectErrors(document).filter(e => e.category === 'VALIDATION ERROR');
|
|
139
|
+
if (errors.length === 0) return undefined;
|
|
155
140
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
for (let i = 0; i < lines.length; ++i) {
|
|
159
|
-
if (lines[i].indexOf(ErrorIndicator) > 0) {
|
|
160
|
-
startidx = i;
|
|
161
|
-
break;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
let endidx = startidx;
|
|
165
|
-
for (let i = startidx + 1; i < lines.length; ++i) {
|
|
166
|
-
if (lines[i].indexOf(ErrorIndicator) > 0) {
|
|
167
|
-
endidx = i;
|
|
168
|
-
break;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
if (startidx > 0) {
|
|
172
|
-
--startidx;
|
|
173
|
-
}
|
|
174
|
-
if (endidx != lines.length) {
|
|
175
|
-
++endidx;
|
|
176
|
-
}
|
|
177
|
-
return lines.slice(startidx, endidx);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
function trimErrorMessage(s: string): string {
|
|
181
|
-
const start = s.indexOf('Expecting:');
|
|
182
|
-
if (start >= 0) {
|
|
183
|
-
const end = s.indexOf('but found:');
|
|
184
|
-
if (end > 0) {
|
|
185
|
-
return `Expecting a valid token sequence, ${s.substring(end)}`;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
return s;
|
|
141
|
+
const source = document.textDocument.getText();
|
|
142
|
+
return formatErrors(errors, source);
|
|
189
143
|
}
|
|
190
144
|
|
|
191
145
|
export function maybeRaiseParserErrors(document: LangiumDocument) {
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
const errLines = new Set<number>();
|
|
196
|
-
if (document.parseResult.lexerErrors.length > 0) {
|
|
197
|
-
document.parseResult.lexerErrors.forEach((err: any) => {
|
|
198
|
-
if (!errLines.has(err.line)) {
|
|
199
|
-
const errMsg = trimErrorMessage(err.message);
|
|
200
|
-
const s = `${ErrorIndicator} (${err.line}:${err.column}) ${errMsg}`;
|
|
201
|
-
lines[err.line - 1] = `${lines[err.line - 1]} ${s}`;
|
|
202
|
-
errLines.add(err.line);
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
hasErrors = true;
|
|
206
|
-
}
|
|
207
|
-
if (document.parseResult.parserErrors.length > 0) {
|
|
208
|
-
document.parseResult.parserErrors.forEach((err: any) => {
|
|
209
|
-
const errMsg = trimErrorMessage(err.message);
|
|
210
|
-
if (err.token.startLine && err.token.endLine) {
|
|
211
|
-
if (!errLines.has(err.token.startLine)) {
|
|
212
|
-
const s = `${ErrorIndicator} (${err.token.startLine}:${err.token.startColumn}) ${errMsg}`;
|
|
213
|
-
lines[err.token.endLine - 1] = `${lines[err.token.endLine - 1]} ${s}`;
|
|
214
|
-
lines.join('\n');
|
|
215
|
-
errLines.add(err.token.startLine);
|
|
216
|
-
}
|
|
217
|
-
} else {
|
|
218
|
-
lines.push(`ERROR: ${errMsg}`);
|
|
219
|
-
}
|
|
220
|
-
});
|
|
221
|
-
hasErrors = true;
|
|
222
|
-
}
|
|
223
|
-
const errs = maybeGetValidationErrors(document, lines);
|
|
224
|
-
if (hasErrors || errs !== undefined) {
|
|
225
|
-
throw new Error(lines.join('\n'));
|
|
146
|
+
const formatted = getFormattedErrors(document);
|
|
147
|
+
if (formatted) {
|
|
148
|
+
throw new Error('\n' + formatted);
|
|
226
149
|
}
|
|
227
150
|
}
|
|
228
151
|
|
|
@@ -262,6 +185,10 @@ function introspectStatement(stmt: Statement): BasePattern {
|
|
|
262
185
|
r.addHandler(h.except, introspectStatement(h.stmt));
|
|
263
186
|
});
|
|
264
187
|
}
|
|
188
|
+
const emptySpec = firstEmptySpec(stmt);
|
|
189
|
+
if (emptySpec) {
|
|
190
|
+
r.setEmptyHandler(introspectStatement(emptySpec.stmt));
|
|
191
|
+
}
|
|
265
192
|
return r;
|
|
266
193
|
}
|
|
267
194
|
|
|
@@ -299,6 +226,14 @@ function introspectPattern(pat: Pattern): BasePattern {
|
|
|
299
226
|
function introspectInto(intoSpec: SelectIntoSpec, p: CrudPattern): CrudPattern {
|
|
300
227
|
intoSpec.entries.forEach((se: SelectIntoEntry) => {
|
|
301
228
|
if (se.attribute) p.addInto(se.alias, se.attribute);
|
|
229
|
+
else if (se.aggregate) {
|
|
230
|
+
const args = se.aggregate.args
|
|
231
|
+
.map((s: string) => {
|
|
232
|
+
return s;
|
|
233
|
+
})
|
|
234
|
+
.join(', ');
|
|
235
|
+
p.addInto(se.alias, `@${se.aggregate?.name}(${args})`);
|
|
236
|
+
}
|
|
302
237
|
});
|
|
303
238
|
return p;
|
|
304
239
|
}
|
|
@@ -379,6 +314,24 @@ function introspectQueryPattern(crudMap: CrudMap): CrudPattern {
|
|
|
379
314
|
};
|
|
380
315
|
cp.joins.push(jp);
|
|
381
316
|
});
|
|
317
|
+
if (opts.where?.clauses) {
|
|
318
|
+
cp.where = new Array<WhereSpecClausePattern>();
|
|
319
|
+
opts.where.clauses.forEach((wc: WhereSpecClause) => {
|
|
320
|
+
cp.where?.push({ lhs: wc.lhs, op: wc.op || '=', rhs: wc.rhs.$cstNode?.text || '' });
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
if (opts.groupByClause) {
|
|
324
|
+
cp.groupBy = opts.groupByClause.colNames;
|
|
325
|
+
}
|
|
326
|
+
if (opts.orderByClause) {
|
|
327
|
+
cp.orderBy = opts.orderByClause.colNames;
|
|
328
|
+
}
|
|
329
|
+
if (opts.limitClause) {
|
|
330
|
+
cp.limit = opts.limitClause.value;
|
|
331
|
+
}
|
|
332
|
+
if (opts.offsetClause) {
|
|
333
|
+
cp.offset = opts.offsetClause.value;
|
|
334
|
+
}
|
|
382
335
|
cp.isCreate = false;
|
|
383
336
|
cp.isQueryUpdate = false;
|
|
384
337
|
cp.isQuery = true;
|
|
@@ -393,6 +346,8 @@ export type ExtractedQueryOptions = {
|
|
|
393
346
|
where: WhereSpec | undefined;
|
|
394
347
|
groupByClause: GroupByClause | undefined;
|
|
395
348
|
orderByClause: OrderByClause | undefined;
|
|
349
|
+
limitClause: LimitClause | undefined;
|
|
350
|
+
offsetClause: OffsetClause | undefined;
|
|
396
351
|
upsert: '@upsert' | undefined;
|
|
397
352
|
distinct: '@distinct' | undefined;
|
|
398
353
|
};
|
|
@@ -404,6 +359,8 @@ export function extractQueryOptions(crudMap: CrudMap): ExtractedQueryOptions {
|
|
|
404
359
|
where: undefined,
|
|
405
360
|
groupByClause: undefined,
|
|
406
361
|
orderByClause: undefined,
|
|
362
|
+
limitClause: undefined,
|
|
363
|
+
offsetClause: undefined,
|
|
407
364
|
upsert: undefined,
|
|
408
365
|
distinct: undefined,
|
|
409
366
|
};
|
|
@@ -421,6 +378,10 @@ export function extractQueryOptions(crudMap: CrudMap): ExtractedQueryOptions {
|
|
|
421
378
|
r.groupByClause = qo.groupByClause;
|
|
422
379
|
} else if (qo.orderByClause) {
|
|
423
380
|
r.orderByClause = qo.orderByClause;
|
|
381
|
+
} else if (qo.limitClause) {
|
|
382
|
+
r.limitClause = qo.limitClause;
|
|
383
|
+
} else if (qo.offsetClause) {
|
|
384
|
+
r.offsetClause = qo.offsetClause;
|
|
424
385
|
} else if (qo.upsert) {
|
|
425
386
|
r.upsert = qo.upsert;
|
|
426
387
|
} else if (qo.distinct) {
|
|
@@ -564,7 +525,7 @@ export async function introspectCase(caseStr: string): Promise<CasePattern> {
|
|
|
564
525
|
|
|
565
526
|
export function canParse(s: string): boolean {
|
|
566
527
|
const ts = s.trim();
|
|
567
|
-
if (ts) {
|
|
528
|
+
if (ts && ts.includes('{')) {
|
|
568
529
|
const contents = ts.substring(1, ts.length - 1).trim();
|
|
569
530
|
return contents.length > 0;
|
|
570
531
|
}
|
|
@@ -582,6 +543,8 @@ export function objectToQueryPattern(obj: any): string {
|
|
|
582
543
|
});
|
|
583
544
|
} else if (k === '@groupBy' || k === '@orderBy') {
|
|
584
545
|
strs.push(`${k} ( ${xs.join(', ')} )`);
|
|
546
|
+
} else if (k === '@limit' || k === '@offset') {
|
|
547
|
+
strs.push(`${k}(${xs})`);
|
|
585
548
|
} else {
|
|
586
549
|
strs.push(`${k} ${objectToQuerySpecPattern(xs, true)}`);
|
|
587
550
|
}
|
package/src/language/syntax.ts
CHANGED
|
@@ -15,6 +15,7 @@ export class BasePattern {
|
|
|
15
15
|
alias: string | undefined;
|
|
16
16
|
aliases: string[] | undefined;
|
|
17
17
|
handlers: Map<string, BasePattern> | undefined;
|
|
18
|
+
emptyHandler: BasePattern | undefined;
|
|
18
19
|
|
|
19
20
|
setAlias(alias: string) {
|
|
20
21
|
this.alias = alias;
|
|
@@ -44,6 +45,11 @@ export class BasePattern {
|
|
|
44
45
|
this.handlers.set(k, handler);
|
|
45
46
|
}
|
|
46
47
|
|
|
48
|
+
setEmptyHandler(handler: BasePattern) {
|
|
49
|
+
this.emptyHandler = handler;
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
|
|
47
53
|
private aliasesAsString(): string | undefined {
|
|
48
54
|
if (this.alias) {
|
|
49
55
|
return ` @as ${this.alias}`;
|
|
@@ -54,24 +60,30 @@ export class BasePattern {
|
|
|
54
60
|
}
|
|
55
61
|
}
|
|
56
62
|
|
|
63
|
+
private emptyHandlerAsString(): string | undefined {
|
|
64
|
+
if (this.emptyHandler) {
|
|
65
|
+
return ` @empty ${this.emptyHandler.toString()}`;
|
|
66
|
+
}
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
|
|
57
70
|
private handlersAsString(): string | undefined {
|
|
58
|
-
if (this.handlers) {
|
|
59
|
-
let s = '{';
|
|
71
|
+
if (this.handlers && this.handlers.size > 0) {
|
|
72
|
+
let s = ' @catch {';
|
|
60
73
|
this.handlers.forEach((handler: BasePattern, k: string) => {
|
|
61
|
-
s = `${s}
|
|
74
|
+
s = `${s}${k} ${handler.toString()} `;
|
|
62
75
|
});
|
|
63
|
-
return s + '}';
|
|
64
|
-
} else {
|
|
65
|
-
return undefined;
|
|
76
|
+
return s.trimEnd() + '}';
|
|
66
77
|
}
|
|
78
|
+
return undefined;
|
|
67
79
|
}
|
|
80
|
+
|
|
68
81
|
hintsAsString(): string {
|
|
69
|
-
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
return `${a}\n${h}`;
|
|
82
|
+
// Order matters: @as, then @catch, then @empty (must be last because it's greedy in the grammar)
|
|
83
|
+
const a = this.aliasesAsString() ?? '';
|
|
84
|
+
const h = this.handlersAsString() ?? '';
|
|
85
|
+
const e = this.emptyHandlerAsString() ?? '';
|
|
86
|
+
return `${a}${h}${e}`;
|
|
75
87
|
}
|
|
76
88
|
|
|
77
89
|
toString(): string {
|
|
@@ -386,12 +398,23 @@ function joinPatternToString(jp: JoinPattern): string {
|
|
|
386
398
|
return `${jp.type} ${jp.targetEntity} {${jp.conditionLhs}${opr} ${jp.conditionRhs}}`;
|
|
387
399
|
}
|
|
388
400
|
|
|
401
|
+
export type WhereSpecClausePattern = {
|
|
402
|
+
lhs: string;
|
|
403
|
+
op: string;
|
|
404
|
+
rhs: string;
|
|
405
|
+
};
|
|
406
|
+
|
|
389
407
|
export class CrudPattern extends BasePattern {
|
|
390
408
|
recordName: string;
|
|
391
409
|
attributes: Array<AttributePattern>;
|
|
392
410
|
relationships: Map<string, CrudPattern[] | CrudPattern> | undefined;
|
|
393
411
|
joins: JoinPattern[];
|
|
394
412
|
into: Map<string, string> | undefined;
|
|
413
|
+
where: WhereSpecClausePattern[] | undefined;
|
|
414
|
+
groupBy: string[] | undefined;
|
|
415
|
+
orderBy: string[] | undefined;
|
|
416
|
+
limit: number | undefined;
|
|
417
|
+
offset: number | undefined;
|
|
395
418
|
isQuery: boolean = false;
|
|
396
419
|
isQueryUpdate: boolean = false;
|
|
397
420
|
isCreate: boolean = false;
|
|
@@ -521,15 +544,29 @@ export class CrudPattern extends BasePattern {
|
|
|
521
544
|
return escapeQueryName(this.recordName);
|
|
522
545
|
}
|
|
523
546
|
|
|
524
|
-
private intoAsString(): string
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
547
|
+
private intoAsString(): string {
|
|
548
|
+
const ss = new Array<string>();
|
|
549
|
+
this.into?.forEach((attr: string, alias: string) => {
|
|
550
|
+
ss.push(`${alias} ${attr}`);
|
|
551
|
+
});
|
|
552
|
+
return `@into { ${ss.join(',\n')} }`;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
private whereAsString(): string {
|
|
556
|
+
const ss = new Array<string>();
|
|
557
|
+
this.where?.forEach((wc: WhereSpecClausePattern) => {
|
|
558
|
+
if (wc.op == '=') ss.push(`${wc.lhs} ${wc.rhs}`);
|
|
559
|
+
else ss.push(`${wc.lhs} ${wc.op} ${wc.rhs}`);
|
|
560
|
+
});
|
|
561
|
+
return `@where {${ss.join(`,\n`)}}`;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
private groupByAsString(): string {
|
|
565
|
+
return `@groupBy(${this.groupBy?.join(', ')})`;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
private orderByAsString(): string {
|
|
569
|
+
return `@orderBy(${this.orderBy?.join(', ')})`;
|
|
533
570
|
}
|
|
534
571
|
|
|
535
572
|
override toString(): string {
|
|
@@ -542,10 +579,28 @@ export class CrudPattern extends BasePattern {
|
|
|
542
579
|
const js = this.joins.map(joinPatternToString);
|
|
543
580
|
s = s.concat(`,\n${js.join(',\n')}`);
|
|
544
581
|
}
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
582
|
+
if (this.into) {
|
|
583
|
+
const ins = this.intoAsString();
|
|
584
|
+
if (ins) {
|
|
585
|
+
s = s.concat(`,\n${ins}`);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
if (this.where) {
|
|
589
|
+
s = s.concat(`,\n${this.whereAsString()}`);
|
|
590
|
+
}
|
|
591
|
+
if (this.groupBy) {
|
|
592
|
+
s = s.concat(`,\n${this.groupByAsString()}`);
|
|
548
593
|
}
|
|
594
|
+
if (this.orderBy) {
|
|
595
|
+
s = s.concat(`,\n${this.orderByAsString()}`);
|
|
596
|
+
}
|
|
597
|
+
if (this.limit !== undefined) {
|
|
598
|
+
s = s.concat(`,\n@limit(${this.limit})`);
|
|
599
|
+
}
|
|
600
|
+
if (this.offset !== undefined) {
|
|
601
|
+
s = s.concat(`,\n@offset(${this.offset})`);
|
|
602
|
+
}
|
|
603
|
+
|
|
549
604
|
return s.concat('}', this.hintsAsString());
|
|
550
605
|
}
|
|
551
606
|
}
|
package/src/runtime/api.ts
CHANGED
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
import { fetchConfig as al_fetchConfig } from './interpreter.js';
|
|
2
|
+
import { defaultDataSource } from './resolvers/sqldb/database.js';
|
|
2
3
|
import {
|
|
3
4
|
makeInstance as al_makeInstance,
|
|
4
5
|
isInstanceOfType as al_isInstanceOfType,
|
|
5
6
|
} from './module.js';
|
|
6
7
|
import { getLocalEnv as al_getLocalEnv, setLocalEnv as al_setLocalEnv } from './auth/defs.js';
|
|
7
8
|
import { now } from './util.js';
|
|
9
|
+
import { initDateFns } from './datefns.js';
|
|
10
|
+
import {
|
|
11
|
+
integrationAuthFetch as al_authFetch,
|
|
12
|
+
getIntegrationAuthHeaders as al_getAuthHeaders,
|
|
13
|
+
getOAuthAuthorizeUrl as al_getOAuthAuthorizeUrl,
|
|
14
|
+
exchangeOAuthCode as al_exchangeOAuthCode,
|
|
15
|
+
getIntegrationAccessToken as al_getAccessToken,
|
|
16
|
+
} from './integration-client.js';
|
|
8
17
|
|
|
9
18
|
declare global {
|
|
10
19
|
var agentlang: any | undefined;
|
|
20
|
+
var dateFns: ReturnType<typeof initDateFns> | undefined;
|
|
11
21
|
function getLocalEnv(k: string, defaultValue?: string): string | undefined;
|
|
12
22
|
function setLocalEnv(k: string, v: string): string;
|
|
13
23
|
function uuid(): string;
|
|
@@ -32,6 +42,32 @@ export function initGlobalApi() {
|
|
|
32
42
|
globalThis.getLocalEnv = al_getLocalEnv;
|
|
33
43
|
globalThis.setLocalEnv = al_setLocalEnv;
|
|
34
44
|
|
|
45
|
+
// Expose date-fns functions globally as dateFns.*
|
|
46
|
+
globalThis.dateFns = initDateFns();
|
|
47
|
+
|
|
48
|
+
// Expose credential auth helpers globally
|
|
49
|
+
globalThis.agentlang.authFetch = al_authFetch;
|
|
50
|
+
globalThis.agentlang.getAuthHeaders = al_getAuthHeaders;
|
|
51
|
+
|
|
52
|
+
// Expose OAuth consent flow helpers globally
|
|
53
|
+
globalThis.agentlang.getOAuthAuthorizeUrl = al_getOAuthAuthorizeUrl;
|
|
54
|
+
globalThis.agentlang.exchangeOAuthCode = al_exchangeOAuthCode;
|
|
55
|
+
globalThis.agentlang.getAccessToken = al_getAccessToken;
|
|
56
|
+
|
|
57
|
+
// Expose raw SQL query for resolvers that need direct database access (e.g. pgvector)
|
|
58
|
+
globalThis.agentlang.rawQuery = async (sql: string, params?: any[]) => {
|
|
59
|
+
if (!defaultDataSource || !defaultDataSource.isInitialized) {
|
|
60
|
+
throw new Error('Database not initialized');
|
|
61
|
+
}
|
|
62
|
+
return defaultDataSource.query(sql, params);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// Expose database type detection for resolvers
|
|
66
|
+
globalThis.agentlang.getDbType = () => {
|
|
67
|
+
if (!defaultDataSource || !defaultDataSource.isInitialized) return 'unknown';
|
|
68
|
+
return defaultDataSource.options.type;
|
|
69
|
+
};
|
|
70
|
+
|
|
35
71
|
ApiInited = true;
|
|
36
72
|
}
|
|
37
73
|
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import {
|
|
2
|
+
addDays as _addDays,
|
|
3
|
+
addWeeks as _addWeeks,
|
|
4
|
+
addMonths as _addMonths,
|
|
5
|
+
startOfWeek as _startOfWeek,
|
|
6
|
+
endOfWeek as _endOfWeek,
|
|
7
|
+
startOfMonth as _startOfMonth,
|
|
8
|
+
endOfMonth as _endOfMonth,
|
|
9
|
+
getISOWeek,
|
|
10
|
+
format,
|
|
11
|
+
parse,
|
|
12
|
+
differenceInDays,
|
|
13
|
+
differenceInWeeks,
|
|
14
|
+
} from 'date-fns';
|
|
15
|
+
import { formatInTimeZone } from 'date-fns-tz';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Parse a date string as local midnight to avoid timezone day-shift issues.
|
|
19
|
+
* date-fns operates in local time, so we must parse date-only strings
|
|
20
|
+
* (YYYY-MM-DD) as local midnight rather than UTC midnight.
|
|
21
|
+
*/
|
|
22
|
+
function toDate(dateStr: string): Date {
|
|
23
|
+
if (!dateStr.includes('T')) {
|
|
24
|
+
const [y, m, d] = dateStr.split('-').map(Number);
|
|
25
|
+
return new Date(y, m - 1, d);
|
|
26
|
+
}
|
|
27
|
+
return new Date(dateStr);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function toDateStr(d: Date): string {
|
|
31
|
+
return format(d, 'yyyy-MM-dd');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function addDays(dateStr: string, days: number): string {
|
|
35
|
+
return toDateStr(_addDays(toDate(dateStr), days));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function addWeeks(dateStr: string, weeks: number): string {
|
|
39
|
+
return toDateStr(_addWeeks(toDate(dateStr), weeks));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function addMonths(dateStr: string, months: number): string {
|
|
43
|
+
return toDateStr(_addMonths(toDate(dateStr), months));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function startOfWeek(dateStr: string): string {
|
|
47
|
+
return toDateStr(_startOfWeek(toDate(dateStr), { weekStartsOn: 1 }));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function endOfWeek(dateStr: string): string {
|
|
51
|
+
return toDateStr(_endOfWeek(toDate(dateStr), { weekStartsOn: 1 }));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function startOfMonth(dateStr: string): string {
|
|
55
|
+
return toDateStr(_startOfMonth(toDate(dateStr)));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function endOfMonth(dateStr: string): string {
|
|
59
|
+
return toDateStr(_endOfMonth(toDate(dateStr)));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function getWeek(dateStr: string): number {
|
|
63
|
+
return getISOWeek(toDate(dateStr));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function dayName(dateStr: string): string {
|
|
67
|
+
return format(toDate(dateStr), 'EEEE');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function formatDate(dateStr: string, fmt: string): string {
|
|
71
|
+
return format(toDate(dateStr), fmt);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function parseDate(str: string, fmt: string): string {
|
|
75
|
+
return toDateStr(parse(str, fmt, new Date()));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function diffInDays(dateStr1: string, dateStr2: string): number {
|
|
79
|
+
return differenceInDays(toDate(dateStr1), toDate(dateStr2));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function diffInWeeks(dateStr1: string, dateStr2: string): number {
|
|
83
|
+
return differenceInWeeks(toDate(dateStr1), toDate(dateStr2));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function today(): string {
|
|
87
|
+
return toDateStr(new Date());
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function toTimezone(dateStr: string, tz: string): string {
|
|
91
|
+
return formatInTimeZone(new Date(dateStr), tz, 'yyyy-MM-dd HH:mm:ssXXX');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function initDateFns() {
|
|
95
|
+
return {
|
|
96
|
+
addDays,
|
|
97
|
+
addWeeks,
|
|
98
|
+
addMonths,
|
|
99
|
+
startOfWeek,
|
|
100
|
+
endOfWeek,
|
|
101
|
+
startOfMonth,
|
|
102
|
+
endOfMonth,
|
|
103
|
+
getWeek,
|
|
104
|
+
dayName,
|
|
105
|
+
formatDate,
|
|
106
|
+
parseDate,
|
|
107
|
+
diffInDays,
|
|
108
|
+
diffInWeeks,
|
|
109
|
+
today,
|
|
110
|
+
toTimezone,
|
|
111
|
+
};
|
|
112
|
+
}
|
package/src/runtime/defs.ts
CHANGED
|
@@ -4,7 +4,8 @@ export const PathAttributeName: string = '__path__';
|
|
|
4
4
|
export const PathAttributeNameQuery: string = '__path__?';
|
|
5
5
|
export const ParentAttributeName: string = '__parent__';
|
|
6
6
|
export const DeletedFlagAttributeName: string = '__is_deleted__';
|
|
7
|
-
export const
|
|
7
|
+
export const AgentIdAttributeName: string = 'agentId';
|
|
8
|
+
export const TenantAttributeName: string = 'agentId';
|
|
8
9
|
|
|
9
10
|
export function isPathAttribute(n: string): boolean {
|
|
10
11
|
return n.startsWith(PathAttributeName);
|