agentlang 0.10.1 → 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 +27 -2
- package/out/language/generated/ast.d.ts.map +1 -1
- package/out/language/generated/ast.js +20 -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 +246 -206
- package/out/language/generated/grammar.js.map +1 -1
- package/out/language/main.cjs +263 -206
- package/out/language/main.cjs.map +2 -2
- package/out/language/parser.d.ts.map +1 -1
- package/out/language/parser.js +28 -2
- 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/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 +71 -7
- 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 +7 -3
- package/out/runtime/modules/ai.d.ts.map +1 -1
- package/out/runtime/modules/ai.js +67 -21
- 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/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 +4 -1
- package/src/api/http.ts +138 -0
- package/src/language/agentlang.langium +3 -1
- package/src/language/generated/ast.ts +32 -1
- package/src/language/generated/grammar.ts +246 -206
- package/src/language/parser.ts +33 -1
- package/src/language/syntax.ts +71 -24
- 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 +82 -6
- package/src/runtime/module.ts +26 -0
- package/src/runtime/modules/ai.ts +78 -31
- 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/util.ts +19 -2
- package/src/syntaxes/agentlang.monarch.ts +1 -1
- package/src/test-harness.ts +423 -0
package/src/api/http.ts
CHANGED
|
@@ -58,6 +58,8 @@ import {
|
|
|
58
58
|
createFileRecord,
|
|
59
59
|
deleteFileRecord,
|
|
60
60
|
} from '../runtime/modules/files.js';
|
|
61
|
+
import * as XLSX from 'xlsx';
|
|
62
|
+
import { objectToQueryPattern } from '../language/parser.js';
|
|
61
63
|
|
|
62
64
|
export async function startServer(
|
|
63
65
|
appSpec: ApplicationSpec,
|
|
@@ -197,6 +199,14 @@ export async function startServer(
|
|
|
197
199
|
handleMetaGet(req, res);
|
|
198
200
|
});
|
|
199
201
|
|
|
202
|
+
app.post('/agentlang/QueryAsCsv', (req: Request, res: Response) => {
|
|
203
|
+
handleQueryAsCsvPost(req, res);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
app.post('/agentlang/QueryAsXlsx', (req: Request, res: Response) => {
|
|
207
|
+
handleQueryAsXlsxPost(req, res);
|
|
208
|
+
});
|
|
209
|
+
|
|
200
210
|
if (isNodeEnv && upload && uploadDir) {
|
|
201
211
|
app.post('/uploadFile', upload.single('file'), (req: Request, res: Response) => {
|
|
202
212
|
handleFileUpload(req, res, config);
|
|
@@ -730,6 +740,69 @@ function normalizedResult(r: Result): Result {
|
|
|
730
740
|
}
|
|
731
741
|
}
|
|
732
742
|
|
|
743
|
+
/**
|
|
744
|
+
* Converts eval result to an array of flat row objects for CSV/XLSX.
|
|
745
|
+
* Handles:
|
|
746
|
+
* - [{ "EntityName": { "attr": "attrval" } }, ...] -> one row per item, columns = Entity + attrs
|
|
747
|
+
* - [{ "attr": "attrval" }, ...] -> one row per item, columns = attrs
|
|
748
|
+
* - [[ { "EntityName": { ... } }, ... ]] -> unwrap single outer array, then one row per inner item
|
|
749
|
+
*/
|
|
750
|
+
function evalResultToRows(data: Result): { [key: string]: unknown }[] {
|
|
751
|
+
let items: Result[];
|
|
752
|
+
if (Array.isArray(data) && data.length === 1 && Array.isArray(data[0])) {
|
|
753
|
+
items = data[0] as Result[];
|
|
754
|
+
} else {
|
|
755
|
+
items = Array.isArray(data) ? (data as Result[]) : [data];
|
|
756
|
+
}
|
|
757
|
+
return items.map((item: Result) => {
|
|
758
|
+
if (item === null || typeof item !== 'object') {
|
|
759
|
+
return { value: item };
|
|
760
|
+
}
|
|
761
|
+
if (Array.isArray(item)) {
|
|
762
|
+
return { value: item };
|
|
763
|
+
}
|
|
764
|
+
const obj = item as { [key: string]: unknown };
|
|
765
|
+
const keys = Object.keys(obj);
|
|
766
|
+
if (keys.length === 1) {
|
|
767
|
+
const [k] = keys;
|
|
768
|
+
const v = obj[k];
|
|
769
|
+
if (
|
|
770
|
+
v !== null &&
|
|
771
|
+
typeof v === 'object' &&
|
|
772
|
+
!Array.isArray(v) &&
|
|
773
|
+
Object.prototype.toString.call(v) === '[object Object]'
|
|
774
|
+
) {
|
|
775
|
+
return { ...(v as { [key: string]: unknown }) };
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
return { ...obj };
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
/**
|
|
783
|
+
* Ensures cell value is stringifiable for CSV/XLSX (nested objects/arrays become JSON string).
|
|
784
|
+
*/
|
|
785
|
+
function cellValue(val: unknown): string | number | boolean | null {
|
|
786
|
+
if (val === null || val === undefined) return '';
|
|
787
|
+
if (typeof val === 'object') return JSON.stringify(val);
|
|
788
|
+
return val as string | number | boolean;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
/**
|
|
792
|
+
* Parses column names from the first instance and returns an array-of-arrays
|
|
793
|
+
* for the sheet: first row = column names, following rows = data. This ensures
|
|
794
|
+
* CSV/XLSX output has proper headers (col1, col2, ...) not 0, 1, 2, ...
|
|
795
|
+
*/
|
|
796
|
+
function rowsToSheetAoa(
|
|
797
|
+
rows: { [key: string]: unknown }[]
|
|
798
|
+
): (string | number | boolean | null)[][] {
|
|
799
|
+
if (rows.length === 0) return [];
|
|
800
|
+
const columns = Object.keys(rows[0] as object);
|
|
801
|
+
const headerRow = columns;
|
|
802
|
+
const dataRows = rows.map(row => columns.map(col => cellValue(row[col])));
|
|
803
|
+
return [headerRow, ...dataRows];
|
|
804
|
+
}
|
|
805
|
+
|
|
733
806
|
async function handleMetaGet(req: Request, res: Response): Promise<void> {
|
|
734
807
|
try {
|
|
735
808
|
const sessionInfo = await verifyAuth('', '', req.headers.authorization);
|
|
@@ -957,6 +1030,71 @@ async function handleMetaGet(req: Request, res: Response): Promise<void> {
|
|
|
957
1030
|
}
|
|
958
1031
|
}
|
|
959
1032
|
|
|
1033
|
+
async function handleQueryAsCsvPost(req: Request, res: Response): Promise<void> {
|
|
1034
|
+
try {
|
|
1035
|
+
const sessionInfo = await verifyAuth('', '', req.headers.authorization);
|
|
1036
|
+
if (isNoSession(sessionInfo)) {
|
|
1037
|
+
res.status(401).send('Authorization required');
|
|
1038
|
+
return;
|
|
1039
|
+
}
|
|
1040
|
+
const q = req.body?.q;
|
|
1041
|
+
if (q === undefined) {
|
|
1042
|
+
res.status(400).send('Missing or invalid pattern');
|
|
1043
|
+
return;
|
|
1044
|
+
}
|
|
1045
|
+
const qs = objectToQueryPattern(q);
|
|
1046
|
+
const result = await parseAndEvaluateStatement(qs, sessionInfo.userId);
|
|
1047
|
+
const normalized = normalizedResult(result);
|
|
1048
|
+
const rows = evalResultToRows(normalized);
|
|
1049
|
+
const aoa = rowsToSheetAoa(rows);
|
|
1050
|
+
const worksheet = XLSX.utils.aoa_to_sheet(aoa);
|
|
1051
|
+
const workbook = XLSX.utils.book_new();
|
|
1052
|
+
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
|
|
1053
|
+
const buffer = XLSX.write(workbook, { type: 'buffer', bookType: 'csv' });
|
|
1054
|
+
const filename = `eval-${Date.now()}.csv`;
|
|
1055
|
+
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
|
|
1056
|
+
res.contentType('text/csv');
|
|
1057
|
+
res.send(buffer);
|
|
1058
|
+
} catch (err: any) {
|
|
1059
|
+
logger.error(err);
|
|
1060
|
+
if (!res.headersSent) {
|
|
1061
|
+
res.status(statusFromErrorType(err)).send(err?.message ?? err?.toString());
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
async function handleQueryAsXlsxPost(req: Request, res: Response): Promise<void> {
|
|
1067
|
+
try {
|
|
1068
|
+
const sessionInfo = await verifyAuth('', '', req.headers.authorization);
|
|
1069
|
+
if (isNoSession(sessionInfo)) {
|
|
1070
|
+
res.status(401).send('Authorization required');
|
|
1071
|
+
return;
|
|
1072
|
+
}
|
|
1073
|
+
const q = req.body?.q;
|
|
1074
|
+
if (q === undefined) {
|
|
1075
|
+
res.status(400).send('Missing or invalid pattern');
|
|
1076
|
+
return;
|
|
1077
|
+
}
|
|
1078
|
+
const qs = objectToQueryPattern(q);
|
|
1079
|
+
const result = await parseAndEvaluateStatement(qs, sessionInfo.userId);
|
|
1080
|
+
const normalized = normalizedResult(result);
|
|
1081
|
+
const rows = evalResultToRows(normalized);
|
|
1082
|
+
const aoa = rowsToSheetAoa(rows);
|
|
1083
|
+
const worksheet = XLSX.utils.aoa_to_sheet(aoa);
|
|
1084
|
+
const workbook = XLSX.utils.book_new();
|
|
1085
|
+
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
|
|
1086
|
+
const buffer = XLSX.write(workbook, { type: 'buffer', bookType: 'xlsx' });
|
|
1087
|
+
const filename = `eval-${Date.now()}.xlsx`;
|
|
1088
|
+
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
|
|
1089
|
+
res.contentType('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
|
1090
|
+
res.send(buffer);
|
|
1091
|
+
} catch (err: any) {
|
|
1092
|
+
logger.error(err);
|
|
1093
|
+
if (!res.headersSent) {
|
|
1094
|
+
res.status(statusFromErrorType(err)).send(err?.message ?? err?.toString());
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
960
1098
|
async function handleFileUpload(
|
|
961
1099
|
req: Request & { file?: Express.Multer.File },
|
|
962
1100
|
res: Response,
|
|
@@ -115,7 +115,9 @@ Statement: pattern=Pattern hints+=RuntimeHint*;
|
|
|
115
115
|
|
|
116
116
|
IfWithAlias: '(' if=If ')';
|
|
117
117
|
|
|
118
|
-
RuntimeHint: aliasSpec=AliasSpec | catchSpec=CatchSpec | thenSpec=ThenSpec;
|
|
118
|
+
RuntimeHint: aliasSpec=AliasSpec | catchSpec=CatchSpec | emptySpec=EmptySpec | thenSpec=ThenSpec;
|
|
119
|
+
|
|
120
|
+
EmptySpec: '@empty' stmt=Statement;
|
|
119
121
|
|
|
120
122
|
AliasSpec: ('@as' (alias=ID | '[' ( aliases+=ID (',' aliases+=ID)*)+ ']'));
|
|
121
123
|
|
|
@@ -49,6 +49,7 @@ export type AgentlangKeywordNames =
|
|
|
49
49
|
| "@catch"
|
|
50
50
|
| "@desc"
|
|
51
51
|
| "@distinct"
|
|
52
|
+
| "@empty"
|
|
52
53
|
| "@enum"
|
|
53
54
|
| "@expr"
|
|
54
55
|
| "@from"
|
|
@@ -586,6 +587,21 @@ export function isElse(item: unknown): item is Else {
|
|
|
586
587
|
return reflection.isInstance(item, Else.$type);
|
|
587
588
|
}
|
|
588
589
|
|
|
590
|
+
export interface EmptySpec extends langium.AstNode {
|
|
591
|
+
readonly $container: RuntimeHint;
|
|
592
|
+
readonly $type: 'EmptySpec';
|
|
593
|
+
stmt: Statement;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
export const EmptySpec = {
|
|
597
|
+
$type: 'EmptySpec',
|
|
598
|
+
stmt: 'stmt'
|
|
599
|
+
} as const;
|
|
600
|
+
|
|
601
|
+
export function isEmptySpec(item: unknown): item is EmptySpec {
|
|
602
|
+
return reflection.isInstance(item, EmptySpec.$type);
|
|
603
|
+
}
|
|
604
|
+
|
|
589
605
|
export interface EntityActionsDefinitions extends langium.AstNode {
|
|
590
606
|
readonly $container: RecordExtraDefinition;
|
|
591
607
|
readonly $type: 'EntityActionsDefinitions';
|
|
@@ -1744,6 +1760,7 @@ export interface RuntimeHint extends langium.AstNode {
|
|
|
1744
1760
|
readonly $type: 'RuntimeHint';
|
|
1745
1761
|
aliasSpec?: AliasSpec;
|
|
1746
1762
|
catchSpec?: CatchSpec;
|
|
1763
|
+
emptySpec?: EmptySpec;
|
|
1747
1764
|
thenSpec?: ThenSpec;
|
|
1748
1765
|
}
|
|
1749
1766
|
|
|
@@ -1751,6 +1768,7 @@ export const RuntimeHint = {
|
|
|
1751
1768
|
$type: 'RuntimeHint',
|
|
1752
1769
|
aliasSpec: 'aliasSpec',
|
|
1753
1770
|
catchSpec: 'catchSpec',
|
|
1771
|
+
emptySpec: 'emptySpec',
|
|
1754
1772
|
thenSpec: 'thenSpec'
|
|
1755
1773
|
} as const;
|
|
1756
1774
|
|
|
@@ -1864,7 +1882,7 @@ export function isStandaloneStatement(item: unknown): item is StandaloneStatemen
|
|
|
1864
1882
|
}
|
|
1865
1883
|
|
|
1866
1884
|
export interface Statement extends langium.AstNode {
|
|
1867
|
-
readonly $container: ArrayLiteral | CaseEntry | ConditionalFlowStep | Else | FlowEntry | ForEach | Handler | If | StandaloneStatement | ThenSpec | WorkflowDefinition;
|
|
1885
|
+
readonly $container: ArrayLiteral | CaseEntry | ConditionalFlowStep | Else | EmptySpec | FlowEntry | ForEach | Handler | If | StandaloneStatement | ThenSpec | WorkflowDefinition;
|
|
1868
1886
|
readonly $type: 'Statement';
|
|
1869
1887
|
hints: Array<RuntimeHint>;
|
|
1870
1888
|
pattern: Pattern;
|
|
@@ -2102,6 +2120,7 @@ export type AgentlangAstType = {
|
|
|
2102
2120
|
Delete: Delete
|
|
2103
2121
|
DirectiveDefinition: DirectiveDefinition
|
|
2104
2122
|
Else: Else
|
|
2123
|
+
EmptySpec: EmptySpec
|
|
2105
2124
|
EntityActionsDefinitions: EntityActionsDefinitions
|
|
2106
2125
|
EntityDefinition: EntityDefinition
|
|
2107
2126
|
EnumSpec: EnumSpec
|
|
@@ -2517,6 +2536,15 @@ export class AgentlangAstReflection extends langium.AbstractAstReflection {
|
|
|
2517
2536
|
},
|
|
2518
2537
|
superTypes: []
|
|
2519
2538
|
},
|
|
2539
|
+
EmptySpec: {
|
|
2540
|
+
name: EmptySpec.$type,
|
|
2541
|
+
properties: {
|
|
2542
|
+
stmt: {
|
|
2543
|
+
name: EmptySpec.stmt
|
|
2544
|
+
}
|
|
2545
|
+
},
|
|
2546
|
+
superTypes: []
|
|
2547
|
+
},
|
|
2520
2548
|
EntityActionsDefinitions: {
|
|
2521
2549
|
name: EntityActionsDefinitions.$type,
|
|
2522
2550
|
properties: {
|
|
@@ -3361,6 +3389,9 @@ export class AgentlangAstReflection extends langium.AbstractAstReflection {
|
|
|
3361
3389
|
catchSpec: {
|
|
3362
3390
|
name: RuntimeHint.catchSpec
|
|
3363
3391
|
},
|
|
3392
|
+
emptySpec: {
|
|
3393
|
+
name: RuntimeHint.emptySpec
|
|
3394
|
+
},
|
|
3364
3395
|
thenSpec: {
|
|
3365
3396
|
name: RuntimeHint.thenSpec
|
|
3366
3397
|
}
|