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
@@ -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 { firstAliasSpec, firstCatchSpec, isString, QuerySuffix } from '../runtime/util.js';
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
- lines?: string[]
124
- ): string[] | undefined {
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
- const sls = new Set<number>();
131
- const scs = new Set<number>();
132
- if (validationErrors.length > 0) {
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
- function trimErrorLines(lines: string[]): string[] {
157
- let startidx = 0;
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 code = document.textDocument.getText();
193
- const lines = code.split('\n');
194
- let hasErrors = false;
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
  }
@@ -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} ${k} ${handler.toString()}\n`;
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
- const a = this.aliasesAsString();
70
- const h = this.handlersAsString();
71
- if (!a && !h) return '';
72
- if (a && !h) return a;
73
- if (!a && h) return h;
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 | undefined {
525
- if (this.into) {
526
- const ss = new Array<string>();
527
- this.into.forEach((attr: string, alias: string) => {
528
- ss.push(`${alias} ${attr}`);
529
- });
530
- return `@into { ${ss.join(',\n')} }`;
531
- }
532
- return undefined;
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
- const ins = this.intoAsString();
546
- if (ins) {
547
- s = s.concat(`,\n${ins}`);
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
  }
@@ -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
+ }
@@ -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 TenantAttributeName: string = '__tenant__';
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);