agentlang 0.0.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/LICENSE +83 -0
- package/README.md +120 -0
- package/bin/cli.js +4 -0
- package/out/api/http.d.ts +3 -0
- package/out/api/http.d.ts.map +1 -0
- package/out/api/http.js +290 -0
- package/out/api/http.js.map +1 -0
- package/out/cli/cli-util.d.ts +7 -0
- package/out/cli/cli-util.d.ts.map +1 -0
- package/out/cli/cli-util.js +9 -0
- package/out/cli/cli-util.js.map +1 -0
- package/out/cli/docs.d.ts +2 -0
- package/out/cli/docs.d.ts.map +1 -0
- package/out/cli/docs.js +236 -0
- package/out/cli/docs.js.map +1 -0
- package/out/cli/main.d.ts +288 -0
- package/out/cli/main.d.ts.map +1 -0
- package/out/cli/main.js +119 -0
- package/out/cli/main.js.map +1 -0
- package/out/cli/openapi-docs.yml +695 -0
- package/out/extension/main.cjs +18093 -0
- package/out/extension/main.cjs.map +7 -0
- package/out/extension/main.d.ts +4 -0
- package/out/extension/main.d.ts.map +1 -0
- package/out/extension/main.js +42 -0
- package/out/extension/main.js.map +1 -0
- package/out/language/agentlang-module.d.ts +42 -0
- package/out/language/agentlang-module.d.ts.map +1 -0
- package/out/language/agentlang-module.js +42 -0
- package/out/language/agentlang-module.js.map +1 -0
- package/out/language/agentlang-validator.d.ts +15 -0
- package/out/language/agentlang-validator.d.ts.map +1 -0
- package/out/language/agentlang-validator.js +50 -0
- package/out/language/agentlang-validator.js.map +1 -0
- package/out/language/generated/ast.d.ts +491 -0
- package/out/language/generated/ast.d.ts.map +1 -0
- package/out/language/generated/ast.js +934 -0
- package/out/language/generated/ast.js.map +1 -0
- package/out/language/generated/grammar.d.ts +7 -0
- package/out/language/generated/grammar.d.ts.map +1 -0
- package/out/language/generated/grammar.js +4475 -0
- package/out/language/generated/grammar.js.map +1 -0
- package/out/language/generated/module.d.ts +14 -0
- package/out/language/generated/module.d.ts.map +1 -0
- package/out/language/generated/module.js +21 -0
- package/out/language/generated/module.js.map +1 -0
- package/out/language/main-browser.d.ts +2 -0
- package/out/language/main-browser.d.ts.map +1 -0
- package/out/language/main-browser.js +10 -0
- package/out/language/main-browser.js.map +1 -0
- package/out/language/main.cjs +36229 -0
- package/out/language/main.cjs.map +7 -0
- package/out/language/main.d.ts +2 -0
- package/out/language/main.d.ts.map +1 -0
- package/out/language/main.js +11 -0
- package/out/language/main.js.map +1 -0
- package/out/language/parser.d.ts +9 -0
- package/out/language/parser.d.ts.map +1 -0
- package/out/language/parser.js +273 -0
- package/out/language/parser.js.map +1 -0
- package/out/language/syntax.d.ts +155 -0
- package/out/language/syntax.d.ts.map +1 -0
- package/out/language/syntax.js +527 -0
- package/out/language/syntax.js.map +1 -0
- package/out/runtime/agents/common.d.ts +2 -0
- package/out/runtime/agents/common.d.ts.map +1 -0
- package/out/runtime/agents/common.js +178 -0
- package/out/runtime/agents/common.js.map +1 -0
- package/out/runtime/agents/impl/openai.d.ts +8 -0
- package/out/runtime/agents/impl/openai.d.ts.map +1 -0
- package/out/runtime/agents/impl/openai.js +15 -0
- package/out/runtime/agents/impl/openai.js.map +1 -0
- package/out/runtime/agents/provider.d.ts +21 -0
- package/out/runtime/agents/provider.d.ts.map +1 -0
- package/out/runtime/agents/provider.js +32 -0
- package/out/runtime/agents/provider.js.map +1 -0
- package/out/runtime/agents/registry.d.ts +2 -0
- package/out/runtime/agents/registry.d.ts.map +1 -0
- package/out/runtime/agents/registry.js +10 -0
- package/out/runtime/agents/registry.js.map +1 -0
- package/out/runtime/auth/cognito.d.ts +16 -0
- package/out/runtime/auth/cognito.d.ts.map +1 -0
- package/out/runtime/auth/cognito.js +186 -0
- package/out/runtime/auth/cognito.js.map +1 -0
- package/out/runtime/auth/defs.d.ts +11 -0
- package/out/runtime/auth/defs.d.ts.map +1 -0
- package/out/runtime/auth/defs.js +24 -0
- package/out/runtime/auth/defs.js.map +1 -0
- package/out/runtime/auth/interface.d.ts +22 -0
- package/out/runtime/auth/interface.d.ts.map +1 -0
- package/out/runtime/auth/interface.js +2 -0
- package/out/runtime/auth/interface.js.map +1 -0
- package/out/runtime/defs.js +24 -0
- package/out/runtime/defs.js.map +1 -0
- package/out/runtime/interpreter.d.ts +69 -0
- package/out/runtime/interpreter.d.ts.map +1 -0
- package/out/runtime/interpreter.js +1163 -0
- package/out/runtime/interpreter.js.map +1 -0
- package/out/runtime/loader.d.ts +25 -0
- package/out/runtime/loader.d.ts.map +1 -0
- package/out/runtime/loader.js +346 -0
- package/out/runtime/loader.js.map +1 -0
- package/out/runtime/logger.d.ts +2 -0
- package/out/runtime/logger.d.ts.map +1 -0
- package/out/runtime/logger.js +44 -0
- package/out/runtime/logger.js.map +1 -0
- package/out/runtime/module.d.ts +273 -0
- package/out/runtime/module.d.ts.map +1 -0
- package/out/runtime/module.js +1786 -0
- package/out/runtime/module.js.map +1 -0
- package/out/runtime/modules/ai.d.ts +26 -0
- package/out/runtime/modules/ai.d.ts.map +1 -0
- package/out/runtime/modules/ai.js +211 -0
- package/out/runtime/modules/ai.js.map +1 -0
- package/out/runtime/modules/auth.d.ts +39 -0
- package/out/runtime/modules/auth.d.ts.map +1 -0
- package/out/runtime/modules/auth.js +359 -0
- package/out/runtime/modules/auth.js.map +1 -0
- package/out/runtime/modules/core.d.ts +2 -0
- package/out/runtime/modules/core.d.ts.map +1 -0
- package/out/runtime/modules/core.js +67 -0
- package/out/runtime/modules/core.js.map +1 -0
- package/out/runtime/relgraph.d.ts +21 -0
- package/out/runtime/relgraph.d.ts.map +1 -0
- package/out/runtime/relgraph.js +156 -0
- package/out/runtime/relgraph.js.map +1 -0
- package/out/runtime/resolvers/interface.d.ts +59 -0
- package/out/runtime/resolvers/interface.d.ts.map +1 -0
- package/out/runtime/resolvers/interface.js +111 -0
- package/out/runtime/resolvers/interface.js.map +1 -0
- package/out/runtime/resolvers/registry.d.ts +8 -0
- package/out/runtime/resolvers/registry.d.ts.map +1 -0
- package/out/runtime/resolvers/registry.js +26 -0
- package/out/runtime/resolvers/registry.js.map +1 -0
- package/out/runtime/resolvers/sqldb/database.d.ts +50 -0
- package/out/runtime/resolvers/sqldb/database.d.ts.map +1 -0
- package/out/runtime/resolvers/sqldb/database.js +618 -0
- package/out/runtime/resolvers/sqldb/database.js.map +1 -0
- package/out/runtime/resolvers/sqldb/dbutil.d.ts +18 -0
- package/out/runtime/resolvers/sqldb/dbutil.d.ts.map +1 -0
- package/out/runtime/resolvers/sqldb/dbutil.js +221 -0
- package/out/runtime/resolvers/sqldb/dbutil.js.map +1 -0
- package/out/runtime/resolvers/sqldb/impl.d.ts +26 -0
- package/out/runtime/resolvers/sqldb/impl.d.ts.map +1 -0
- package/out/runtime/resolvers/sqldb/impl.js +300 -0
- package/out/runtime/resolvers/sqldb/impl.js.map +1 -0
- package/out/runtime/state.js +83 -0
- package/out/runtime/state.js.map +1 -0
- package/out/runtime/util.d.ts +43 -0
- package/out/runtime/util.d.ts.map +1 -0
- package/out/runtime/util.js +447 -0
- package/out/runtime/util.js.map +1 -0
- package/out/setupClassic.d.ts +98 -0
- package/out/setupClassic.d.ts.map +1 -0
- package/out/setupClassic.js +38 -0
- package/out/setupClassic.js.map +1 -0
- package/out/setupCommon.d.ts +2 -0
- package/out/setupCommon.d.ts.map +1 -0
- package/out/setupCommon.js +33 -0
- package/out/setupCommon.js.map +1 -0
- package/out/setupExtended.d.ts +40 -0
- package/out/setupExtended.d.ts.map +1 -0
- package/out/setupExtended.js +67 -0
- package/out/setupExtended.js.map +1 -0
- package/out/syntaxes/agentlang.monarch.d.ts +77 -0
- package/out/syntaxes/agentlang.monarch.d.ts.map +1 -0
- package/out/syntaxes/agentlang.monarch.js +31 -0
- package/out/syntaxes/agentlang.monarch.js.map +1 -0
- package/out/utils/fs/index.d.ts +14 -0
- package/out/utils/fs/index.d.ts.map +1 -0
- package/out/utils/fs/index.js +26 -0
- package/out/utils/fs/index.js.map +1 -0
- package/out/utils/fs/interfaces.d.ts +105 -0
- package/out/utils/fs/interfaces.d.ts.map +1 -0
- package/out/utils/fs/interfaces.js +5 -0
- package/out/utils/fs/interfaces.js.map +1 -0
- package/out/utils/fs/lightning-fs.d.ts +116 -0
- package/out/utils/fs/lightning-fs.d.ts.map +1 -0
- package/out/utils/fs/lightning-fs.js +243 -0
- package/out/utils/fs/lightning-fs.js.map +1 -0
- package/out/utils/fs/node-fs.d.ts +93 -0
- package/out/utils/fs/node-fs.d.ts.map +1 -0
- package/out/utils/fs/node-fs.js +169 -0
- package/out/utils/fs/node-fs.js.map +1 -0
- package/out/utils/fs-utils.d.ts +153 -0
- package/out/utils/fs-utils.d.ts.map +1 -0
- package/out/utils/fs-utils.js +271 -0
- package/out/utils/fs-utils.js.map +1 -0
- package/out/utils/runtime.d.ts +36 -0
- package/out/utils/runtime.d.ts.map +1 -0
- package/out/utils/runtime.js +39 -0
- package/out/utils/runtime.js.map +1 -0
- package/package.json +155 -0
- package/src/api/http.ts +361 -0
- package/src/cli/cli-util.ts +18 -0
- package/src/cli/main.ts +146 -0
- package/src/extension/main.ts +51 -0
- package/src/language/agentlang-module.ts +75 -0
- package/src/language/agentlang-validator.ts +60 -0
- package/src/language/agentlang.langium +178 -0
- package/src/language/generated/ast.ts +1698 -0
- package/src/language/generated/grammar.ts +4477 -0
- package/src/language/generated/module.ts +25 -0
- package/src/language/main-browser.ts +19 -0
- package/src/language/main.ts +13 -0
- package/src/language/parser.ts +329 -0
- package/src/language/syntax.ts +646 -0
- package/src/runtime/agents/common.ts +177 -0
- package/src/runtime/agents/impl/openai.ts +19 -0
- package/src/runtime/agents/provider.ts +58 -0
- package/src/runtime/agents/registry.ts +9 -0
- package/src/runtime/auth/cognito.ts +225 -0
- package/src/runtime/auth/defs.ts +33 -0
- package/src/runtime/auth/interface.ts +31 -0
- package/src/runtime/defs.ts +33 -0
- package/src/runtime/interpreter.ts +1352 -0
- package/src/runtime/loader.ts +450 -0
- package/src/runtime/logger.ts +51 -0
- package/src/runtime/module.ts +2188 -0
- package/src/runtime/modules/ai.ts +257 -0
- package/src/runtime/modules/auth.ts +489 -0
- package/src/runtime/modules/core.ts +95 -0
- package/src/runtime/relgraph.ts +195 -0
- package/src/runtime/resolvers/interface.ts +160 -0
- package/src/runtime/resolvers/registry.ts +30 -0
- package/src/runtime/resolvers/sqldb/database.ts +823 -0
- package/src/runtime/resolvers/sqldb/dbutil.ts +257 -0
- package/src/runtime/resolvers/sqldb/impl.ts +471 -0
- package/src/runtime/state.ts +87 -0
- package/src/runtime/util.ts +513 -0
- package/src/setupClassic.ts +43 -0
- package/src/setupCommon.ts +33 -0
- package/src/setupExtended.ts +79 -0
- package/src/syntaxes/agentlang.monarch.ts +31 -0
- package/src/utils/fs/index.ts +28 -0
- package/src/utils/fs/interfaces.ts +118 -0
- package/src/utils/fs/lightning-fs.ts +284 -0
- package/src/utils/fs/node-fs.ts +185 -0
- package/src/utils/fs-utils.ts +304 -0
- package/src/utils/runtime.ts +43 -0
package/src/api/http.ts
ADDED
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import express, { Request, Response } from 'express';
|
|
3
|
+
import {
|
|
4
|
+
getAllChildRelationships,
|
|
5
|
+
getAllEntityNames,
|
|
6
|
+
getAllEventNames,
|
|
7
|
+
Instance,
|
|
8
|
+
InstanceAttributes,
|
|
9
|
+
makeInstance,
|
|
10
|
+
objectAsInstanceAttributes,
|
|
11
|
+
Relationship,
|
|
12
|
+
} from '../runtime/module.js';
|
|
13
|
+
import { evaluate, parseAndEvaluateStatement, Result } from '../runtime/interpreter.js';
|
|
14
|
+
import { ApplicationSpec } from '../runtime/loader.js';
|
|
15
|
+
import { logger } from '../runtime/logger.js';
|
|
16
|
+
import { requireAuth, verifySession } from '../runtime/modules/auth.js';
|
|
17
|
+
import { ActiveSessionInfo, BypassSession, isNoSession, NoSession } from '../runtime/auth/defs.js';
|
|
18
|
+
import {
|
|
19
|
+
escapeFqName,
|
|
20
|
+
forceAsEscapedName,
|
|
21
|
+
forceAsFqName,
|
|
22
|
+
isString,
|
|
23
|
+
makeFqName,
|
|
24
|
+
restoreFqName,
|
|
25
|
+
splitFqName,
|
|
26
|
+
walkDownInstancePath,
|
|
27
|
+
} from '../runtime/util.js';
|
|
28
|
+
import { BadRequestError, PathAttributeNameQuery, UnauthorisedError } from '../runtime/defs.js';
|
|
29
|
+
|
|
30
|
+
export function startServer(appSpec: ApplicationSpec, port: number) {
|
|
31
|
+
const app = express();
|
|
32
|
+
app.use(express.json());
|
|
33
|
+
|
|
34
|
+
const appName: string = appSpec.name;
|
|
35
|
+
const appVersion: string = appSpec.version;
|
|
36
|
+
|
|
37
|
+
app.get('/', (req: Request, res: Response) => {
|
|
38
|
+
res.send(appName);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
getAllEventNames().forEach((eventNames: string[], moduleName: string) => {
|
|
42
|
+
eventNames.forEach((n: string) => {
|
|
43
|
+
app.post(`/${moduleName}/${n}`, (req: Request, res: Response) => {
|
|
44
|
+
handleEventPost(moduleName, n, req, res);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
getAllEntityNames().forEach((entityNames: string[], moduleName: string) => {
|
|
50
|
+
entityNames.forEach((n: string) => {
|
|
51
|
+
app.get(`/${moduleName}/${n}`, (req: Request, res: Response) => {
|
|
52
|
+
handleEntityGet(moduleName, n, req, res);
|
|
53
|
+
});
|
|
54
|
+
app.get(`/${moduleName}/${n}/*path`, (req: Request, res: Response) => {
|
|
55
|
+
handleEntityGet(moduleName, n, req, res);
|
|
56
|
+
});
|
|
57
|
+
app.post(`/${moduleName}/${n}`, (req: Request, res: Response) => {
|
|
58
|
+
handleEntityPost(moduleName, n, req, res);
|
|
59
|
+
});
|
|
60
|
+
app.post(`/${moduleName}/${n}/*path`, (req: Request, res: Response) => {
|
|
61
|
+
handleEntityPost(moduleName, n, req, res);
|
|
62
|
+
});
|
|
63
|
+
app.put(`/${moduleName}/${n}/*path`, (req: Request, res: Response) => {
|
|
64
|
+
handleEntityPut(moduleName, n, req, res);
|
|
65
|
+
});
|
|
66
|
+
app.delete(`/${moduleName}/${n}/*path`, (req: Request, res: Response) => {
|
|
67
|
+
handleEntityDelete(moduleName, n, req, res);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
app.listen(port, () => {
|
|
73
|
+
console.log(
|
|
74
|
+
chalk.green(
|
|
75
|
+
`Application ${chalk.bold(appName + ' version ' + appVersion)} started on port ${chalk.bold(port)}`
|
|
76
|
+
)
|
|
77
|
+
);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function ok(res: Response) {
|
|
82
|
+
return (value: Result) => {
|
|
83
|
+
const result: Result = normalizedResult(value);
|
|
84
|
+
res.contentType('application/json');
|
|
85
|
+
res.send(JSON.stringify(result));
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function statusFromErrorType(err: any): number {
|
|
90
|
+
if (err instanceof UnauthorisedError) {
|
|
91
|
+
return 401;
|
|
92
|
+
} else if (err instanceof BadRequestError) {
|
|
93
|
+
return 400;
|
|
94
|
+
} else {
|
|
95
|
+
return 500;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function internalError(res: Response) {
|
|
100
|
+
return (reason: any) => {
|
|
101
|
+
logger.error(reason);
|
|
102
|
+
res.status(statusFromErrorType(reason)).send(reason.message);
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function patternFromAttributes(
|
|
107
|
+
moduleName: string,
|
|
108
|
+
recName: string,
|
|
109
|
+
attrs: InstanceAttributes
|
|
110
|
+
): string {
|
|
111
|
+
const attrsStrs = new Array<string>();
|
|
112
|
+
attrs.forEach((v: any, n: string) => {
|
|
113
|
+
let av = isString(v) ? `"${v}"` : v;
|
|
114
|
+
if (av instanceof Object) {
|
|
115
|
+
av = JSON.stringify(av);
|
|
116
|
+
}
|
|
117
|
+
attrsStrs.push(`${n} ${av}`);
|
|
118
|
+
});
|
|
119
|
+
return `{${moduleName}/${recName} { ${attrsStrs.join(',\n')} }}`;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function normalizeRequestPath(path: string[], moduleName: string): string[] {
|
|
123
|
+
if (path.length <= 1) {
|
|
124
|
+
return path;
|
|
125
|
+
}
|
|
126
|
+
const result = new Array<string>();
|
|
127
|
+
result.push(path[0]);
|
|
128
|
+
for (let i = 1; i < path.length; ++i) {
|
|
129
|
+
const rn = forceAsEscapedName(path[i], moduleName);
|
|
130
|
+
const en = forceAsEscapedName(path[++i], moduleName);
|
|
131
|
+
result.push(rn);
|
|
132
|
+
result.push(en);
|
|
133
|
+
if (i < path.length) {
|
|
134
|
+
result.push(path[++i]);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function pathFromRequest(moduleName: string, entryName: string, req: Request): string {
|
|
141
|
+
const path: any = req.params.path;
|
|
142
|
+
if (!path) {
|
|
143
|
+
return req.url;
|
|
144
|
+
}
|
|
145
|
+
let p = '';
|
|
146
|
+
if (path instanceof Array) {
|
|
147
|
+
p = normalizeRequestPath(path, moduleName).join('/');
|
|
148
|
+
} else {
|
|
149
|
+
p = path.toString();
|
|
150
|
+
}
|
|
151
|
+
p = p.trim();
|
|
152
|
+
if (p.endsWith('/')) {
|
|
153
|
+
p = p.substring(0, p.length - 1);
|
|
154
|
+
}
|
|
155
|
+
return `${escapeFqName(makeFqName(moduleName, entryName))}/${p}`;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
async function handleEventPost(
|
|
159
|
+
moduleName: string,
|
|
160
|
+
eventName: string,
|
|
161
|
+
req: Request,
|
|
162
|
+
res: Response
|
|
163
|
+
): Promise<void> {
|
|
164
|
+
try {
|
|
165
|
+
const sessionInfo = await verifyAuth(moduleName, eventName, req.headers.authorization);
|
|
166
|
+
if (isNoSession(sessionInfo)) {
|
|
167
|
+
res.status(401).send('Authorization required');
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const inst: Instance = makeInstance(
|
|
171
|
+
moduleName,
|
|
172
|
+
eventName,
|
|
173
|
+
objectAsInstanceAttributes(req.body)
|
|
174
|
+
).setAuthContext(sessionInfo);
|
|
175
|
+
evaluate(inst, ok(res)).catch(internalError(res));
|
|
176
|
+
} catch (err: any) {
|
|
177
|
+
logger.error(err);
|
|
178
|
+
res.status(500).send(err.toString());
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async function handleEntityPost(
|
|
183
|
+
moduleName: string,
|
|
184
|
+
entityName: string,
|
|
185
|
+
req: Request,
|
|
186
|
+
res: Response
|
|
187
|
+
): Promise<void> {
|
|
188
|
+
try {
|
|
189
|
+
const sessionInfo = await verifyAuth(moduleName, entityName, req.headers.authorization);
|
|
190
|
+
if (isNoSession(sessionInfo)) {
|
|
191
|
+
res.status(401).send('Authorization required');
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
const pattern = req.params.path
|
|
195
|
+
? createChildPattern(moduleName, entityName, req)
|
|
196
|
+
: patternFromAttributes(moduleName, entityName, objectAsInstanceAttributes(req.body));
|
|
197
|
+
parseAndEvaluateStatement(pattern, sessionInfo.userId).then(ok(res)).catch(internalError(res));
|
|
198
|
+
} catch (err: any) {
|
|
199
|
+
logger.error(err);
|
|
200
|
+
res.status(500).send(err.toString());
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async function handleEntityGet(
|
|
205
|
+
moduleName: string,
|
|
206
|
+
entityName: string,
|
|
207
|
+
req: Request,
|
|
208
|
+
res: Response
|
|
209
|
+
): Promise<void> {
|
|
210
|
+
try {
|
|
211
|
+
const path = pathFromRequest(moduleName, entityName, req);
|
|
212
|
+
const sessionInfo = await verifyAuth(moduleName, entityName, req.headers.authorization);
|
|
213
|
+
if (isNoSession(sessionInfo)) {
|
|
214
|
+
res.status(401).send('Authorization required');
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
let pattern = '';
|
|
218
|
+
if (req.query.tree) {
|
|
219
|
+
pattern = fetchTreePattern(makeFqName(moduleName, entityName), path);
|
|
220
|
+
} else {
|
|
221
|
+
const r = walkDownInstancePath(path);
|
|
222
|
+
let moduleName = r[0];
|
|
223
|
+
let entityName = r[1];
|
|
224
|
+
const id = r[2];
|
|
225
|
+
const parts = r[3];
|
|
226
|
+
if (parts.length == 2 && id == undefined) {
|
|
227
|
+
pattern = `{${moduleName}/${entityName}? {}}`;
|
|
228
|
+
} else {
|
|
229
|
+
moduleName = restoreFqName(moduleName);
|
|
230
|
+
entityName = restoreFqName(entityName);
|
|
231
|
+
if (id == undefined) {
|
|
232
|
+
pattern = `{${moduleName}/${entityName} {${PathAttributeNameQuery}like "${path}%"}}`;
|
|
233
|
+
} else {
|
|
234
|
+
pattern = `{${moduleName}/${entityName} {${PathAttributeNameQuery} "${path}"}}`;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
parseAndEvaluateStatement(pattern, sessionInfo.userId).then(ok(res)).catch(internalError(res));
|
|
239
|
+
} catch (err: any) {
|
|
240
|
+
logger.error(err);
|
|
241
|
+
res.status(500).send(err.toString());
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
async function handleEntityPut(
|
|
246
|
+
moduleName: string,
|
|
247
|
+
entityName: string,
|
|
248
|
+
req: Request,
|
|
249
|
+
res: Response
|
|
250
|
+
): Promise<void> {
|
|
251
|
+
try {
|
|
252
|
+
const path = pathFromRequest(moduleName, entityName, req);
|
|
253
|
+
const sessionInfo = await verifyAuth(moduleName, entityName, req.headers.authorization);
|
|
254
|
+
if (isNoSession(sessionInfo)) {
|
|
255
|
+
res.status(401).send('Authorization required');
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
const attrs = objectAsInstanceAttributes(req.body);
|
|
259
|
+
attrs.set(PathAttributeNameQuery, path);
|
|
260
|
+
const pattern = patternFromAttributes(moduleName, entityName, attrs);
|
|
261
|
+
parseAndEvaluateStatement(pattern, sessionInfo.userId).then(ok(res)).catch(internalError(res));
|
|
262
|
+
} catch (err: any) {
|
|
263
|
+
logger.error(err);
|
|
264
|
+
res.status(500).send(err.toString());
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
async function handleEntityDelete(
|
|
269
|
+
moduleName: string,
|
|
270
|
+
entityName: string,
|
|
271
|
+
req: Request,
|
|
272
|
+
res: Response
|
|
273
|
+
): Promise<void> {
|
|
274
|
+
try {
|
|
275
|
+
const path = pathFromRequest(moduleName, entityName, req);
|
|
276
|
+
const sessionInfo = await verifyAuth(moduleName, entityName, req.headers.authorization);
|
|
277
|
+
if (isNoSession(sessionInfo)) {
|
|
278
|
+
res.status(401).send('Authorization required');
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
const pattern = `delete {${moduleName}/${entityName} {${PathAttributeNameQuery} "${path}"}}`;
|
|
282
|
+
parseAndEvaluateStatement(pattern, sessionInfo.userId).then(ok(res)).catch(internalError(res));
|
|
283
|
+
} catch (err: any) {
|
|
284
|
+
logger.error(err);
|
|
285
|
+
res.status(500).send(err.toString());
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function fetchTreePattern(fqName: string, path?: string): string {
|
|
290
|
+
let pattern = path ? `{${fqName} {${PathAttributeNameQuery} "${path}"}` : `{${fqName}? {}`;
|
|
291
|
+
const rels = getAllChildRelationships(fqName);
|
|
292
|
+
if (rels.length > 0) {
|
|
293
|
+
const treePats = new Array<string>();
|
|
294
|
+
rels.forEach((rel: Relationship) => {
|
|
295
|
+
treePats.push(`${rel.getFqName()} ${fetchTreePattern(rel.getChildFqName())}`);
|
|
296
|
+
});
|
|
297
|
+
pattern = pattern.concat(',', treePats.join(','));
|
|
298
|
+
}
|
|
299
|
+
return `${pattern}}`;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function createChildPattern(moduleName: string, entityName: string, req: Request): string {
|
|
303
|
+
const path = pathFromRequest(moduleName, entityName, req);
|
|
304
|
+
try {
|
|
305
|
+
const parts = path.split('/');
|
|
306
|
+
const pinfo = parts.slice(-4);
|
|
307
|
+
const parentFqname = forceAsFqName(pinfo[0], moduleName);
|
|
308
|
+
const relName = forceAsFqName(pinfo[2], moduleName);
|
|
309
|
+
const parentPath = parts.slice(0, parts.length - 2).join('/');
|
|
310
|
+
const childFqName = forceAsFqName(pinfo[3], moduleName);
|
|
311
|
+
const cparts = splitFqName(childFqName);
|
|
312
|
+
const childModuleName = cparts.getModuleName();
|
|
313
|
+
const childName = cparts.getEntryName();
|
|
314
|
+
const cp = patternFromAttributes(
|
|
315
|
+
childModuleName,
|
|
316
|
+
childName,
|
|
317
|
+
objectAsInstanceAttributes(req.body)
|
|
318
|
+
);
|
|
319
|
+
return `{${parentFqname} {${PathAttributeNameQuery} "${parentPath}"}, ${relName} ${cp}}`;
|
|
320
|
+
} catch (err: any) {
|
|
321
|
+
throw new BadRequestError(err.message);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
async function verifyAuth(
|
|
326
|
+
moduleName: string,
|
|
327
|
+
eventName: string,
|
|
328
|
+
authValue: string | undefined
|
|
329
|
+
): Promise<ActiveSessionInfo> {
|
|
330
|
+
if (requireAuth(moduleName, eventName)) {
|
|
331
|
+
if (authValue) {
|
|
332
|
+
const token = authValue.substring(authValue.indexOf(' ')).trim();
|
|
333
|
+
return await verifySession(token);
|
|
334
|
+
} else {
|
|
335
|
+
return NoSession;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return BypassSession;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function normalizedResult(r: Result): Result {
|
|
342
|
+
if (r instanceof Array) {
|
|
343
|
+
return r.map((x: Result) => {
|
|
344
|
+
return normalizedResult(x);
|
|
345
|
+
});
|
|
346
|
+
} else if (r instanceof Instance) {
|
|
347
|
+
r.mergeRelatedInstances();
|
|
348
|
+
Array.from(r.attributes.keys()).forEach(k => {
|
|
349
|
+
const v: Result = r.attributes.get(k);
|
|
350
|
+
if (v instanceof Array || v instanceof Instance) {
|
|
351
|
+
r.attributes.set(k, normalizedResult(v));
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
return r.asObject();
|
|
355
|
+
} else {
|
|
356
|
+
if (r instanceof Map) {
|
|
357
|
+
return Object.fromEntries(r.entries());
|
|
358
|
+
}
|
|
359
|
+
return r;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { path } from '../utils/runtime.js';
|
|
2
|
+
|
|
3
|
+
interface FilePathData {
|
|
4
|
+
destination: string;
|
|
5
|
+
name: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function extractDestinationAndName(
|
|
9
|
+
filePath: string,
|
|
10
|
+
destination: string | undefined
|
|
11
|
+
): FilePathData {
|
|
12
|
+
const fileName = path.basename(filePath, path.extname(filePath)).replace(/[.-]/g, '');
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
destination: destination ?? path.join(path.dirname(filePath), 'generated'),
|
|
16
|
+
name: fileName,
|
|
17
|
+
};
|
|
18
|
+
}
|
package/src/cli/main.ts
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { AgentlangLanguageMetaData } from '../language/generated/module.js';
|
|
4
|
+
import { createAgentlangServices } from '../language/agentlang-module.js';
|
|
5
|
+
import {
|
|
6
|
+
ApplicationSpec,
|
|
7
|
+
internModule,
|
|
8
|
+
load,
|
|
9
|
+
loadCoreModules,
|
|
10
|
+
runStandaloneStatements,
|
|
11
|
+
} from '../runtime/loader.js';
|
|
12
|
+
import { NodeFileSystem } from 'langium/node';
|
|
13
|
+
import { extractDocument } from '../runtime/loader.js';
|
|
14
|
+
import * as url from 'node:url';
|
|
15
|
+
import * as fs from 'node:fs/promises';
|
|
16
|
+
import * as path from 'node:path';
|
|
17
|
+
import { startServer } from '../api/http.js';
|
|
18
|
+
import { initDatabase } from '../runtime/resolvers/sqldb/database.js';
|
|
19
|
+
import { logger } from '../runtime/logger.js';
|
|
20
|
+
import { runInitFunctions } from '../runtime/util.js';
|
|
21
|
+
import { Module } from '../runtime/module.js';
|
|
22
|
+
import { ModuleDefinition } from '../language/generated/ast.js';
|
|
23
|
+
import { z } from 'zod';
|
|
24
|
+
import { loadConfig } from 'c12';
|
|
25
|
+
import { Config, ConfigSchema, setAppConfig } from '../runtime/state.js';
|
|
26
|
+
|
|
27
|
+
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
|
|
28
|
+
|
|
29
|
+
const packagePath = path.resolve(__dirname, '..', '..', 'package.json');
|
|
30
|
+
const packageContent = await fs.readFile(packagePath, 'utf-8');
|
|
31
|
+
|
|
32
|
+
export type GenerateOptions = {
|
|
33
|
+
destination?: string;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export default function (): void {
|
|
37
|
+
const program = new Command();
|
|
38
|
+
|
|
39
|
+
program.version(JSON.parse(packageContent).version);
|
|
40
|
+
|
|
41
|
+
const fileExtensions = AgentlangLanguageMetaData.fileExtensions.join(', ');
|
|
42
|
+
|
|
43
|
+
program
|
|
44
|
+
.command('run')
|
|
45
|
+
.argument('<file>', `source file (possible file extensions: ${fileExtensions})`)
|
|
46
|
+
.option('-c, --config <config>', 'configuration file')
|
|
47
|
+
.description('Loads and runs an agentlang module')
|
|
48
|
+
.action(runModule);
|
|
49
|
+
|
|
50
|
+
program
|
|
51
|
+
.command('parseAndValidate')
|
|
52
|
+
.argument('<file>', `source file (possible file extensions: ${fileExtensions})`)
|
|
53
|
+
.option('-d, --destination <dir>', 'destination directory of generating')
|
|
54
|
+
.description('Parses and validates an Agentlang module')
|
|
55
|
+
.action(parseAndValidate);
|
|
56
|
+
|
|
57
|
+
program.parse(process.argv);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Parse and validate a program written in our language.
|
|
62
|
+
* Verifies that no lexer or parser errors occur.
|
|
63
|
+
* Implicitly also checks for validation errors while extracting the document
|
|
64
|
+
*
|
|
65
|
+
* @param fileName Program to validate
|
|
66
|
+
*/
|
|
67
|
+
export const parseAndValidate = async (fileName: string): Promise<void> => {
|
|
68
|
+
// retrieve the services for our language
|
|
69
|
+
const services = createAgentlangServices(NodeFileSystem).Agentlang;
|
|
70
|
+
// extract a document for our program
|
|
71
|
+
const document = await extractDocument(fileName, services);
|
|
72
|
+
// extract the parse result details
|
|
73
|
+
const parseResult = document.parseResult;
|
|
74
|
+
// verify no lexer, parser, or general diagnostic errors show up
|
|
75
|
+
if (parseResult.lexerErrors.length === 0 && parseResult.parserErrors.length === 0) {
|
|
76
|
+
console.log(chalk.green(`Parsed and validated ${fileName} successfully!`));
|
|
77
|
+
} else {
|
|
78
|
+
console.log(chalk.red(`Failed to parse and validate ${fileName}!`));
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export async function runPreInitTasks(): Promise<boolean> {
|
|
83
|
+
let result: boolean = true;
|
|
84
|
+
await loadCoreModules().catch((reason: any) => {
|
|
85
|
+
const msg = `Failed to load core modules - ${reason.toString()}`;
|
|
86
|
+
logger.error(msg);
|
|
87
|
+
console.log(chalk.red(msg));
|
|
88
|
+
result = false;
|
|
89
|
+
});
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export async function runPostInitTasks(appSpec?: ApplicationSpec, config?: Config) {
|
|
94
|
+
await initDatabase(config?.store);
|
|
95
|
+
await runInitFunctions();
|
|
96
|
+
await runStandaloneStatements();
|
|
97
|
+
if (appSpec) startServer(appSpec, config?.service?.port || 8080);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export const runModule = async (fileName: string, options?: { config?: string }): Promise<void> => {
|
|
101
|
+
const configDir =
|
|
102
|
+
path.dirname(fileName) === '.' ? process.cwd() : path.resolve(process.cwd(), fileName);
|
|
103
|
+
|
|
104
|
+
let config: Config | undefined;
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
const { config: rawConfig } = await loadConfig({
|
|
108
|
+
cwd: configDir,
|
|
109
|
+
name: 'config',
|
|
110
|
+
configFile: options?.config || 'app.config',
|
|
111
|
+
dotenv: true,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
config = setAppConfig(ConfigSchema.parse(rawConfig));
|
|
115
|
+
} catch (err) {
|
|
116
|
+
if (err instanceof z.ZodError) {
|
|
117
|
+
console.log(chalk.red('Config validation failed:'));
|
|
118
|
+
err.errors.forEach((error, index) => {
|
|
119
|
+
console.log(chalk.red(` ${index + 1}. ${error.path.join('.')}: ${error.message}`));
|
|
120
|
+
});
|
|
121
|
+
} else {
|
|
122
|
+
console.log(`Config loading failed: ${err}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const r: boolean = await runPreInitTasks();
|
|
127
|
+
if (!r) {
|
|
128
|
+
throw new Error('Failed to initialize runtime');
|
|
129
|
+
}
|
|
130
|
+
await load(fileName, undefined, async (appSpec?: ApplicationSpec) => {
|
|
131
|
+
await runPostInitTasks(appSpec, config);
|
|
132
|
+
});
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
export async function internAndRunModule(
|
|
136
|
+
module: ModuleDefinition,
|
|
137
|
+
appSpec?: ApplicationSpec
|
|
138
|
+
): Promise<Module> {
|
|
139
|
+
const r: boolean = await runPreInitTasks();
|
|
140
|
+
if (!r) {
|
|
141
|
+
throw new Error('Failed to initialize runtime');
|
|
142
|
+
}
|
|
143
|
+
const rm: Module = internModule(module);
|
|
144
|
+
await runPostInitTasks(appSpec);
|
|
145
|
+
return rm;
|
|
146
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { LanguageClientOptions, ServerOptions } from 'vscode-languageclient/node.js';
|
|
2
|
+
import type * as vscode from 'vscode';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import { LanguageClient, TransportKind } from 'vscode-languageclient/node.js';
|
|
5
|
+
|
|
6
|
+
let client: LanguageClient;
|
|
7
|
+
|
|
8
|
+
// This function is called when the extension is activated.
|
|
9
|
+
export function activate(context: vscode.ExtensionContext): void {
|
|
10
|
+
client = startLanguageClient(context);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// This function is called when the extension is deactivated.
|
|
14
|
+
export function deactivate(): Thenable<void> | undefined {
|
|
15
|
+
if (client) {
|
|
16
|
+
return client.stop();
|
|
17
|
+
}
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function startLanguageClient(context: vscode.ExtensionContext): LanguageClient {
|
|
22
|
+
const serverModule = context.asAbsolutePath(path.join('out', 'language', 'main.cjs'));
|
|
23
|
+
// The debug options for the server
|
|
24
|
+
// --inspect=6009: runs the server in Node's Inspector mode so VS Code can attach to the server for debugging.
|
|
25
|
+
// By setting `process.env.DEBUG_BREAK` to a truthy value, the language server will wait until a debugger is attached.
|
|
26
|
+
const debugOptions = {
|
|
27
|
+
execArgv: [
|
|
28
|
+
'--nolazy',
|
|
29
|
+
`--inspect${process.env.DEBUG_BREAK ? '-brk' : ''}=${process.env.DEBUG_SOCKET || '6009'}`,
|
|
30
|
+
],
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// If the extension is launched in debug mode then the debug server options are used
|
|
34
|
+
// Otherwise the run options are used
|
|
35
|
+
const serverOptions: ServerOptions = {
|
|
36
|
+
run: { module: serverModule, transport: TransportKind.ipc },
|
|
37
|
+
debug: { module: serverModule, transport: TransportKind.ipc, options: debugOptions },
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// Options to control the language client
|
|
41
|
+
const clientOptions: LanguageClientOptions = {
|
|
42
|
+
documentSelector: [{ scheme: '*', language: 'agentlang' }],
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Create the language client and start the client.
|
|
46
|
+
const client = new LanguageClient('agentlang', 'Agentlang', serverOptions, clientOptions);
|
|
47
|
+
|
|
48
|
+
// Start the client. This will also launch the server
|
|
49
|
+
client.start();
|
|
50
|
+
return client;
|
|
51
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { type Module, inject } from 'langium';
|
|
2
|
+
import {
|
|
3
|
+
createDefaultModule,
|
|
4
|
+
createDefaultSharedModule,
|
|
5
|
+
type DefaultSharedModuleContext,
|
|
6
|
+
type LangiumServices,
|
|
7
|
+
type LangiumSharedServices,
|
|
8
|
+
type PartialLangiumServices,
|
|
9
|
+
} from 'langium/lsp';
|
|
10
|
+
import { AgentlangGeneratedModule, AgentlangGeneratedSharedModule } from './generated/module.js';
|
|
11
|
+
import { AgentlangValidator, registerValidationChecks } from './agentlang-validator.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Declaration of custom services - add your own service classes here.
|
|
15
|
+
*/
|
|
16
|
+
export type AgentlangAddedServices = {
|
|
17
|
+
validation: {
|
|
18
|
+
AgentlangValidator: AgentlangValidator;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Union of Langium default services and your custom services - use this as constructor parameter
|
|
24
|
+
* of custom service classes.
|
|
25
|
+
*/
|
|
26
|
+
export type AgentlangServices = LangiumServices & AgentlangAddedServices;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Dependency injection module that overrides Langium default services and contributes the
|
|
30
|
+
* declared custom services. The Langium defaults can be partially specified to override only
|
|
31
|
+
* selected services, while the custom services must be fully specified.
|
|
32
|
+
*/
|
|
33
|
+
export const AgentlangModule: Module<
|
|
34
|
+
AgentlangServices,
|
|
35
|
+
PartialLangiumServices & AgentlangAddedServices
|
|
36
|
+
> = {
|
|
37
|
+
validation: {
|
|
38
|
+
AgentlangValidator: () => new AgentlangValidator(),
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Create the full set of services required by Langium.
|
|
44
|
+
*
|
|
45
|
+
* First inject the shared services by merging two modules:
|
|
46
|
+
* - Langium default shared services
|
|
47
|
+
* - Services generated by langium-cli
|
|
48
|
+
*
|
|
49
|
+
* Then inject the language-specific services by merging three modules:
|
|
50
|
+
* - Langium default language-specific services
|
|
51
|
+
* - Services generated by langium-cli
|
|
52
|
+
* - Services specified in this file
|
|
53
|
+
*
|
|
54
|
+
* @param context Optional module context with the LSP connection
|
|
55
|
+
* @returns An object wrapping the shared services and the language-specific services
|
|
56
|
+
*/
|
|
57
|
+
export function createAgentlangServices(context: DefaultSharedModuleContext): {
|
|
58
|
+
shared: LangiumSharedServices;
|
|
59
|
+
Agentlang: AgentlangServices;
|
|
60
|
+
} {
|
|
61
|
+
const shared = inject(createDefaultSharedModule(context), AgentlangGeneratedSharedModule);
|
|
62
|
+
const Agentlang = inject(
|
|
63
|
+
createDefaultModule({ shared }),
|
|
64
|
+
AgentlangGeneratedModule,
|
|
65
|
+
AgentlangModule
|
|
66
|
+
);
|
|
67
|
+
shared.ServiceRegistry.register(Agentlang);
|
|
68
|
+
registerValidationChecks(Agentlang);
|
|
69
|
+
if (!context.connection) {
|
|
70
|
+
// We don't run inside a language server
|
|
71
|
+
// Therefore, initialize the configuration provider instantly
|
|
72
|
+
shared.workspace.ConfigurationProvider.initialized({});
|
|
73
|
+
}
|
|
74
|
+
return { shared, Agentlang };
|
|
75
|
+
}
|