flowquery 1.0.11 → 1.0.13
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/README.md +142 -38
- package/dist/flowquery.min.js +1 -1
- package/dist/parsing/functions/aggregate_function.d.ts +1 -1
- package/dist/parsing/functions/aggregate_function.d.ts.map +1 -1
- package/dist/parsing/functions/aggregate_function.js.map +1 -1
- package/dist/parsing/functions/async_function.d.ts +4 -15
- package/dist/parsing/functions/async_function.d.ts.map +1 -1
- package/dist/parsing/functions/async_function.js +6 -59
- package/dist/parsing/functions/async_function.js.map +1 -1
- package/dist/parsing/functions/function.d.ts +1 -1
- package/dist/parsing/functions/function.d.ts.map +1 -1
- package/dist/parsing/functions/function.js +1 -1
- package/dist/parsing/functions/function.js.map +1 -1
- package/dist/parsing/functions/function_factory.d.ts +2 -0
- package/dist/parsing/functions/function_factory.d.ts.map +1 -1
- package/dist/parsing/functions/function_factory.js +12 -11
- package/dist/parsing/functions/function_factory.js.map +1 -1
- package/dist/parsing/functions/function_metadata.d.ts +53 -24
- package/dist/parsing/functions/function_metadata.d.ts.map +1 -1
- package/dist/parsing/functions/function_metadata.js +57 -53
- package/dist/parsing/functions/function_metadata.js.map +1 -1
- package/dist/parsing/functions/predicate_function.d.ts +1 -1
- package/dist/parsing/functions/predicate_function.d.ts.map +1 -1
- package/dist/parsing/functions/predicate_function.js +1 -1
- package/dist/parsing/functions/predicate_function.js.map +1 -1
- package/dist/parsing/operations/load.js +1 -1
- package/dist/parsing/operations/load.js.map +1 -1
- package/dist/parsing/parser.d.ts.map +1 -1
- package/dist/parsing/parser.js +1 -2
- package/dist/parsing/parser.js.map +1 -1
- package/docs/flowquery.min.js +1 -1
- package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
- package/misc/apps/RAG/README.md +0 -12
- package/misc/apps/RAG/package.json +1 -2
- package/misc/apps/RAG/src/components/ChatContainer.tsx +33 -6
- package/misc/apps/RAG/src/components/ChatMessage.css +24 -0
- package/misc/apps/RAG/src/components/ChatMessage.tsx +51 -2
- package/misc/apps/RAG/src/components/FlowQueryAgent.ts +566 -286
- package/misc/apps/RAG/src/plugins/index.ts +3 -1
- package/misc/apps/RAG/src/plugins/loaders/CatFacts.ts +6 -5
- package/misc/apps/RAG/src/plugins/loaders/FetchJson.ts +3 -3
- package/misc/apps/RAG/src/plugins/loaders/Form.ts +5 -5
- package/misc/apps/RAG/src/plugins/loaders/Llm.ts +14 -14
- package/misc/apps/RAG/src/plugins/loaders/MockData.ts +5 -5
- package/misc/apps/RAG/src/plugins/loaders/Table.ts +4 -4
- package/misc/apps/RAG/src/plugins/loaders/Weather.ts +126 -0
- package/misc/apps/RAG/src/prompts/FlowQuerySystemPrompt.ts +4 -0
- package/package.json +1 -1
- package/src/parsing/functions/aggregate_function.ts +1 -1
- package/src/parsing/functions/async_function.ts +5 -50
- package/src/parsing/functions/function.ts +2 -2
- package/src/parsing/functions/function_factory.ts +18 -9
- package/src/parsing/functions/function_metadata.ts +57 -56
- package/src/parsing/functions/predicate_function.ts +2 -2
- package/src/parsing/operations/load.ts +1 -1
- package/src/parsing/parser.ts +2 -1
- package/tests/extensibility.test.ts +50 -12
- package/tests/parsing/parser.test.ts +2 -2
- package/misc/apps/RAG/.env.example +0 -14
|
@@ -10,13 +10,15 @@
|
|
|
10
10
|
import FlowQuery from 'flowquery';
|
|
11
11
|
import { FunctionMetadata } from 'flowquery/extensibility';
|
|
12
12
|
|
|
13
|
-
// Import
|
|
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
|
|
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
|
|
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 *
|
|
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
|
|
75
|
+
export default CatFacts;
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import { FunctionDef } from 'flowquery/extensibility';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* FetchJson
|
|
12
|
+
* FetchJson class - fetches JSON data from a URL and yields items.
|
|
13
13
|
*/
|
|
14
14
|
@FunctionDef({
|
|
15
15
|
description: 'Fetches JSON data from a URL. If the response is an array, yields each item individually.',
|
|
@@ -37,7 +37,7 @@ import { FunctionDef } from 'flowquery/extensibility';
|
|
|
37
37
|
"LOAD JSON FROM fetchJson('https://api.example.com/data') AS item RETURN item WHERE item.active = true"
|
|
38
38
|
]
|
|
39
39
|
})
|
|
40
|
-
export class
|
|
40
|
+
export class FetchJson {
|
|
41
41
|
/**
|
|
42
42
|
* Fetches JSON data from a URL and yields each item if array, or the object itself.
|
|
43
43
|
*
|
|
@@ -63,4 +63,4 @@ export class FetchJsonLoader {
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
export default
|
|
66
|
+
export default FetchJson;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Form
|
|
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
|
|
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
|
|
@@ -118,7 +118,7 @@ interface FormConfig {
|
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
/**
|
|
121
|
-
* Form
|
|
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
|
|
162
|
+
export class Form {
|
|
163
163
|
/**
|
|
164
164
|
* Creates an Adaptive Card form with the specified fields and configuration.
|
|
165
165
|
*
|
|
@@ -575,4 +575,4 @@ export class FormLoader {
|
|
|
575
575
|
}
|
|
576
576
|
}
|
|
577
577
|
|
|
578
|
-
export {
|
|
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
|
|
13
|
-
* import {
|
|
14
|
-
* const
|
|
15
|
-
* const response = await
|
|
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
|
-
*
|
|
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
|
|
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
|
|
247
|
-
* const response = await
|
|
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
|
|
285
|
-
* for await (const chunk of
|
|
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
|
|
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
|
|
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
|
|
433
|
+
return Llm.extractContent(response);
|
|
434
434
|
}
|
|
435
435
|
|
|
436
|
-
export default
|
|
436
|
+
export default Llm;
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import { FunctionDef } from 'flowquery/extensibility';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* MockUsers
|
|
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
|
|
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
|
|
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
|
|
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 {
|
|
149
|
+
export { MockUsers as default };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Table
|
|
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
|
|
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
|
|
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 {
|
|
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,5 +1,5 @@
|
|
|
1
1
|
import ASTNode from "../ast_node";
|
|
2
|
-
import
|
|
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
|
|
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
|
*
|
|
@@ -56,39 +37,13 @@ class AsyncFunction extends ASTNode {
|
|
|
56
37
|
}
|
|
57
38
|
|
|
58
39
|
/**
|
|
59
|
-
*
|
|
40
|
+
* Generates the async data provider function results.
|
|
60
41
|
*
|
|
61
42
|
* @yields Data items from the async provider
|
|
62
43
|
* @throws {Error} If the function is not registered as an async provider
|
|
63
44
|
*/
|
|
64
|
-
public async *
|
|
65
|
-
|
|
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})`;
|
|
45
|
+
public async *generate(): AsyncGenerator<any, void, unknown> {
|
|
46
|
+
throw new Error("Not implemented: generate method must be overridden in subclasses.");
|
|
92
47
|
}
|
|
93
48
|
}
|
|
94
49
|
|
|
@@ -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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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;
|