flowquery 1.0.12 → 1.0.14

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 (60) hide show
  1. package/README.md +3 -3
  2. package/dist/flowquery.min.js +1 -1
  3. package/dist/parsing/functions/aggregate_function.d.ts +1 -1
  4. package/dist/parsing/functions/aggregate_function.d.ts.map +1 -1
  5. package/dist/parsing/functions/aggregate_function.js.map +1 -1
  6. package/dist/parsing/functions/async_function.d.ts +19 -16
  7. package/dist/parsing/functions/async_function.d.ts.map +1 -1
  8. package/dist/parsing/functions/async_function.js +20 -59
  9. package/dist/parsing/functions/async_function.js.map +1 -1
  10. package/dist/parsing/functions/function.d.ts +1 -1
  11. package/dist/parsing/functions/function.d.ts.map +1 -1
  12. package/dist/parsing/functions/function.js +1 -1
  13. package/dist/parsing/functions/function.js.map +1 -1
  14. package/dist/parsing/functions/function_factory.d.ts +2 -0
  15. package/dist/parsing/functions/function_factory.d.ts.map +1 -1
  16. package/dist/parsing/functions/function_factory.js +12 -11
  17. package/dist/parsing/functions/function_factory.js.map +1 -1
  18. package/dist/parsing/functions/function_metadata.d.ts +53 -24
  19. package/dist/parsing/functions/function_metadata.d.ts.map +1 -1
  20. package/dist/parsing/functions/function_metadata.js +55 -45
  21. package/dist/parsing/functions/function_metadata.js.map +1 -1
  22. package/dist/parsing/functions/predicate_function.d.ts +1 -1
  23. package/dist/parsing/functions/predicate_function.d.ts.map +1 -1
  24. package/dist/parsing/functions/predicate_function.js +1 -1
  25. package/dist/parsing/functions/predicate_function.js.map +1 -1
  26. package/dist/parsing/operations/load.d.ts +1 -0
  27. package/dist/parsing/operations/load.d.ts.map +1 -1
  28. package/dist/parsing/operations/load.js +3 -1
  29. package/dist/parsing/operations/load.js.map +1 -1
  30. package/dist/parsing/parser.d.ts.map +1 -1
  31. package/dist/parsing/parser.js +1 -2
  32. package/dist/parsing/parser.js.map +1 -1
  33. package/docs/flowquery.min.js +1 -1
  34. package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
  35. package/misc/apps/RAG/package.json +1 -2
  36. package/misc/apps/RAG/src/components/ChatContainer.tsx +33 -6
  37. package/misc/apps/RAG/src/components/ChatMessage.css +24 -0
  38. package/misc/apps/RAG/src/components/ChatMessage.tsx +51 -2
  39. package/misc/apps/RAG/src/components/FlowQueryAgent.ts +566 -286
  40. package/misc/apps/RAG/src/plugins/index.ts +3 -1
  41. package/misc/apps/RAG/src/plugins/loaders/CatFacts.ts +6 -5
  42. package/misc/apps/RAG/src/plugins/loaders/Form.ts +7 -7
  43. package/misc/apps/RAG/src/plugins/loaders/Llm.ts +14 -14
  44. package/misc/apps/RAG/src/plugins/loaders/MockData.ts +5 -5
  45. package/misc/apps/RAG/src/plugins/loaders/Table.ts +4 -4
  46. package/misc/apps/RAG/src/plugins/loaders/Weather.ts +126 -0
  47. package/misc/apps/RAG/src/prompts/FlowQuerySystemPrompt.ts +4 -0
  48. package/package.json +1 -1
  49. package/src/parsing/functions/aggregate_function.ts +1 -1
  50. package/src/parsing/functions/async_function.ts +20 -51
  51. package/src/parsing/functions/function.ts +2 -2
  52. package/src/parsing/functions/function_factory.ts +18 -9
  53. package/src/parsing/functions/function_metadata.ts +55 -47
  54. package/src/parsing/functions/predicate_function.ts +2 -2
  55. package/src/parsing/operations/load.ts +3 -1
  56. package/src/parsing/parser.ts +2 -1
  57. package/tests/extensibility.test.ts +22 -22
  58. package/tests/parsing/parser.test.ts +2 -2
  59. package/misc/apps/RAG/.env.example +0 -14
  60. package/misc/apps/RAG/src/plugins/loaders/FetchJson.ts +0 -66
@@ -10,13 +10,15 @@
10
10
  import FlowQuery from 'flowquery';
11
11
  import { FunctionMetadata } from 'flowquery/extensibility';
12
12
 
13
- // Import loader classes - the @FunctionDef decorator auto-registers them with FlowQuery
13
+ // Import plugin classes - the @FunctionDef decorator auto-registers them with FlowQuery
14
+ // This step is essential to ensure decorators are executed so that plugins are registered with FlowQuery
14
15
  import './loaders/FetchJson';
15
16
  import './loaders/CatFacts';
16
17
  import './loaders/MockData';
17
18
  import './loaders/Llm';
18
19
  import './loaders/Table';
19
20
  import './loaders/Form';
21
+ import './loaders/Weather';
20
22
 
21
23
  /**
22
24
  * Initialize plugins.
@@ -6,12 +6,12 @@
6
6
  * RETURN fact.text
7
7
  */
8
8
 
9
- import { FunctionDef } from 'flowquery/extensibility';
9
+ import { FunctionDef, AsyncFunction } from 'flowquery/extensibility';
10
10
 
11
11
  const CAT_FACTS_API = 'https://catfact.ninja/facts';
12
12
 
13
13
  /**
14
- * CatFacts loader class - fetches random cat facts from the Cat Facts API.
14
+ * CatFacts class - fetches random cat facts from the Cat Facts API.
15
15
  */
16
16
  @FunctionDef({
17
17
  description: 'Fetches random cat facts from the Cat Facts API (catfact.ninja)',
@@ -38,10 +38,11 @@ const CAT_FACTS_API = 'https://catfact.ninja/facts';
38
38
  "LOAD JSON FROM catFacts(5) AS fact RETURN fact.text, fact.length AS length"
39
39
  ]
40
40
  })
41
- export class CatFactsLoader {
41
+ export class CatFacts extends AsyncFunction {
42
42
  private readonly apiUrl: string;
43
43
 
44
44
  constructor(apiUrl: string = CAT_FACTS_API) {
45
+ super();
45
46
  this.apiUrl = apiUrl;
46
47
  }
47
48
 
@@ -50,7 +51,7 @@ export class CatFactsLoader {
50
51
  *
51
52
  * @param count - Number of cat facts to fetch (default: 1)
52
53
  */
53
- async *fetch(count: number = 1): AsyncGenerator<any, void, unknown> {
54
+ async *generate(count: number = 1): AsyncGenerator<any, void, unknown> {
54
55
  const url = `${this.apiUrl}?limit=${count}`;
55
56
  const response = await fetch(url);
56
57
 
@@ -71,4 +72,4 @@ export class CatFactsLoader {
71
72
  }
72
73
  }
73
74
 
74
- export default CatFactsLoader;
75
+ export default CatFacts;
@@ -1,10 +1,10 @@
1
1
  /**
2
- * Form loader plugin - transforms configuration into Adaptive Card form format.
2
+ * Form plugin - transforms configuration into Adaptive Card form format.
3
3
  *
4
4
  * Adaptive Cards are platform-agnostic UI snippets that can be rendered in
5
5
  * Microsoft Teams, Outlook, Windows, and other applications.
6
6
  *
7
- * This loader creates customizable forms with various input types including:
7
+ * This plugin creates customizable forms with various input types including:
8
8
  * - Text inputs (single and multi-line)
9
9
  * - Number inputs
10
10
  * - Date and time pickers
@@ -22,7 +22,7 @@
22
22
  * RETURN form
23
23
  */
24
24
 
25
- import { FunctionDef } from 'flowquery/extensibility';
25
+ import { FunctionDef, AsyncFunction } from 'flowquery/extensibility';
26
26
 
27
27
  /**
28
28
  * Interface for Adaptive Card structure
@@ -118,7 +118,7 @@ interface FormConfig {
118
118
  }
119
119
 
120
120
  /**
121
- * Form loader - creates customizable Adaptive Card forms.
121
+ * Form class - creates customizable Adaptive Card forms.
122
122
  */
123
123
  @FunctionDef({
124
124
  description: 'Creates a customizable Adaptive Card form with various input types',
@@ -159,7 +159,7 @@ interface FormConfig {
159
159
  "LOAD JSON FROM form('Survey', [{ id: 'rating', type: 'dropdown', label: 'Rating', choices: ['1', '2', '3', '4', '5'] }, { id: 'subscribe', type: 'toggle', label: 'Subscribe', toggleTitle: 'Yes, send me updates' }], { submitButton: { title: 'Submit Survey', style: 'positive' } }) AS form RETURN form"
160
160
  ]
161
161
  })
162
- export class FormLoader {
162
+ export class Form extends AsyncFunction {
163
163
  /**
164
164
  * Creates an Adaptive Card form with the specified fields and configuration.
165
165
  *
@@ -167,7 +167,7 @@ export class FormLoader {
167
167
  * @param fields - Array of field configurations
168
168
  * @param config - Optional form configuration
169
169
  */
170
- async *fetch(
170
+ async *generate(
171
171
  title: string,
172
172
  fields: FormFieldConfig[],
173
173
  config?: FormConfig
@@ -575,4 +575,4 @@ export class FormLoader {
575
575
  }
576
576
  }
577
577
 
578
- export { FormLoader as default };
578
+ export { Form as default };
@@ -9,10 +9,10 @@
9
9
  * LOAD JSON FROM llm('Translate to French: Hello', { model: 'gpt-4o', temperature: 0.3 }) AS response
10
10
  * RETURN response.choices[0].message.content
11
11
  *
12
- * This loader can also be used standalone outside of FlowQuery:
13
- * import { LlmLoader } from './plugins/loaders/Llm';
14
- * const loader = new LlmLoader();
15
- * const response = await loader.complete('What is 2+2?');
12
+ * This class can also be used standalone outside of FlowQuery:
13
+ * import { Llm } from './plugins/loaders/Llm';
14
+ * const llmInstance = new Llm();
15
+ * const response = await llmInstance.complete('What is 2+2?');
16
16
  * console.log(response.choices[0].message.content);
17
17
  */
18
18
 
@@ -78,7 +78,7 @@ export interface LlmResponse {
78
78
  }
79
79
 
80
80
  /**
81
- * LLM Loader class - calls OpenAI-compatible APIs for chat completions.
81
+ * Llm class - calls OpenAI-compatible APIs for chat completions.
82
82
  */
83
83
  @FunctionDef({
84
84
  description: 'Calls OpenAI-compatible chat completion APIs. Supports GPT models and any OpenAI-compatible endpoint.',
@@ -132,7 +132,7 @@ export interface LlmResponse {
132
132
  ],
133
133
  notes: 'Requires API key configured in Settings or passed as apiKey option. Works with any OpenAI-compatible API by setting the apiUrl option.'
134
134
  })
135
- export class LlmLoader {
135
+ export class Llm {
136
136
  private readonly defaultOptions: Partial<LlmOptions>;
137
137
 
138
138
  constructor(defaultOptions: Partial<LlmOptions> = {}) {
@@ -243,8 +243,8 @@ export class LlmLoader {
243
243
  *
244
244
  * @example
245
245
  * ```typescript
246
- * const loader = new LlmLoader();
247
- * const response = await loader.complete('What is the capital of France?');
246
+ * const llmInstance = new Llm();
247
+ * const response = await llmInstance.complete('What is the capital of France?');
248
248
  * console.log(response.choices[0].message.content);
249
249
  * ```
250
250
  */
@@ -281,8 +281,8 @@ export class LlmLoader {
281
281
  *
282
282
  * @example
283
283
  * ```typescript
284
- * const loader = new LlmLoader();
285
- * for await (const chunk of loader.stream('Tell me a story')) {
284
+ * const llmInstance = new Llm();
285
+ * for await (const chunk of llmInstance.stream('Tell me a story')) {
286
286
  * if (chunk.choices?.[0]?.delta?.content) {
287
287
  * process.stdout.write(chunk.choices[0].delta.content);
288
288
  * }
@@ -396,7 +396,7 @@ export class LlmLoader {
396
396
  * ```
397
397
  */
398
398
  export async function llm(prompt: string, options?: LlmOptions): Promise<LlmResponse> {
399
- return new LlmLoader().complete(prompt, options);
399
+ return new Llm().complete(prompt, options);
400
400
  }
401
401
 
402
402
  /**
@@ -419,7 +419,7 @@ export async function llm(prompt: string, options?: LlmOptions): Promise<LlmResp
419
419
  * ```
420
420
  */
421
421
  export async function* llmStream(prompt: string, options?: LlmOptions): AsyncGenerator<any, void, unknown> {
422
- yield* new LlmLoader().stream(prompt, options);
422
+ yield* new Llm().stream(prompt, options);
423
423
  }
424
424
 
425
425
  /**
@@ -430,7 +430,7 @@ export async function* llmStream(prompt: string, options?: LlmOptions): AsyncGen
430
430
  * @returns The text content from the first choice
431
431
  */
432
432
  export function extractContent(response: LlmResponse): string {
433
- return LlmLoader.extractContent(response);
433
+ return Llm.extractContent(response);
434
434
  }
435
435
 
436
- export default LlmLoader;
436
+ export default Llm;
@@ -9,7 +9,7 @@
9
9
  import { FunctionDef } from 'flowquery/extensibility';
10
10
 
11
11
  /**
12
- * MockUsers loader class - generates mock user data for testing.
12
+ * MockUsers class - generates mock user data for testing.
13
13
  */
14
14
  @FunctionDef({
15
15
  description: 'Generates mock user data for testing purposes',
@@ -39,7 +39,7 @@ import { FunctionDef } from 'flowquery/extensibility';
39
39
  "LOAD JSON FROM mockUsers(20) AS user RETURN user WHERE user.active = true"
40
40
  ]
41
41
  })
42
- export class MockUsersLoader {
42
+ export class MockUsers {
43
43
  private readonly firstNames: string[];
44
44
  private readonly lastNames: string[];
45
45
  private readonly domains: string[];
@@ -77,7 +77,7 @@ export class MockUsersLoader {
77
77
  }
78
78
 
79
79
  /**
80
- * MockProducts loader class - generates mock product data for testing.
80
+ * MockProducts class - generates mock product data for testing.
81
81
  */
82
82
  @FunctionDef({
83
83
  description: 'Generates mock product data for testing purposes',
@@ -108,7 +108,7 @@ export class MockUsersLoader {
108
108
  "LOAD JSON FROM mockProducts(50) AS p RETURN p WHERE p.category = 'Electronics'"
109
109
  ]
110
110
  })
111
- export class MockProductsLoader {
111
+ export class MockProducts {
112
112
  private readonly categories: string[];
113
113
  private readonly adjectives: string[];
114
114
  private readonly nouns: string[];
@@ -146,4 +146,4 @@ export class MockProductsLoader {
146
146
  }
147
147
  }
148
148
 
149
- export { MockUsersLoader as default };
149
+ export { MockUsers as default };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Table loader plugin - transforms tabular data into Adaptive Card format.
2
+ * Table plugin - transforms tabular data into Adaptive Card format.
3
3
  *
4
4
  * Adaptive Cards are platform-agnostic UI snippets that can be rendered in
5
5
  * Microsoft Teams, Outlook, Windows, and other applications.
@@ -42,7 +42,7 @@ interface TableRow {
42
42
  }
43
43
 
44
44
  /**
45
- * Table loader - transforms tabular data into an Adaptive Card table format.
45
+ * Table class - transforms tabular data into an Adaptive Card table format.
46
46
  */
47
47
  @FunctionDef({
48
48
  description: 'Transforms tabular data into an Adaptive Card JSON format with a table layout',
@@ -90,7 +90,7 @@ interface TableRow {
90
90
  "LOAD JSON FROM mockProducts(10) AS p WITH collect(p) AS products LOAD JSON FROM table(products, 'Products', ['name', 'price', 'category']) AS card RETURN card"
91
91
  ]
92
92
  })
93
- export class TableLoader {
93
+ export class Table {
94
94
  /**
95
95
  * Transforms data into an Adaptive Card with table layout.
96
96
  *
@@ -268,4 +268,4 @@ export class TableLoader {
268
268
  }
269
269
  }
270
270
 
271
- export { TableLoader as default };
271
+ export { Table as default };
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Example plugin: Fetch weather forecast for a location.
3
+ *
4
+ * Usage in FlowQuery:
5
+ * LOAD JSON FROM weather('Oslo') AS forecast
6
+ * RETURN forecast
7
+ */
8
+
9
+ import { FunctionDef } from 'flowquery/extensibility';
10
+
11
+ const GEOCODING_API = 'https://geocoding-api.open-meteo.com/v1/search';
12
+ const WEATHER_API = 'https://api.met.no/weatherapi/locationforecast/2.0/compact';
13
+
14
+ /**
15
+ * Weather class - fetches weather forecast for a given location.
16
+ */
17
+ @FunctionDef({
18
+ description: 'Fetches weather forecast for a location using Open-Meteo geocoding and MET Norway weather API',
19
+ category: 'async',
20
+ parameters: [
21
+ {
22
+ name: 'location',
23
+ description: 'The name of the location to get weather for (e.g., "Oslo", "New York")',
24
+ type: 'string',
25
+ required: true
26
+ }
27
+ ],
28
+ output: {
29
+ description: 'Weather forecast data point with location and weather parameters',
30
+ type: 'object',
31
+ properties: {
32
+ date: { description: 'ISO 8601 timestamp in UTC', type: 'string' },
33
+ location: { description: 'Name of the location', type: 'string' },
34
+ lat: { description: 'Latitude in decimal degrees', type: 'number' },
35
+ lon: { description: 'Longitude in decimal degrees', type: 'number' },
36
+ temperature: { description: 'Air temperature in celsius', type: 'number' },
37
+ humidity: { description: 'Relative humidity in %', type: 'number' },
38
+ pressure: { description: 'Air pressure at sea level in hPa', type: 'number' },
39
+ cloud_cover: { description: 'Total cloud cover in %', type: 'number' },
40
+ wind_speed: { description: 'Wind speed in m/s', type: 'number' },
41
+ wind_direction: { description: 'Wind direction in degrees (0=N, 90=E, 180=S, 270=W)', type: 'number' },
42
+ precipitation: { description: 'Expected precipitation in mm (next hour if available)', type: 'number' },
43
+ symbol: { description: 'Weather symbol code (e.g., "partlycloudy_day", "rain")', type: 'string' }
44
+ }
45
+ },
46
+ examples: [
47
+ "LOAD JSON FROM weather('Oslo') AS forecast RETURN forecast",
48
+ "LOAD JSON FROM weather('London') AS forecast RETURN forecast[0]"
49
+ ]
50
+ })
51
+ export class Weather {
52
+ private readonly geocodingApiUrl: string;
53
+ private readonly weatherApiUrl: string;
54
+
55
+ constructor(geocodingApiUrl: string = GEOCODING_API, weatherApiUrl: string = WEATHER_API) {
56
+ this.geocodingApiUrl = geocodingApiUrl;
57
+ this.weatherApiUrl = weatherApiUrl;
58
+ }
59
+
60
+ /**
61
+ * Fetches weather forecast for a given location.
62
+ *
63
+ * @param location - The name of the location to get weather for
64
+ */
65
+ async *fetch(location: string): AsyncGenerator<any, void, unknown> {
66
+ // Step 1: Geocode the location name to get lat/lon
67
+ const geocodeUrl = `${this.geocodingApiUrl}?name=${encodeURIComponent(location)}`;
68
+ const geocodeResponse = await fetch(geocodeUrl);
69
+
70
+ if (!geocodeResponse.ok) {
71
+ throw new Error(`Failed to geocode location: ${geocodeResponse.statusText}`);
72
+ }
73
+
74
+ const geocodeData = await geocodeResponse.json();
75
+
76
+ if (!geocodeData.results || geocodeData.results.length === 0) {
77
+ throw new Error(`Location not found: ${location}`);
78
+ }
79
+
80
+ const firstResult = geocodeData.results[0];
81
+ const lat = firstResult.latitude;
82
+ const lon = firstResult.longitude;
83
+
84
+ // Step 2: Fetch weather forecast using lat/lon
85
+ const weatherUrl = `${this.weatherApiUrl}?lat=${lat}&lon=${lon}`;
86
+ const weatherResponse = await fetch(weatherUrl, {
87
+ headers: {
88
+ // MET Norway API requires a User-Agent header
89
+ 'User-Agent': 'FlowQuery-RAG/1.0'
90
+ }
91
+ });
92
+
93
+ if (!weatherResponse.ok) {
94
+ throw new Error(`Failed to fetch weather: ${weatherResponse.statusText}`);
95
+ }
96
+
97
+ const weatherData = await weatherResponse.json();
98
+
99
+ // Transform timeseries into simplified flat records and yield row by row
100
+ const locationName = firstResult.name;
101
+ const timeseries = weatherData.properties?.timeseries || [];
102
+
103
+ for (const entry of timeseries) {
104
+ const instant = entry.data?.instant?.details || {};
105
+ const next1h = entry.data?.next_1_hours || {};
106
+ const next6h = entry.data?.next_6_hours || {};
107
+
108
+ yield {
109
+ date: entry.time,
110
+ location: locationName,
111
+ lat,
112
+ lon,
113
+ temperature: instant.air_temperature,
114
+ humidity: instant.relative_humidity,
115
+ pressure: instant.air_pressure_at_sea_level,
116
+ cloud_cover: instant.cloud_area_fraction,
117
+ wind_speed: instant.wind_speed,
118
+ wind_direction: instant.wind_from_direction,
119
+ precipitation: next1h.details?.precipitation_amount ?? next6h.details?.precipitation_amount ?? null,
120
+ symbol: next1h.summary?.symbol_code ?? next6h.summary?.symbol_code ?? null
121
+ };
122
+ }
123
+ }
124
+ }
125
+
126
+ export default Weather;
@@ -287,6 +287,10 @@ When the user asks a question that doesn't require data fetching (e.g., asking a
287
287
  - Use meaningful aliases in RETURN statements for better readability
288
288
  - Generate the simplest query that fulfills the user's request
289
289
  - If you cannot determine what the user needs, ask clarifying questions (with [NO_QUERY_NEEDED])
290
+ - Do not use order by or coalesce
291
+ - Do not use list comprehension [i for i in ...]
292
+ - Do not use substring function
293
+ - Do not use limit or skip
290
294
 
291
295
  ${FLOWQUERY_LANGUAGE_REFERENCE}
292
296
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flowquery",
3
- "version": "1.0.12",
3
+ "version": "1.0.14",
4
4
  "description": "A declarative query language for data processing pipelines.",
5
5
  "main": "dist/index.node.js",
6
6
  "types": "dist/index.node.d.ts",
@@ -21,7 +21,7 @@ class AggregateFunction extends Function {
21
21
  *
22
22
  * @param name - The function name
23
23
  */
24
- constructor(name: string) {
24
+ constructor(name?: string) {
25
25
  super(name);
26
26
  }
27
27
 
@@ -1,5 +1,5 @@
1
1
  import ASTNode from "../ast_node";
2
- import FunctionFactory from "./function_factory";
2
+ import Function from "./function";
3
3
 
4
4
  /**
5
5
  * Represents an async data provider function call for use in LOAD operations.
@@ -17,26 +17,7 @@ import FunctionFactory from "./function_factory";
17
17
  * }
18
18
  * ```
19
19
  */
20
- class AsyncFunction extends ASTNode {
21
- private _name: string;
22
-
23
- /**
24
- * Creates a new AsyncFunction with the given name.
25
- *
26
- * @param name - The function name (must be registered as an async provider)
27
- */
28
- constructor(name: string) {
29
- super();
30
- this._name = name;
31
- }
32
-
33
- /**
34
- * Gets the function name.
35
- */
36
- public get name(): string {
37
- return this._name;
38
- }
39
-
20
+ class AsyncFunction extends Function {
40
21
  /**
41
22
  * Sets the function parameters.
42
23
  *
@@ -48,47 +29,35 @@ class AsyncFunction extends ASTNode {
48
29
 
49
30
  /**
50
31
  * Evaluates all parameters and returns their values.
32
+ * Used by the framework to pass arguments to generate().
51
33
  *
52
34
  * @returns Array of parameter values
53
35
  */
54
- private getArguments(): any[] {
36
+ public getArguments(): any[] {
55
37
  return this.children.map(child => child.value());
56
38
  }
57
39
 
58
40
  /**
59
- * Executes the async data provider function and yields results.
41
+ * Generates the async data provider function results.
60
42
  *
43
+ * Subclasses override this method with their own typed parameters.
44
+ * The framework automatically evaluates the AST children and spreads
45
+ * them as arguments when calling this method.
46
+ *
47
+ * @param args - Arguments passed from the query (e.g., myFunc(arg1, arg2))
61
48
  * @yields Data items from the async provider
62
49
  * @throws {Error} If the function is not registered as an async provider
50
+ *
51
+ * @example
52
+ * ```typescript
53
+ * // Subclass with typed parameters:
54
+ * async *generate(count: number = 1, filter?: string): AsyncGenerator<any> {
55
+ * // Implementation
56
+ * }
57
+ * ```
63
58
  */
64
- public async *execute(): AsyncGenerator<any, void, unknown> {
65
- const provider = FunctionFactory.getAsyncProvider(this._name);
66
- if (!provider) {
67
- throw new Error(`Async data provider '${this._name}' is not registered`);
68
- }
69
-
70
- const args = this.getArguments();
71
- const result = provider(...args);
72
-
73
- // Check if result is an async generator or a promise
74
- if (result && typeof (result as AsyncGenerator).next === 'function') {
75
- // It's an async generator
76
- yield* result as AsyncGenerator<any, void, unknown>;
77
- } else {
78
- // It's a promise - await and yield the result
79
- const data = await result;
80
- if (Array.isArray(data)) {
81
- for (const item of data) {
82
- yield item;
83
- }
84
- } else {
85
- yield data;
86
- }
87
- }
88
- }
89
-
90
- public toString(): string {
91
- return `AsyncFunction (${this._name})`;
59
+ public async *generate(...args: any[]): AsyncGenerator<any, void, unknown> {
60
+ throw new Error("Not implemented: generate method must be overridden in subclasses.");
92
61
  }
93
62
  }
94
63
 
@@ -22,9 +22,9 @@ class Function extends ASTNode {
22
22
  *
23
23
  * @param name - The function name
24
24
  */
25
- constructor(name: string) {
25
+ constructor(name?: string) {
26
26
  super();
27
- this._name = name;
27
+ this._name = name || this.constructor.name;
28
28
  }
29
29
 
30
30
  /**
@@ -22,9 +22,10 @@ import {
22
22
  getRegisteredFunctionMetadata,
23
23
  getFunctionMetadata,
24
24
  getRegisteredFunctionFactory,
25
- getRegisteredAsyncProvider,
26
25
  AsyncDataProvider
27
26
  } from "./function_metadata";
27
+ import AsyncFunction from "./async_function";
28
+ import { get } from "node:http";
28
29
 
29
30
  // Re-export AsyncDataProvider for backwards compatibility
30
31
  export { AsyncDataProvider };
@@ -50,7 +51,7 @@ class FunctionFactory {
50
51
  * @returns The async data provider, or undefined if not found
51
52
  */
52
53
  public static getAsyncProvider(name: string): AsyncDataProvider | undefined {
53
- return getRegisteredAsyncProvider(name.toLowerCase());
54
+ return getRegisteredFunctionFactory(name.toLowerCase());
54
55
  }
55
56
 
56
57
  /**
@@ -60,7 +61,7 @@ class FunctionFactory {
60
61
  * @returns True if the function is an async data provider
61
62
  */
62
63
  public static isAsyncProvider(name: string): boolean {
63
- return getRegisteredAsyncProvider(name.toLowerCase()) !== undefined;
64
+ return getRegisteredFunctionFactory(name.toLowerCase(), "async") !== undefined;
64
65
  }
65
66
 
66
67
  /**
@@ -123,7 +124,7 @@ class FunctionFactory {
123
124
  * @returns A Function instance of the appropriate type
124
125
  */
125
126
  public static create(name: string): Function {
126
- const lowerName = name.toLowerCase();
127
+ const lowerName: string = name.toLowerCase();
127
128
 
128
129
  // Check decorator-registered functions (built-ins use @FunctionDef)
129
130
  const decoratorFactory = getRegisteredFunctionFactory(lowerName);
@@ -131,8 +132,7 @@ class FunctionFactory {
131
132
  return decoratorFactory();
132
133
  }
133
134
 
134
- // Unknown function - return generic Function instance
135
- return new Function(name);
135
+ throw new Error(`Unknown function: ${name}`);
136
136
  }
137
137
 
138
138
  /**
@@ -143,7 +143,7 @@ class FunctionFactory {
143
143
  * @returns A PredicateFunction instance of the appropriate type
144
144
  */
145
145
  public static createPredicate(name: string): PredicateFunction {
146
- const lowerName = name.toLowerCase();
146
+ const lowerName: string = name.toLowerCase();
147
147
 
148
148
  // Check decorator-registered predicate functions
149
149
  const decoratorFactory = getRegisteredFunctionFactory(lowerName, 'predicate');
@@ -151,9 +151,18 @@ class FunctionFactory {
151
151
  return decoratorFactory();
152
152
  }
153
153
 
154
- // Unknown predicate function - return generic PredicateFunction instance
155
- return new PredicateFunction(name);
154
+ throw new Error(`Unknown predicate function: ${name}`);
156
155
  }
156
+
157
+ public static createAsync(name: string): AsyncFunction {
158
+ const lowerName: string = name.toLowerCase();
159
+ const decoratorFactory = getRegisteredFunctionFactory(lowerName, 'async');
160
+ if (decoratorFactory) {
161
+ return decoratorFactory() as AsyncFunction;
162
+ }
163
+ throw new Error(`Unknown async function: ${name}`);
164
+ }
165
+
157
166
  }
158
167
 
159
168
  export default FunctionFactory;