flowquery 1.0.25 → 1.0.27
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/.github/workflows/release.yml +1 -0
- package/.husky/pre-commit +3 -2
- package/dist/flowquery.min.js +1 -1
- package/dist/parsing/expressions/reference.d.ts +1 -0
- package/dist/parsing/expressions/reference.d.ts.map +1 -1
- package/dist/parsing/expressions/reference.js +3 -0
- package/dist/parsing/expressions/reference.js.map +1 -1
- package/dist/parsing/parser.d.ts.map +1 -1
- package/dist/parsing/parser.js +19 -4
- package/dist/parsing/parser.js.map +1 -1
- package/docs/flowquery.min.js +1 -1
- package/flowquery-py/pyproject.toml +1 -1
- package/flowquery-py/src/parsing/parser.py +14 -0
- package/flowquery-py/tests/compute/test_runner.py +67 -1
- package/flowquery-py/tests/parsing/test_parser.py +18 -0
- package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
- package/jest.config.js +6 -9
- package/misc/apps/RAG/data/chats.json +302 -0
- package/misc/apps/RAG/data/emails.json +182 -0
- package/misc/apps/RAG/data/events.json +226 -0
- package/misc/apps/RAG/data/files.json +172 -0
- package/misc/apps/RAG/data/users.json +158 -0
- package/misc/apps/RAG/jest.config.js +21 -0
- package/misc/apps/RAG/package.json +9 -2
- package/misc/apps/RAG/src/App.tsx +5 -5
- package/misc/apps/RAG/src/components/ChatContainer.tsx +53 -124
- package/misc/apps/RAG/src/components/FlowQueryAgent.ts +151 -157
- package/misc/apps/RAG/src/components/index.ts +1 -1
- package/misc/apps/RAG/src/graph/index.ts +19 -0
- package/misc/apps/RAG/src/graph/initializeGraph.ts +254 -0
- package/misc/apps/RAG/src/index.tsx +25 -13
- package/misc/apps/RAG/src/prompts/FlowQuerySystemPrompt.ts +146 -231
- package/misc/apps/RAG/src/prompts/index.ts +4 -4
- package/misc/apps/RAG/src/tests/graph.test.ts +35 -0
- package/misc/apps/RAG/src/utils/FlowQueryExecutor.ts +20 -21
- package/misc/apps/RAG/src/utils/FlowQueryExtractor.ts +35 -30
- package/misc/apps/RAG/src/utils/Llm.ts +248 -0
- package/misc/apps/RAG/src/utils/index.ts +7 -4
- package/misc/apps/RAG/tsconfig.json +4 -3
- package/misc/apps/RAG/webpack.config.js +40 -40
- package/package.json +1 -1
- package/src/parsing/expressions/reference.ts +8 -5
- package/src/parsing/parser.ts +19 -4
- package/tests/compute/runner.test.ts +47 -1
- package/tests/parsing/parser.test.ts +16 -0
- package/misc/apps/RAG/src/plugins/README.md +0 -139
- package/misc/apps/RAG/src/plugins/index.ts +0 -72
- package/misc/apps/RAG/src/plugins/loaders/CatFacts.ts +0 -70
- package/misc/apps/RAG/src/plugins/loaders/FetchJson.ts +0 -65
- package/misc/apps/RAG/src/plugins/loaders/Form.ts +0 -594
- package/misc/apps/RAG/src/plugins/loaders/Llm.ts +0 -450
- package/misc/apps/RAG/src/plugins/loaders/MockData.ts +0 -101
- package/misc/apps/RAG/src/plugins/loaders/Table.ts +0 -274
- package/misc/apps/RAG/src/plugins/loaders/Weather.ts +0 -138
|
@@ -3,9 +3,9 @@ import Identifier from "./identifier";
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Represents a reference to a previously defined variable or expression.
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
7
|
* References point to values defined earlier in the query (e.g., in WITH or LOAD statements).
|
|
8
|
-
*
|
|
8
|
+
*
|
|
9
9
|
* @example
|
|
10
10
|
* ```typescript
|
|
11
11
|
* const ref = new Reference("myVar", previousNode);
|
|
@@ -14,10 +14,10 @@ import Identifier from "./identifier";
|
|
|
14
14
|
*/
|
|
15
15
|
class Reference extends Identifier {
|
|
16
16
|
private _referred: ASTNode | undefined = undefined;
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
/**
|
|
19
19
|
* Creates a new Reference to a variable.
|
|
20
|
-
*
|
|
20
|
+
*
|
|
21
21
|
* @param value - The identifier name
|
|
22
22
|
* @param referred - The node this reference points to (optional)
|
|
23
23
|
*/
|
|
@@ -25,6 +25,9 @@ class Reference extends Identifier {
|
|
|
25
25
|
super(value);
|
|
26
26
|
this._referred = referred;
|
|
27
27
|
}
|
|
28
|
+
public get referred(): ASTNode | undefined {
|
|
29
|
+
return this._referred;
|
|
30
|
+
}
|
|
28
31
|
public set referred(node: ASTNode) {
|
|
29
32
|
this._referred = node;
|
|
30
33
|
}
|
|
@@ -39,4 +42,4 @@ class Reference extends Identifier {
|
|
|
39
42
|
}
|
|
40
43
|
}
|
|
41
44
|
|
|
42
|
-
export default Reference;
|
|
45
|
+
export default Reference;
|
package/src/parsing/parser.ts
CHANGED
|
@@ -220,6 +220,7 @@ class Parser extends BaseParser {
|
|
|
220
220
|
}
|
|
221
221
|
|
|
222
222
|
private parseWhere(): Where | null {
|
|
223
|
+
this.skipWhitespaceAndComments();
|
|
223
224
|
if (!this.token.isWhere()) {
|
|
224
225
|
return null;
|
|
225
226
|
}
|
|
@@ -437,8 +438,15 @@ class Parser extends BaseParser {
|
|
|
437
438
|
node.identifier = identifier;
|
|
438
439
|
this.variables.set(identifier, node);
|
|
439
440
|
} else if (identifier !== null) {
|
|
440
|
-
|
|
441
|
-
|
|
441
|
+
let reference = this.variables.get(identifier);
|
|
442
|
+
// Resolve through Expression -> Reference -> Node (e.g., after WITH)
|
|
443
|
+
if (reference instanceof Expression && reference.firstChild() instanceof Reference) {
|
|
444
|
+
const inner = (reference.firstChild() as Reference).referred;
|
|
445
|
+
if (inner instanceof Node) {
|
|
446
|
+
reference = inner;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
if (reference === undefined || !(reference instanceof Node)) {
|
|
442
450
|
throw new Error(`Undefined node reference: ${identifier}`);
|
|
443
451
|
}
|
|
444
452
|
node = new NodeReference(node, reference);
|
|
@@ -628,8 +636,15 @@ class Parser extends BaseParser {
|
|
|
628
636
|
relationship.identifier = variable;
|
|
629
637
|
this.variables.set(variable, relationship);
|
|
630
638
|
} else if (variable !== null) {
|
|
631
|
-
|
|
632
|
-
|
|
639
|
+
let reference = this.variables.get(variable);
|
|
640
|
+
// Resolve through Expression -> Reference -> Relationship (e.g., after WITH)
|
|
641
|
+
if (reference instanceof Expression && reference.firstChild() instanceof Reference) {
|
|
642
|
+
const inner = (reference.firstChild() as Reference).referred;
|
|
643
|
+
if (inner instanceof Relationship) {
|
|
644
|
+
reference = inner;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
if (reference === undefined || !(reference instanceof Relationship)) {
|
|
633
648
|
throw new Error(`Undefined relationship reference: ${variable}`);
|
|
634
649
|
}
|
|
635
650
|
relationship = new RelationshipReference(relationship, reference);
|
|
@@ -414,7 +414,7 @@ test("Test lookup which is keyword", async () => {
|
|
|
414
414
|
expect(results[0]).toEqual({ aa: 1 });
|
|
415
415
|
});
|
|
416
416
|
|
|
417
|
-
test("Test lookup which is keyword", async () => {
|
|
417
|
+
test("Test lookup which is keyword with bracket notation", async () => {
|
|
418
418
|
const runner = new Runner('RETURN {return: 1}["return"] as aa');
|
|
419
419
|
await runner.run();
|
|
420
420
|
const results = runner.results;
|
|
@@ -1556,3 +1556,49 @@ test("Test reserved keywords as relationship types and labels", async () => {
|
|
|
1556
1556
|
expect(results.length).toBe(1);
|
|
1557
1557
|
expect(results[0]).toEqual({ name1: "Node 1", name2: "Node 2" });
|
|
1558
1558
|
});
|
|
1559
|
+
|
|
1560
|
+
test("Test match with node reference passed through WITH", async () => {
|
|
1561
|
+
await new Runner(`
|
|
1562
|
+
CREATE VIRTUAL (:User) AS {
|
|
1563
|
+
UNWIND [
|
|
1564
|
+
{id: 1, name: 'Alice', mail: 'alice@test.com', jobTitle: 'CEO'},
|
|
1565
|
+
{id: 2, name: 'Bob', mail: 'bob@test.com', jobTitle: 'VP'},
|
|
1566
|
+
{id: 3, name: 'Carol', mail: 'carol@test.com', jobTitle: 'VP'},
|
|
1567
|
+
{id: 4, name: 'Dave', mail: 'dave@test.com', jobTitle: 'Engineer'}
|
|
1568
|
+
] AS record
|
|
1569
|
+
RETURN record.id AS id, record.name AS name, record.mail AS mail, record.jobTitle AS jobTitle
|
|
1570
|
+
}
|
|
1571
|
+
`).run();
|
|
1572
|
+
await new Runner(`
|
|
1573
|
+
CREATE VIRTUAL (:User)-[:MANAGES]-(:User) AS {
|
|
1574
|
+
UNWIND [
|
|
1575
|
+
{left_id: 1, right_id: 2},
|
|
1576
|
+
{left_id: 1, right_id: 3},
|
|
1577
|
+
{left_id: 2, right_id: 4}
|
|
1578
|
+
] AS record
|
|
1579
|
+
RETURN record.left_id AS left_id, record.right_id AS right_id
|
|
1580
|
+
}
|
|
1581
|
+
`).run();
|
|
1582
|
+
// Equivalent to:
|
|
1583
|
+
// MATCH (ceo:User)-[:MANAGES]->(dr1:User)
|
|
1584
|
+
// WHERE ceo.jobTitle = 'CEO'
|
|
1585
|
+
// WITH ceo, dr1
|
|
1586
|
+
// MATCH (ceo)-[:MANAGES]->(dr2:User)
|
|
1587
|
+
// WHERE dr1.mail <> dr2.mail
|
|
1588
|
+
// RETURN ceo, dr1, dr2
|
|
1589
|
+
const match = new Runner(`
|
|
1590
|
+
MATCH (ceo:User)-[:MANAGES]->(dr1:User)
|
|
1591
|
+
WHERE ceo.jobTitle = 'CEO'
|
|
1592
|
+
WITH ceo, dr1
|
|
1593
|
+
MATCH (ceo)-[:MANAGES]->(dr2:User)
|
|
1594
|
+
WHERE dr1.mail <> dr2.mail
|
|
1595
|
+
RETURN ceo.name AS ceo, dr1.name AS dr1, dr2.name AS dr2
|
|
1596
|
+
`);
|
|
1597
|
+
await match.run();
|
|
1598
|
+
const results = match.results;
|
|
1599
|
+
// CEO (Alice) manages Bob and Carol. All distinct pairs:
|
|
1600
|
+
// (Alice, Bob, Carol) and (Alice, Carol, Bob)
|
|
1601
|
+
expect(results.length).toBe(2);
|
|
1602
|
+
expect(results[0]).toEqual({ ceo: "Alice", dr1: "Bob", dr2: "Carol" });
|
|
1603
|
+
expect(results[1]).toEqual({ ceo: "Alice", dr1: "Carol", dr2: "Bob" });
|
|
1604
|
+
});
|
|
@@ -867,6 +867,22 @@ test("Test node with properties", () => {
|
|
|
867
867
|
expect(node.properties.get("value")?.value()).toBe("hello");
|
|
868
868
|
});
|
|
869
869
|
|
|
870
|
+
test("Test WHERE in CREATE VIRTUAL sub-query", () => {
|
|
871
|
+
const parser = new Parser();
|
|
872
|
+
const ast = parser.parse(`
|
|
873
|
+
CREATE VIRTUAL (:Email)-[:HAS_ATTACHMENT]-(:File) AS {
|
|
874
|
+
LOAD JSON FROM '/data/emails.json' AS email
|
|
875
|
+
WHERE email.hasAttachments = true
|
|
876
|
+
UNWIND email.attachments AS fileId
|
|
877
|
+
RETURN email.id AS left_id, fileId AS right_id
|
|
878
|
+
}
|
|
879
|
+
`);
|
|
880
|
+
const create = ast.firstChild() as CreateRelationship;
|
|
881
|
+
expect(create.relationship).not.toBeNull();
|
|
882
|
+
expect(create.relationship!.type).toBe("HAS_ATTACHMENT");
|
|
883
|
+
expect(create.statement).not.toBeNull();
|
|
884
|
+
});
|
|
885
|
+
|
|
870
886
|
test("Test relationship with properties", () => {
|
|
871
887
|
const parser = new Parser();
|
|
872
888
|
const ast = parser.parse("MATCH (:Person)-[r:LIKES{since: 2022}]->(:Food) return a");
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
# FlowQuery Plugin System
|
|
2
|
-
|
|
3
|
-
This folder contains the plugin system for adding async data loader functions to FlowQuery.
|
|
4
|
-
|
|
5
|
-
## Quick Start
|
|
6
|
-
|
|
7
|
-
1. Create a new file in `loaders/` (e.g., `my-api.ts`)
|
|
8
|
-
2. Define your plugin following the `AsyncLoaderPlugin` interface
|
|
9
|
-
3. Import and add it to the `allPlugins` array in `index.ts`
|
|
10
|
-
|
|
11
|
-
## Creating a Plugin
|
|
12
|
-
|
|
13
|
-
### Basic Plugin Structure
|
|
14
|
-
|
|
15
|
-
```typescript
|
|
16
|
-
import { AsyncLoaderPlugin } from '../types';
|
|
17
|
-
|
|
18
|
-
// Your async data provider function
|
|
19
|
-
async function* myDataProvider(arg1: string, arg2?: number): AsyncGenerator<any, void, unknown> {
|
|
20
|
-
const response = await fetch(`https://api.example.com/${arg1}`);
|
|
21
|
-
const data = await response.json();
|
|
22
|
-
|
|
23
|
-
// Yield items one at a time (for arrays)
|
|
24
|
-
if (Array.isArray(data)) {
|
|
25
|
-
for (const item of data) {
|
|
26
|
-
yield item;
|
|
27
|
-
}
|
|
28
|
-
} else {
|
|
29
|
-
yield data;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Export the plugin definition
|
|
34
|
-
export const myPlugin: AsyncLoaderPlugin = {
|
|
35
|
-
name: 'myData', // Function name in FlowQuery
|
|
36
|
-
provider: myDataProvider,
|
|
37
|
-
metadata: {
|
|
38
|
-
description: 'Fetches data from My API',
|
|
39
|
-
category: 'data',
|
|
40
|
-
parameters: [
|
|
41
|
-
{ name: 'arg1', description: 'First argument', type: 'string', required: true },
|
|
42
|
-
{ name: 'arg2', description: 'Optional second arg', type: 'number', required: false }
|
|
43
|
-
],
|
|
44
|
-
output: {
|
|
45
|
-
description: 'Data item',
|
|
46
|
-
type: 'object',
|
|
47
|
-
properties: {
|
|
48
|
-
id: { description: 'Item ID', type: 'number' },
|
|
49
|
-
value: { description: 'Item value', type: 'string' }
|
|
50
|
-
}
|
|
51
|
-
},
|
|
52
|
-
examples: [
|
|
53
|
-
"LOAD JSON FROM myData('users') AS item RETURN item.id, item.value"
|
|
54
|
-
]
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
export default myPlugin;
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
### Register the Plugin
|
|
62
|
-
|
|
63
|
-
Add your plugin to `index.ts`:
|
|
64
|
-
|
|
65
|
-
```typescript
|
|
66
|
-
import myPlugin from './loaders/my-api';
|
|
67
|
-
|
|
68
|
-
const allPlugins: AsyncLoaderPlugin[] = [
|
|
69
|
-
// ... existing plugins
|
|
70
|
-
myPlugin,
|
|
71
|
-
];
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
## Using Plugins in FlowQuery
|
|
75
|
-
|
|
76
|
-
Once registered, use your plugin in FlowQuery queries:
|
|
77
|
-
|
|
78
|
-
```sql
|
|
79
|
-
-- Fetch data from your custom source
|
|
80
|
-
LOAD JSON FROM myData('users') AS user
|
|
81
|
-
WHERE user.active = true
|
|
82
|
-
RETURN user.name, user.email
|
|
83
|
-
|
|
84
|
-
-- Combine with filtering and ordering
|
|
85
|
-
LOAD JSON FROM myData('products', 50) AS product
|
|
86
|
-
WHERE product.price > 10
|
|
87
|
-
ORDER BY product.name ASC
|
|
88
|
-
RETURN product.name, product.price
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
## Available Built-in Plugins
|
|
92
|
-
|
|
93
|
-
| Plugin | Description | Example |
|
|
94
|
-
|--------|-------------|---------|
|
|
95
|
-
| `fetchJson` | Fetch JSON from any URL | `fetchJson('https://api.example.com/data')` |
|
|
96
|
-
|
|
97
|
-
> **Note**: Additional plugins may be registered. Check `index.ts` for the current list of available plugins.
|
|
98
|
-
|
|
99
|
-
## Plugin Types
|
|
100
|
-
|
|
101
|
-
### AsyncLoaderPlugin
|
|
102
|
-
|
|
103
|
-
```typescript
|
|
104
|
-
interface AsyncLoaderPlugin {
|
|
105
|
-
name: string; // Function name (lowercased when registered)
|
|
106
|
-
provider: AsyncDataProvider; // The async generator/function
|
|
107
|
-
metadata?: PluginMetadata; // Optional metadata for LLM consumption
|
|
108
|
-
}
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
### AsyncDataProvider
|
|
112
|
-
|
|
113
|
-
```typescript
|
|
114
|
-
type AsyncDataProvider = (...args: any[]) => AsyncGenerator<any, void, unknown> | Promise<any>;
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
Plugins can return either:
|
|
118
|
-
- An `AsyncGenerator` that yields items one at a time
|
|
119
|
-
- A `Promise` that resolves to an array or single value
|
|
120
|
-
|
|
121
|
-
### PluginMetadata
|
|
122
|
-
|
|
123
|
-
```typescript
|
|
124
|
-
interface PluginMetadata {
|
|
125
|
-
name: string;
|
|
126
|
-
description: string;
|
|
127
|
-
category?: string;
|
|
128
|
-
parameters?: ParameterSchema[];
|
|
129
|
-
output?: OutputSchema;
|
|
130
|
-
examples?: string[];
|
|
131
|
-
}
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
## Tips
|
|
135
|
-
|
|
136
|
-
1. **Use generators for large datasets** - Yield items one at a time to avoid memory issues
|
|
137
|
-
2. **Add comprehensive metadata** - This helps LLMs understand and use your functions
|
|
138
|
-
3. **Handle errors gracefully** - Throw descriptive errors for API failures
|
|
139
|
-
4. **Include examples** - Show users how to use your plugin in FlowQuery
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Plugin loader - automatically discovers and loads all plugins.
|
|
3
|
-
*
|
|
4
|
-
* To add a new plugin:
|
|
5
|
-
* 1. Create a new file in the `loaders/` directory
|
|
6
|
-
* 2. Add the @FunctionDef decorator with category: 'async' to your loader class
|
|
7
|
-
* 3. Import the class in this file (the decorator auto-registers with FlowQuery)
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import FlowQuery from 'flowquery';
|
|
11
|
-
import { FunctionMetadata } from 'flowquery/extensibility';
|
|
12
|
-
|
|
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
|
|
15
|
-
import './loaders/FetchJson';
|
|
16
|
-
import './loaders/CatFacts';
|
|
17
|
-
import './loaders/MockData';
|
|
18
|
-
import './loaders/Llm';
|
|
19
|
-
import './loaders/Table';
|
|
20
|
-
import './loaders/Form';
|
|
21
|
-
import './loaders/Weather';
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Initialize plugins.
|
|
25
|
-
* Plugins are auto-registered via @FunctionDef decorators when imported.
|
|
26
|
-
* This function just logs the registered plugins for debugging.
|
|
27
|
-
*/
|
|
28
|
-
export function initializePlugins(): void {
|
|
29
|
-
const plugins = getLoadedPluginNames();
|
|
30
|
-
console.log(`FlowQuery plugins loaded: ${plugins.join(', ')}`);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Get the list of loaded plugin names.
|
|
35
|
-
* Uses FlowQuery's introspection to discover registered async providers.
|
|
36
|
-
*/
|
|
37
|
-
export function getLoadedPluginNames(): string[] {
|
|
38
|
-
return FlowQuery.listFunctions({ asyncOnly: true }).map(f => f.name);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Get metadata for all loaded plugins.
|
|
43
|
-
* Uses FlowQuery's functions() introspection as the single source of truth.
|
|
44
|
-
*/
|
|
45
|
-
export function getAllPluginMetadata(): FunctionMetadata[] {
|
|
46
|
-
return FlowQuery.listFunctions({ asyncOnly: true });
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Get all available async loader plugins by querying FlowQuery directly.
|
|
51
|
-
* This is the preferred async method that uses functions() introspection.
|
|
52
|
-
*
|
|
53
|
-
* @returns Promise resolving to array of plugin metadata
|
|
54
|
-
*/
|
|
55
|
-
export async function getAvailableLoaders(): Promise<FunctionMetadata[]> {
|
|
56
|
-
const runner = new FlowQuery(`
|
|
57
|
-
WITH functions() AS funcs
|
|
58
|
-
UNWIND funcs AS f
|
|
59
|
-
WHERE f.isAsyncProvider = true
|
|
60
|
-
RETURN f
|
|
61
|
-
`);
|
|
62
|
-
await runner.run();
|
|
63
|
-
return runner.results.map((r: any) => r.expr0 as FunctionMetadata);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Re-export types for external use
|
|
67
|
-
export type { FunctionMetadata, FunctionDefOptions, ParameterSchema, OutputSchema } from 'flowquery/extensibility';
|
|
68
|
-
export { FunctionDef } from 'flowquery/extensibility';
|
|
69
|
-
|
|
70
|
-
// Re-export standalone loader functions for use outside of FlowQuery
|
|
71
|
-
export { llm, llmStream, extractContent } from './loaders/Llm';
|
|
72
|
-
export type { LlmOptions, LlmResponse } from './loaders/Llm';
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Example plugin: Fetch random cat facts from the Cat Facts API.
|
|
3
|
-
*
|
|
4
|
-
* Usage in FlowQuery:
|
|
5
|
-
* CALL catFacts(5) YIELD text, length
|
|
6
|
-
*/
|
|
7
|
-
import { AsyncFunction, FunctionDef } from "flowquery/extensibility";
|
|
8
|
-
|
|
9
|
-
const CAT_FACTS_API = "https://catfact.ninja/facts";
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* CatFacts class - fetches random cat facts from the Cat Facts API.
|
|
13
|
-
*/
|
|
14
|
-
@FunctionDef({
|
|
15
|
-
description: "Fetches random cat facts from the Cat Facts API (catfact.ninja)",
|
|
16
|
-
category: "async",
|
|
17
|
-
parameters: [
|
|
18
|
-
{
|
|
19
|
-
name: "count",
|
|
20
|
-
description: "Number of cat facts to fetch",
|
|
21
|
-
type: "number",
|
|
22
|
-
required: false,
|
|
23
|
-
default: 1,
|
|
24
|
-
},
|
|
25
|
-
],
|
|
26
|
-
output: {
|
|
27
|
-
description: "Cat fact object",
|
|
28
|
-
type: "object",
|
|
29
|
-
properties: {
|
|
30
|
-
text: { description: "The cat fact text", type: "string" },
|
|
31
|
-
length: { description: "Length of the fact text", type: "number" },
|
|
32
|
-
},
|
|
33
|
-
},
|
|
34
|
-
examples: ["CALL catFacts() YIELD text", "CALL catFacts(5) YIELD text, length"],
|
|
35
|
-
})
|
|
36
|
-
export class CatFacts extends AsyncFunction {
|
|
37
|
-
private readonly apiUrl: string;
|
|
38
|
-
|
|
39
|
-
constructor(apiUrl: string = CAT_FACTS_API) {
|
|
40
|
-
super();
|
|
41
|
-
this.apiUrl = apiUrl;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Fetches random cat facts from the Cat Facts API.
|
|
46
|
-
*
|
|
47
|
-
* @param count - Number of cat facts to fetch (default: 1)
|
|
48
|
-
*/
|
|
49
|
-
async *generate(count: number = 1): AsyncGenerator<any, void, unknown> {
|
|
50
|
-
const url = `${this.apiUrl}?limit=${count}`;
|
|
51
|
-
const response = await fetch(url);
|
|
52
|
-
|
|
53
|
-
if (!response.ok) {
|
|
54
|
-
throw new Error(`Failed to fetch cat facts: ${response.statusText}`);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const json = await response.json();
|
|
58
|
-
const data = json.data || [];
|
|
59
|
-
|
|
60
|
-
for (const item of data) {
|
|
61
|
-
// Map 'fact' to 'text' for backwards compatibility with existing queries
|
|
62
|
-
yield {
|
|
63
|
-
text: item.fact,
|
|
64
|
-
length: item.length,
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export default CatFacts;
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Example plugin: Fetch JSON data from a URL.
|
|
3
|
-
*
|
|
4
|
-
* Usage in FlowQuery:
|
|
5
|
-
* CALL fetchJson('https://api.example.com/data') YIELD name, value
|
|
6
|
-
*/
|
|
7
|
-
import { AsyncFunction, FunctionDef } from "flowquery/extensibility";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* FetchJson class - fetches JSON data from a URL and yields items.
|
|
11
|
-
*/
|
|
12
|
-
@FunctionDef({
|
|
13
|
-
description:
|
|
14
|
-
"Fetches JSON data from a URL. If the response is an array, yields each item individually.",
|
|
15
|
-
category: "async",
|
|
16
|
-
parameters: [
|
|
17
|
-
{
|
|
18
|
-
name: "url",
|
|
19
|
-
description: "The URL to fetch JSON from",
|
|
20
|
-
type: "string",
|
|
21
|
-
required: true,
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
name: "options",
|
|
25
|
-
description: "Optional fetch options (headers, method, etc.)",
|
|
26
|
-
type: "object",
|
|
27
|
-
required: false,
|
|
28
|
-
},
|
|
29
|
-
],
|
|
30
|
-
output: {
|
|
31
|
-
description: "JSON data items",
|
|
32
|
-
type: "object",
|
|
33
|
-
},
|
|
34
|
-
examples: [
|
|
35
|
-
"CALL fetchJson('https://api.example.com/users') YIELD name",
|
|
36
|
-
"CALL fetchJson('https://api.example.com/data') YIELD name, active WHERE active = true",
|
|
37
|
-
],
|
|
38
|
-
})
|
|
39
|
-
export class FetchJson extends AsyncFunction {
|
|
40
|
-
/**
|
|
41
|
-
* Fetches JSON data from a URL and yields each item if array, or the object itself.
|
|
42
|
-
*
|
|
43
|
-
* @param url - The URL to fetch JSON from
|
|
44
|
-
* @param options - Optional fetch options
|
|
45
|
-
*/
|
|
46
|
-
async *generate(url: string, options?: RequestInit): AsyncGenerator<any, void, unknown> {
|
|
47
|
-
const response = await fetch(url, options);
|
|
48
|
-
|
|
49
|
-
if (!response.ok) {
|
|
50
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const data = await response.json();
|
|
54
|
-
|
|
55
|
-
if (Array.isArray(data)) {
|
|
56
|
-
for (const item of data) {
|
|
57
|
-
yield item;
|
|
58
|
-
}
|
|
59
|
-
} else {
|
|
60
|
-
yield data;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export default FetchJson;
|