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.
Files changed (178) hide show
  1. package/README.md +7 -14
  2. package/out/api/http.d.ts +4 -0
  3. package/out/api/http.d.ts.map +1 -1
  4. package/out/api/http.js +307 -26
  5. package/out/api/http.js.map +1 -1
  6. package/out/cli/main.d.ts.map +1 -1
  7. package/out/cli/main.js +3 -0
  8. package/out/cli/main.js.map +1 -1
  9. package/out/extension/main.cjs +250 -250
  10. package/out/extension/main.cjs.map +2 -2
  11. package/out/language/agentlang-validator.d.ts.map +1 -1
  12. package/out/language/agentlang-validator.js +4 -0
  13. package/out/language/agentlang-validator.js.map +1 -1
  14. package/out/language/error-reporter.d.ts +53 -0
  15. package/out/language/error-reporter.d.ts.map +1 -0
  16. package/out/language/error-reporter.js +879 -0
  17. package/out/language/error-reporter.js.map +1 -0
  18. package/out/language/generated/ast.d.ts +77 -2
  19. package/out/language/generated/ast.d.ts.map +1 -1
  20. package/out/language/generated/ast.js +60 -0
  21. package/out/language/generated/ast.js.map +1 -1
  22. package/out/language/generated/grammar.d.ts.map +1 -1
  23. package/out/language/generated/grammar.js +342 -206
  24. package/out/language/generated/grammar.js.map +1 -1
  25. package/out/language/main.cjs +901 -710
  26. package/out/language/main.cjs.map +3 -3
  27. package/out/language/parser.d.ts +4 -2
  28. package/out/language/parser.d.ts.map +1 -1
  29. package/out/language/parser.js +58 -99
  30. package/out/language/parser.js.map +1 -1
  31. package/out/language/syntax.d.ts +16 -0
  32. package/out/language/syntax.d.ts.map +1 -1
  33. package/out/language/syntax.js +66 -27
  34. package/out/language/syntax.js.map +1 -1
  35. package/out/runtime/api.d.ts +2 -0
  36. package/out/runtime/api.d.ts.map +1 -1
  37. package/out/runtime/api.js +25 -0
  38. package/out/runtime/api.js.map +1 -1
  39. package/out/runtime/datefns.d.ts +34 -0
  40. package/out/runtime/datefns.d.ts.map +1 -0
  41. package/out/runtime/datefns.js +82 -0
  42. package/out/runtime/datefns.js.map +1 -0
  43. package/out/runtime/defs.d.ts +1 -0
  44. package/out/runtime/defs.d.ts.map +1 -1
  45. package/out/runtime/defs.js +2 -1
  46. package/out/runtime/defs.js.map +1 -1
  47. package/out/runtime/document-retriever.d.ts +24 -0
  48. package/out/runtime/document-retriever.d.ts.map +1 -0
  49. package/out/runtime/document-retriever.js +258 -0
  50. package/out/runtime/document-retriever.js.map +1 -0
  51. package/out/runtime/embeddings/chunker.d.ts +18 -0
  52. package/out/runtime/embeddings/chunker.d.ts.map +1 -1
  53. package/out/runtime/embeddings/chunker.js +47 -15
  54. package/out/runtime/embeddings/chunker.js.map +1 -1
  55. package/out/runtime/embeddings/openai.d.ts.map +1 -1
  56. package/out/runtime/embeddings/openai.js +22 -9
  57. package/out/runtime/embeddings/openai.js.map +1 -1
  58. package/out/runtime/embeddings/provider.d.ts +1 -0
  59. package/out/runtime/embeddings/provider.d.ts.map +1 -1
  60. package/out/runtime/embeddings/provider.js +20 -1
  61. package/out/runtime/embeddings/provider.js.map +1 -1
  62. package/out/runtime/exec-graph.d.ts.map +1 -1
  63. package/out/runtime/exec-graph.js +22 -3
  64. package/out/runtime/exec-graph.js.map +1 -1
  65. package/out/runtime/integration-client.d.ts +21 -0
  66. package/out/runtime/integration-client.d.ts.map +1 -0
  67. package/out/runtime/integration-client.js +112 -0
  68. package/out/runtime/integration-client.js.map +1 -0
  69. package/out/runtime/integrations.d.ts.map +1 -1
  70. package/out/runtime/integrations.js +20 -9
  71. package/out/runtime/integrations.js.map +1 -1
  72. package/out/runtime/interpreter.d.ts +10 -0
  73. package/out/runtime/interpreter.d.ts.map +1 -1
  74. package/out/runtime/interpreter.js +221 -22
  75. package/out/runtime/interpreter.js.map +1 -1
  76. package/out/runtime/loader.d.ts.map +1 -1
  77. package/out/runtime/loader.js +70 -7
  78. package/out/runtime/loader.js.map +1 -1
  79. package/out/runtime/logger.d.ts.map +1 -1
  80. package/out/runtime/logger.js +8 -1
  81. package/out/runtime/logger.js.map +1 -1
  82. package/out/runtime/module.d.ts +18 -0
  83. package/out/runtime/module.d.ts.map +1 -1
  84. package/out/runtime/module.js +91 -3
  85. package/out/runtime/module.js.map +1 -1
  86. package/out/runtime/modules/ai.d.ts +16 -5
  87. package/out/runtime/modules/ai.d.ts.map +1 -1
  88. package/out/runtime/modules/ai.js +286 -88
  89. package/out/runtime/modules/ai.js.map +1 -1
  90. package/out/runtime/modules/core.d.ts.map +1 -1
  91. package/out/runtime/modules/core.js +5 -1
  92. package/out/runtime/modules/core.js.map +1 -1
  93. package/out/runtime/monitor.d.ts +6 -0
  94. package/out/runtime/monitor.d.ts.map +1 -1
  95. package/out/runtime/monitor.js +21 -1
  96. package/out/runtime/monitor.js.map +1 -1
  97. package/out/runtime/relgraph.d.ts.map +1 -1
  98. package/out/runtime/relgraph.js +7 -3
  99. package/out/runtime/relgraph.js.map +1 -1
  100. package/out/runtime/resolvers/interface.d.ts +7 -2
  101. package/out/runtime/resolvers/interface.d.ts.map +1 -1
  102. package/out/runtime/resolvers/interface.js +17 -3
  103. package/out/runtime/resolvers/interface.js.map +1 -1
  104. package/out/runtime/resolvers/sqldb/database.d.ts +2 -0
  105. package/out/runtime/resolvers/sqldb/database.d.ts.map +1 -1
  106. package/out/runtime/resolvers/sqldb/database.js +142 -126
  107. package/out/runtime/resolvers/sqldb/database.js.map +1 -1
  108. package/out/runtime/resolvers/sqldb/dbutil.d.ts.map +1 -1
  109. package/out/runtime/resolvers/sqldb/dbutil.js +25 -4
  110. package/out/runtime/resolvers/sqldb/dbutil.js.map +1 -1
  111. package/out/runtime/resolvers/sqldb/impl.d.ts +2 -1
  112. package/out/runtime/resolvers/sqldb/impl.d.ts.map +1 -1
  113. package/out/runtime/resolvers/sqldb/impl.js +24 -7
  114. package/out/runtime/resolvers/sqldb/impl.js.map +1 -1
  115. package/out/runtime/resolvers/vector/lancedb-store.d.ts +16 -0
  116. package/out/runtime/resolvers/vector/lancedb-store.d.ts.map +1 -0
  117. package/out/runtime/resolvers/vector/lancedb-store.js +159 -0
  118. package/out/runtime/resolvers/vector/lancedb-store.js.map +1 -0
  119. package/out/runtime/resolvers/vector/types.d.ts +32 -0
  120. package/out/runtime/resolvers/vector/types.d.ts.map +1 -0
  121. package/out/runtime/resolvers/vector/types.js +2 -0
  122. package/out/runtime/resolvers/vector/types.js.map +1 -0
  123. package/out/runtime/services/documentFetcher.d.ts.map +1 -1
  124. package/out/runtime/services/documentFetcher.js +21 -6
  125. package/out/runtime/services/documentFetcher.js.map +1 -1
  126. package/out/runtime/state.d.ts +19 -1
  127. package/out/runtime/state.d.ts.map +1 -1
  128. package/out/runtime/state.js +36 -1
  129. package/out/runtime/state.js.map +1 -1
  130. package/out/runtime/util.d.ts +3 -2
  131. package/out/runtime/util.d.ts.map +1 -1
  132. package/out/runtime/util.js +13 -2
  133. package/out/runtime/util.js.map +1 -1
  134. package/out/syntaxes/agentlang.monarch.js +1 -1
  135. package/out/syntaxes/agentlang.monarch.js.map +1 -1
  136. package/out/test-harness.d.ts +36 -0
  137. package/out/test-harness.d.ts.map +1 -0
  138. package/out/test-harness.js +341 -0
  139. package/out/test-harness.js.map +1 -0
  140. package/package.json +22 -19
  141. package/src/api/http.ts +336 -38
  142. package/src/cli/main.ts +3 -0
  143. package/src/language/agentlang-validator.ts +3 -0
  144. package/src/language/agentlang.langium +6 -2
  145. package/src/language/error-reporter.ts +1028 -0
  146. package/src/language/generated/ast.ts +94 -1
  147. package/src/language/generated/grammar.ts +342 -206
  148. package/src/language/parser.ts +64 -101
  149. package/src/language/syntax.ts +79 -24
  150. package/src/runtime/api.ts +36 -0
  151. package/src/runtime/datefns.ts +112 -0
  152. package/src/runtime/defs.ts +2 -1
  153. package/src/runtime/document-retriever.ts +311 -0
  154. package/src/runtime/embeddings/chunker.ts +52 -14
  155. package/src/runtime/embeddings/openai.ts +27 -9
  156. package/src/runtime/embeddings/provider.ts +22 -1
  157. package/src/runtime/exec-graph.ts +23 -2
  158. package/src/runtime/integration-client.ts +158 -0
  159. package/src/runtime/integrations.ts +20 -11
  160. package/src/runtime/interpreter.ts +221 -15
  161. package/src/runtime/loader.ts +83 -5
  162. package/src/runtime/logger.ts +12 -1
  163. package/src/runtime/module.ts +104 -3
  164. package/src/runtime/modules/ai.ts +341 -107
  165. package/src/runtime/modules/core.ts +5 -1
  166. package/src/runtime/monitor.ts +27 -1
  167. package/src/runtime/relgraph.ts +7 -3
  168. package/src/runtime/resolvers/interface.ts +23 -3
  169. package/src/runtime/resolvers/sqldb/database.ts +158 -130
  170. package/src/runtime/resolvers/sqldb/dbutil.ts +28 -6
  171. package/src/runtime/resolvers/sqldb/impl.ts +25 -7
  172. package/src/runtime/resolvers/vector/lancedb-store.ts +187 -0
  173. package/src/runtime/resolvers/vector/types.ts +39 -0
  174. package/src/runtime/services/documentFetcher.ts +21 -6
  175. package/src/runtime/state.ts +40 -1
  176. package/src/runtime/util.ts +19 -2
  177. package/src/syntaxes/agentlang.monarch.ts +1 -1
  178. package/src/test-harness.ts +423 -0
package/README.md CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  <div align="center">
3
2
 
4
3
  <p>
@@ -25,18 +24,20 @@
25
24
  <a href="https://github.com/agentlang-ai/agentlang/tree/main/example"><img src="https://img.shields.io/badge/Examples-Page-yellow?logo=homepage&logoColor=yellow&style=for-the-badge"></a>
26
25
 
27
26
  [![Node Version](https://img.shields.io/badge/node-%3E%3D20.0.0-brightgreen?logo=node.js)](https://nodejs.org) [![CI](https://github.com/agentlang-ai/agentlang/actions/workflows/ci.yml/badge.svg)](https://github.com/agentlang-ai/agentlang/actions/workflows/ci.yml)![License](https://img.shields.io/badge/License-Sustainable%20Use%20v1.0-blue.svg) [![npm downloads](https://img.shields.io/npm/dm/agentlang.svg)](https://www.npmjs.com/package/agentlang)
27
+
28
28
  <hr>
29
29
 
30
30
  ## Agentlang - Team as Code
31
+
31
32
  </div>
32
33
 
33
34
  Agentlang is a declarative DSL (built on TypeScript) for creating AI Agents and full-stack Agentic Apps. With Agentlang, you define, version, run, mentor, and monitor teams of AI agents, along with the app infrastructure they need: data model, workflows, RBAC, integrations, and UI. We refer to this approach - bringing together AI agent development and App development into a single coherent discipline - as Team-as-Code (our riff on IaC).
34
35
 
35
- * **For Devs and Non-Devs:** Code and vibe-code in your IDE, focusing on the business-logic of your app, not wiring. Alternatively, you can build, run, mentor and monitor your AI Team in Studio - our visual-builder (coming soon). Switch back-and-forth between the two modes seamlessly.
36
+ - **For Devs and Non-Devs:** Code and vibe-code in your IDE, focusing on the business-logic of your app, not wiring. Alternatively, you can build, run, mentor and monitor your AI Team in Studio - our visual-builder (coming soon). Switch back-and-forth between the two modes seamlessly.
36
37
 
37
- * **Robust Integrations:** The Agentlang runtime ships with native integrations for LLMs, databases, vector DBs, and auth providers. Our connector architecture is built for the enterprise, with a rapidly growing catalog for systems like Salesforce, ServiceNow, HubSpot, Snowflake, and more. Also, because Agentlang compiles to Node.js (and runs in the browser), you can use any existing JavaScript library out of the box.
38
+ - **Robust Integrations:** The Agentlang runtime ships with native integrations for LLMs, databases, vector DBs, and auth providers. Our connector architecture is built for the enterprise, with a rapidly growing catalog for systems like Salesforce, ServiceNow, HubSpot, Snowflake, and more. Also, because Agentlang compiles to Node.js (and runs in the browser), you can use any existing JavaScript library out of the box.
38
39
 
39
- * **Production-grade**: Under the hood, it’s all modern TypeScript—strong typing, tooling, testing, and CI/CD-friendly workflows—built for enterprise-class reliability, governance, and scale.
40
+ - **Production-grade**: Under the hood, it’s all modern TypeScript—strong typing, tooling, testing, and CI/CD-friendly workflows—built for enterprise-class reliability, governance, and scale.
40
41
 
41
42
  Agentlang introduces two foundational innovations: [Agentic Reliability Modeling](#-agentic-reliability-modeling) and [AgentLang Ontology](#agentlang-ontology)
42
43
 
@@ -132,7 +133,6 @@ workflow ticketInProgress {
132
133
  }
133
134
  ```
134
135
 
135
-
136
136
  ### ✨ First-class AI Agents
137
137
 
138
138
  Agents and many concepts agents use are built-in language constructs.
@@ -328,8 +328,8 @@ What makes this model special is how seamlessly an agent can interact with it
328
328
 
329
329
  To get started with Agentlang Ontology, please see the [Agentlang Tutorial](https://docs.fractl.io/app) or explore the following example applications:
330
330
 
331
- * [Car Dealership](https://github.com/agentlang-ai/agentlang/tree/main/example/car_dealership)
332
- * [Customer Support System](https://github.com/agentlang-ai/agentlang/tree/main/example/customer_support_system)
331
+ - [Car Dealership](https://github.com/agentlang-ai/agentlang/tree/main/example/car_dealership)
332
+ - [Customer Support System](https://github.com/agentlang-ai/agentlang/tree/main/example/customer_support_system)
333
333
 
334
334
  ## 🚀 Getting Started
335
335
 
@@ -363,14 +363,7 @@ For contributors who want to build and develop Agentlang itself:
363
363
  ```shell
364
364
  # Install dependencies
365
365
  npm install
366
-
367
- OR
368
-
369
- # Install pnpm: https://pnpm.io/installation
370
- # Use pnpm
371
- pnpm install
372
366
  ```
373
- **Note**: If pnpm shows build script warnings, run `pnpm approve-builds` and approve esbuild and sqlite3.
374
367
 
375
368
  ### ⚡ Build
376
369
 
package/out/api/http.d.ts CHANGED
@@ -1,4 +1,8 @@
1
+ import { Express } from 'express';
2
+ import { InstanceAttributes } from '../runtime/module.js';
1
3
  import { ApplicationSpec } from '../runtime/loader.js';
2
4
  import { Config } from '../runtime/state.js';
5
+ export declare function createApp(appSpec: ApplicationSpec, config?: Config): Promise<Express>;
3
6
  export declare function startServer(appSpec: ApplicationSpec, port: number, host?: string, config?: Config): Promise<void>;
7
+ export declare function patternFromAttributes(moduleName: string, recName: string, attrs: InstanceAttributes, entityFqName?: string): string;
4
8
  //# sourceMappingURL=http.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/api/http.ts"],"names":[],"mappings":"AAwBA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AA8BvD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAO7C,wBAAsB,WAAW,CAC/B,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,iBAgQhB"}
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/api/http.ts"],"names":[],"mappings":"AACA,OAAgB,EAAE,OAAO,EAAqB,MAAM,SAAS,CAAC;AAE9D,OAAO,EAKL,kBAAkB,EAcnB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AA8BvD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAc7C,wBAAsB,SAAS,CAAC,OAAO,EAAE,eAAe,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAqU3F;AAED,wBAAsB,WAAW,CAC/B,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,iBAyBhB;AAuDD,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,kBAAkB,EACzB,YAAY,CAAC,EAAE,MAAM,GACpB,MAAM,CA8BR"}
package/out/api/http.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import chalk from 'chalk';
2
2
  import express from 'express';
3
3
  import * as path from 'path';
4
- import { getAllChildRelationships, getAllEntityNames, getAllEventNames, Instance, isBetweenRelationship, makeInstance, objectAsInstanceAttributes, fetchModule, getModuleNames, Record, fetchRefTarget, getAttributeNames, getAllBetweenRelationshipNames, linkInstancesEvent, } from '../runtime/module.js';
4
+ import { getAllChildRelationships, getAllEntityNames, getAllEventNames, Instance, isBetweenRelationship, getRelationship, makeInstance, objectAsInstanceAttributes, fetchModule, getModuleNames, Record, fetchRefTarget, getAttributeNames, getAllBetweenRelationshipNames, linkInstancesEvent, } from '../runtime/module.js';
5
5
  import { isNodeEnv } from '../utils/runtime.js';
6
6
  import { parseAndEvaluateStatement } from '../runtime/interpreter.js';
7
7
  import { logger } from '../runtime/logger.js';
@@ -11,7 +11,11 @@ import { escapeFqName, forceAsEscapedName, forceAsFqName, isString, isStringNume
11
11
  import { BadRequestError, isPathAttribute, PathAttributeNameQuery, setEntityEndpointsUpdater, setEventEndpointsUpdater, setRelationshipEndpointsUpdater, UnauthorisedError, } from '../runtime/defs.js';
12
12
  import { evaluate } from '../runtime/interpreter.js';
13
13
  import { findFileByFilename, createFileRecord, deleteFileRecord, } from '../runtime/modules/files.js';
14
- export async function startServer(appSpec, port, host, config) {
14
+ import { getOAuthAuthorizeUrl, exchangeOAuthCode, getIntegrationAccessToken, } from '../runtime/integration-client.js';
15
+ import * as XLSX from 'xlsx';
16
+ import { objectToQueryPattern } from '../language/parser.js';
17
+ export async function createApp(appSpec, config) {
18
+ var _a;
15
19
  const app = express();
16
20
  app.use(express.json());
17
21
  // Add CORS middleware
@@ -123,6 +127,85 @@ export async function startServer(appSpec, port, host, config) {
123
127
  app.get('/meta', (req, res) => {
124
128
  handleMetaGet(req, res);
125
129
  });
130
+ app.post('/agentlang/QueryAsCsv', (req, res) => {
131
+ handleQueryAsCsvPost(req, res);
132
+ });
133
+ app.post('/agentlang/QueryAsXlsx', (req, res) => {
134
+ handleQueryAsXlsxPost(req, res);
135
+ });
136
+ // --- Built-in OAuth proxy ---
137
+ if ((_a = config === null || config === void 0 ? void 0 : config.integrations) === null || _a === void 0 ? void 0 : _a.oauth) {
138
+ const connections = config.integrations.connections;
139
+ // Resolve provider key (e.g. 'google_drive') to integration entity name
140
+ // (e.g. 'google-drive') by extracting from the config path.
141
+ function resolveIntegrationName(provider) {
142
+ const entry = connections[provider];
143
+ if (!entry)
144
+ return provider;
145
+ const configPath = typeof entry === 'string' ? entry : entry.config;
146
+ if (!configPath)
147
+ return provider;
148
+ return configPath.split('/')[0];
149
+ }
150
+ app.get('/agentlang/oauth/authorize-url', async (req, res) => {
151
+ try {
152
+ const provider = req.query.provider;
153
+ const redirectUri = req.query.redirectUri;
154
+ if (!provider || !redirectUri) {
155
+ res.status(400).json({ error: 'provider and redirectUri query params are required' });
156
+ return;
157
+ }
158
+ if (!connections[provider]) {
159
+ res.status(400).json({ error: `Unknown provider: ${provider}` });
160
+ return;
161
+ }
162
+ const result = await getOAuthAuthorizeUrl(resolveIntegrationName(provider), redirectUri);
163
+ res.json(result);
164
+ }
165
+ catch (err) {
166
+ logger.error(`OAuth authorize-url error: ${err}`);
167
+ res.status(500).json({ error: err.message || 'Failed to get authorization URL' });
168
+ }
169
+ });
170
+ app.post('/agentlang/oauth/exchange', async (req, res) => {
171
+ try {
172
+ const { provider, code, state } = req.body;
173
+ if (!provider || !code || !state) {
174
+ res.status(400).json({ error: 'provider, code, and state are required in request body' });
175
+ return;
176
+ }
177
+ if (!connections[provider]) {
178
+ res.status(400).json({ error: `Unknown provider: ${provider}` });
179
+ return;
180
+ }
181
+ const result = await exchangeOAuthCode(resolveIntegrationName(provider), code, state);
182
+ res.json(result);
183
+ }
184
+ catch (err) {
185
+ logger.error(`OAuth exchange error: ${err}`);
186
+ res.status(500).json({ error: err.message || 'Failed to exchange authorization code' });
187
+ }
188
+ });
189
+ app.get('/agentlang/oauth/access-token', async (req, res) => {
190
+ try {
191
+ const provider = req.query.provider;
192
+ if (!provider) {
193
+ res.status(400).json({ error: 'provider query param is required' });
194
+ return;
195
+ }
196
+ if (!connections[provider]) {
197
+ res.status(400).json({ error: `Unknown provider: ${provider}` });
198
+ return;
199
+ }
200
+ const result = await getIntegrationAccessToken(resolveIntegrationName(provider));
201
+ res.json(result);
202
+ }
203
+ catch (err) {
204
+ logger.error(`OAuth access-token error: ${err}`);
205
+ res.status(500).json({ error: err.message || 'Failed to get access token' });
206
+ }
207
+ });
208
+ }
126
209
  if (isNodeEnv && upload && uploadDir) {
127
210
  app.post('/uploadFile', upload.single('file'), (req, res) => {
128
211
  handleFileUpload(req, res, config);
@@ -201,15 +284,6 @@ export async function startServer(appSpec, port, host, config) {
201
284
  addBetweenHandlers(moduleName, n);
202
285
  });
203
286
  });
204
- const cb = () => {
205
- console.log(chalk.green(`Application ${chalk.bold(appName + ' version ' + appVersion)} started on port ${chalk.bold(port)}`));
206
- };
207
- if (host) {
208
- app.listen(port, host, cb);
209
- }
210
- else {
211
- app.listen(port, cb);
212
- }
213
287
  setEventEndpointsUpdater((moduleName) => {
214
288
  const m = fetchModule(moduleName);
215
289
  const eventNames = m.getEventNames();
@@ -231,6 +305,27 @@ export async function startServer(appSpec, port, host, config) {
231
305
  addBetweenHandlers(moduleName, n);
232
306
  });
233
307
  });
308
+ return app;
309
+ }
310
+ export async function startServer(appSpec, port, host, config) {
311
+ const app = await createApp(appSpec, config);
312
+ const appName = appSpec.name;
313
+ const appVersion = appSpec.version;
314
+ // Expose port and host on globalThis so resolver code (e.g. integration-manager's
315
+ // auth-resolver) can make self-referencing HTTP calls to the correct address.
316
+ globalThis.__agentlang_port = port;
317
+ if (host) {
318
+ globalThis.__agentlang_host = host;
319
+ }
320
+ const cb = () => {
321
+ console.log(chalk.green(`Application ${chalk.bold(appName + ' version ' + appVersion)} started on port ${chalk.bold(port)}`));
322
+ };
323
+ if (host) {
324
+ app.listen(port, host, cb);
325
+ }
326
+ else {
327
+ app.listen(port, cb);
328
+ }
234
329
  }
235
330
  function ok(res) {
236
331
  return (value) => {
@@ -256,19 +351,62 @@ function internalError(res) {
256
351
  res.status(statusFromErrorType(reason)).send(reason.message);
257
352
  };
258
353
  }
259
- function patternFromAttributes(moduleName, recName, attrs) {
354
+ function formatAttrValue(v, n) {
355
+ let av = isString(v) ? `"${v}"` : v;
356
+ if (av instanceof Object) {
357
+ av = JSON.stringify(av);
358
+ }
359
+ if (isPathAttribute(n)) {
360
+ av = escapeSepInPath(av);
361
+ }
362
+ return `${n} ${av}`;
363
+ }
364
+ function buildChildPattern(otherFqName, childObj) {
365
+ const childAttrs = Object.entries(childObj)
366
+ .map(([k, v]) => {
367
+ let av;
368
+ if (isString(v)) {
369
+ av = `"${v}"`;
370
+ }
371
+ else if (v instanceof Object) {
372
+ av = JSON.stringify(v);
373
+ }
374
+ else {
375
+ av = v;
376
+ }
377
+ return `${k} ${av}`;
378
+ })
379
+ .join(', ');
380
+ return `{${otherFqName} {${childAttrs}}, @upsert}`;
381
+ }
382
+ export function patternFromAttributes(moduleName, recName, attrs, entityFqName) {
260
383
  const attrsStrs = new Array();
384
+ const relPatterns = new Array();
261
385
  attrs.forEach((v, n) => {
262
- let av = isString(v) ? `"${v}"` : v;
263
- if (av instanceof Object) {
264
- av = JSON.stringify(av);
265
- }
266
- if (isPathAttribute(n)) {
267
- av = escapeSepInPath(av);
386
+ if (entityFqName) {
387
+ try {
388
+ if (isBetweenRelationship(n, moduleName)) {
389
+ const rel = getRelationship(n, moduleName);
390
+ const otherFqName = rel.getParentFqName() === entityFqName ? rel.getChildFqName() : rel.getParentFqName();
391
+ const children = Array.isArray(v) ? v : [v];
392
+ const childPatterns = children
393
+ .map((child) => buildChildPattern(otherFqName, child))
394
+ .join(', ');
395
+ relPatterns.push(`${n} [${childPatterns}]`);
396
+ return;
397
+ }
398
+ }
399
+ catch (_a) {
400
+ // Not a relationship — fall through to normal attribute handling
401
+ }
268
402
  }
269
- attrsStrs.push(`${n} ${av}`);
403
+ attrsStrs.push(formatAttrValue(v, n));
270
404
  });
271
- return `{${moduleName}/${recName} { ${attrsStrs.join(',\n')} }}`;
405
+ const entityPat = `{${moduleName}/${recName} {${attrsStrs.join(',\n')}}`;
406
+ if (relPatterns.length > 0) {
407
+ return `${entityPat}, ${relPatterns.join(', ')}}`;
408
+ }
409
+ return `${entityPat}}`;
272
410
  }
273
411
  function normalizeRequestPath(path, moduleName) {
274
412
  if (path.length <= 1) {
@@ -318,7 +456,7 @@ async function handleEventPost(moduleName, eventName, req, res) {
318
456
  return;
319
457
  }
320
458
  const inst = makeInstance(moduleName, eventName, objectAsInstanceAttributes(req.body)).setAuthContext(sessionInfo);
321
- evaluate(inst, ok(res)).catch(internalError(res));
459
+ evaluate(inst).then(ok(res)).catch(internalError(res));
322
460
  }
323
461
  catch (err) {
324
462
  logger.error(err);
@@ -332,9 +470,10 @@ async function handleEntityPost(moduleName, entityName, req, res) {
332
470
  res.status(401).send('Authorization required');
333
471
  return;
334
472
  }
473
+ const entityFqName = makeFqName(moduleName, entityName);
335
474
  const pattern = req.params.path
336
475
  ? createChildPattern(moduleName, entityName, req)
337
- : patternFromAttributes(moduleName, entityName, objectAsInstanceAttributes(req.body));
476
+ : patternFromAttributes(moduleName, entityName, objectAsInstanceAttributes(req.body), entityFqName);
338
477
  parseAndEvaluateStatement(pattern, sessionInfo.userId).then(ok(res)).catch(internalError(res));
339
478
  }
340
479
  catch (err) {
@@ -368,16 +507,24 @@ const joinTags = new Map()
368
507
  .set('@joinOn', '@join')
369
508
  .set('@leftJoinOn', '@left_join')
370
509
  .set('@rightJoinOn', '@right_join');
510
+ const paginationTags = new Set(['@limit', '@offset']);
371
511
  function objectAsAttributesPattern(entityFqName, obj) {
372
512
  const attrs = new Array();
373
513
  let joinType;
374
514
  let joinOnAttr;
515
+ const paginationParts = new Array();
375
516
  Object.keys(obj).forEach(key => {
376
517
  const s = obj[key];
377
518
  if (joinTags.has(key)) {
378
519
  joinType = joinTags.get(key);
379
520
  joinOnAttr = s;
380
521
  }
522
+ else if (paginationTags.has(key)) {
523
+ const n = parseInt(s, 10);
524
+ if (!Number.isNaN(n) && Number.isInteger(n) && n >= 0) {
525
+ paginationParts.push(`${key}(${n})`);
526
+ }
527
+ }
381
528
  else {
382
529
  let v = s;
383
530
  if (!s.startsWith('"')) {
@@ -405,13 +552,19 @@ function objectAsAttributesPattern(entityFqName, obj) {
405
552
  });
406
553
  const intoPat = `@into {${intoSpec.join(', ')}}`;
407
554
  joinOnAttr = reverseJoin ? splitRefs(joinOnAttr)[1] : joinOnAttr;
555
+ const paginationStr = paginationParts.length > 0 ? `,\n${paginationParts.join(',\n')}` : '';
408
556
  return [
409
- `${pat},\n${joinType} ${targetEntity} {${targetAttr}? ${entityFqName}.${joinOnAttr}}, \n${intoPat}`,
557
+ `${pat},\n${joinType} ${targetEntity} {${targetAttr}? ${entityFqName}.${joinOnAttr}}, \n${intoPat}${paginationStr}`,
410
558
  hasQueryAttrs,
559
+ '',
411
560
  ];
412
561
  }
413
562
  else {
414
- return [pat, hasQueryAttrs];
563
+ return [
564
+ pat,
565
+ hasQueryAttrs,
566
+ paginationParts.length > 0 ? `,\n${paginationParts.join(',\n')}` : '',
567
+ ];
415
568
  }
416
569
  }
417
570
  function queryPatternFromPath(path, req) {
@@ -423,9 +576,9 @@ function queryPatternFromPath(path, req) {
423
576
  const fqName = `${moduleName}/${entityName}`;
424
577
  if (parts.length == 2 && id === undefined) {
425
578
  if (req.query && Object.keys(req.query).length > 0) {
426
- const [pat, hasQueryAttrs] = objectAsAttributesPattern(fqName, req.query);
579
+ const [pat, hasQueryAttrs, paginationPat] = objectAsAttributesPattern(fqName, req.query);
427
580
  const n = hasQueryAttrs ? fqName : `${fqName}?`;
428
- return `{${n} ${pat}}`;
581
+ return `{${n} ${pat}${paginationPat}}`;
429
582
  }
430
583
  else {
431
584
  return `{${fqName}? {}}`;
@@ -578,6 +731,66 @@ function normalizedResult(r) {
578
731
  return r;
579
732
  }
580
733
  }
734
+ /**
735
+ * Converts eval result to an array of flat row objects for CSV/XLSX.
736
+ * Handles:
737
+ * - [{ "EntityName": { "attr": "attrval" } }, ...] -> one row per item, columns = Entity + attrs
738
+ * - [{ "attr": "attrval" }, ...] -> one row per item, columns = attrs
739
+ * - [[ { "EntityName": { ... } }, ... ]] -> unwrap single outer array, then one row per inner item
740
+ */
741
+ function evalResultToRows(data) {
742
+ let items;
743
+ if (Array.isArray(data) && data.length === 1 && Array.isArray(data[0])) {
744
+ items = data[0];
745
+ }
746
+ else {
747
+ items = Array.isArray(data) ? data : [data];
748
+ }
749
+ return items.map((item) => {
750
+ if (item === null || typeof item !== 'object') {
751
+ return { value: item };
752
+ }
753
+ if (Array.isArray(item)) {
754
+ return { value: item };
755
+ }
756
+ const obj = item;
757
+ const keys = Object.keys(obj);
758
+ if (keys.length === 1) {
759
+ const [k] = keys;
760
+ const v = obj[k];
761
+ if (v !== null &&
762
+ typeof v === 'object' &&
763
+ !Array.isArray(v) &&
764
+ Object.prototype.toString.call(v) === '[object Object]') {
765
+ return Object.assign({}, v);
766
+ }
767
+ }
768
+ return Object.assign({}, obj);
769
+ });
770
+ }
771
+ /**
772
+ * Ensures cell value is stringifiable for CSV/XLSX (nested objects/arrays become JSON string).
773
+ */
774
+ function cellValue(val) {
775
+ if (val === null || val === undefined)
776
+ return '';
777
+ if (typeof val === 'object')
778
+ return JSON.stringify(val);
779
+ return val;
780
+ }
781
+ /**
782
+ * Parses column names from the first instance and returns an array-of-arrays
783
+ * for the sheet: first row = column names, following rows = data. This ensures
784
+ * CSV/XLSX output has proper headers (col1, col2, ...) not 0, 1, 2, ...
785
+ */
786
+ function rowsToSheetAoa(rows) {
787
+ if (rows.length === 0)
788
+ return [];
789
+ const columns = Object.keys(rows[0]);
790
+ const headerRow = columns;
791
+ const dataRows = rows.map(row => columns.map(col => cellValue(row[col])));
792
+ return [headerRow, ...dataRows];
793
+ }
581
794
  async function handleMetaGet(req, res) {
582
795
  try {
583
796
  const sessionInfo = await verifyAuth('', '', req.headers.authorization);
@@ -781,6 +994,74 @@ async function handleMetaGet(req, res) {
781
994
  res.status(500).send(err.toString());
782
995
  }
783
996
  }
997
+ async function handleQueryAsCsvPost(req, res) {
998
+ var _a, _b;
999
+ try {
1000
+ const sessionInfo = await verifyAuth('', '', req.headers.authorization);
1001
+ if (isNoSession(sessionInfo)) {
1002
+ res.status(401).send('Authorization required');
1003
+ return;
1004
+ }
1005
+ const q = (_a = req.body) === null || _a === void 0 ? void 0 : _a.q;
1006
+ if (q === undefined) {
1007
+ res.status(400).send('Missing or invalid pattern');
1008
+ return;
1009
+ }
1010
+ const qs = objectToQueryPattern(q);
1011
+ const result = await parseAndEvaluateStatement(qs, sessionInfo.userId);
1012
+ const normalized = normalizedResult(result);
1013
+ const rows = evalResultToRows(normalized);
1014
+ const aoa = rowsToSheetAoa(rows);
1015
+ const worksheet = XLSX.utils.aoa_to_sheet(aoa);
1016
+ const workbook = XLSX.utils.book_new();
1017
+ XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
1018
+ const buffer = XLSX.write(workbook, { type: 'buffer', bookType: 'csv' });
1019
+ const filename = `eval-${Date.now()}.csv`;
1020
+ res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
1021
+ res.contentType('text/csv');
1022
+ res.send(buffer);
1023
+ }
1024
+ catch (err) {
1025
+ logger.error(err);
1026
+ if (!res.headersSent) {
1027
+ res.status(statusFromErrorType(err)).send((_b = err === null || err === void 0 ? void 0 : err.message) !== null && _b !== void 0 ? _b : err === null || err === void 0 ? void 0 : err.toString());
1028
+ }
1029
+ }
1030
+ }
1031
+ async function handleQueryAsXlsxPost(req, res) {
1032
+ var _a, _b;
1033
+ try {
1034
+ const sessionInfo = await verifyAuth('', '', req.headers.authorization);
1035
+ if (isNoSession(sessionInfo)) {
1036
+ res.status(401).send('Authorization required');
1037
+ return;
1038
+ }
1039
+ const q = (_a = req.body) === null || _a === void 0 ? void 0 : _a.q;
1040
+ if (q === undefined) {
1041
+ res.status(400).send('Missing or invalid pattern');
1042
+ return;
1043
+ }
1044
+ const qs = objectToQueryPattern(q);
1045
+ const result = await parseAndEvaluateStatement(qs, sessionInfo.userId);
1046
+ const normalized = normalizedResult(result);
1047
+ const rows = evalResultToRows(normalized);
1048
+ const aoa = rowsToSheetAoa(rows);
1049
+ const worksheet = XLSX.utils.aoa_to_sheet(aoa);
1050
+ const workbook = XLSX.utils.book_new();
1051
+ XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
1052
+ const buffer = XLSX.write(workbook, { type: 'buffer', bookType: 'xlsx' });
1053
+ const filename = `eval-${Date.now()}.xlsx`;
1054
+ res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
1055
+ res.contentType('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
1056
+ res.send(buffer);
1057
+ }
1058
+ catch (err) {
1059
+ logger.error(err);
1060
+ if (!res.headersSent) {
1061
+ res.status(statusFromErrorType(err)).send((_b = err === null || err === void 0 ? void 0 : err.message) !== null && _b !== void 0 ? _b : err === null || err === void 0 ? void 0 : err.toString());
1062
+ }
1063
+ }
1064
+ }
784
1065
  async function handleFileUpload(req, res, config) {
785
1066
  var _a;
786
1067
  try {