flowquery 1.0.5 → 1.0.7
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 +74 -0
- package/dist/compute/runner.d.ts +1 -22
- package/dist/compute/runner.d.ts.map +1 -1
- package/dist/compute/runner.js.map +1 -1
- package/dist/extensibility.d.ts +35 -0
- package/dist/extensibility.d.ts.map +1 -0
- package/dist/extensibility.js +49 -0
- package/dist/extensibility.js.map +1 -0
- package/dist/flowquery.min.js +1 -1
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.browser.js +0 -80
- package/dist/index.browser.js.map +1 -1
- package/dist/index.node.d.ts +3 -3
- package/dist/index.node.d.ts.map +1 -1
- package/dist/index.node.js +0 -80
- package/dist/index.node.js.map +1 -1
- package/dist/parsing/functions/avg.d.ts.map +1 -1
- package/dist/parsing/functions/avg.js +20 -2
- package/dist/parsing/functions/avg.js.map +1 -1
- package/dist/parsing/functions/collect.d.ts.map +1 -1
- package/dist/parsing/functions/collect.js +20 -2
- package/dist/parsing/functions/collect.js.map +1 -1
- package/dist/parsing/functions/function_factory.d.ts +26 -80
- package/dist/parsing/functions/function_factory.d.ts.map +1 -1
- package/dist/parsing/functions/function_factory.js +46 -168
- package/dist/parsing/functions/function_factory.js.map +1 -1
- package/dist/parsing/functions/function_metadata.d.ts +81 -20
- package/dist/parsing/functions/function_metadata.d.ts.map +1 -1
- package/dist/parsing/functions/function_metadata.js +154 -152
- package/dist/parsing/functions/function_metadata.js.map +1 -1
- package/dist/parsing/functions/functions.d.ts.map +1 -1
- package/dist/parsing/functions/functions.js +37 -2
- package/dist/parsing/functions/functions.js.map +1 -1
- package/dist/parsing/functions/join.d.ts.map +1 -1
- package/dist/parsing/functions/join.js +21 -2
- package/dist/parsing/functions/join.js.map +1 -1
- package/dist/parsing/functions/predicate_function.d.ts +1 -0
- package/dist/parsing/functions/predicate_function.d.ts.map +1 -1
- package/dist/parsing/functions/predicate_function.js +3 -0
- package/dist/parsing/functions/predicate_function.js.map +1 -1
- package/dist/parsing/functions/predicate_sum.d.ts.map +1 -1
- package/dist/parsing/functions/predicate_sum.js +23 -2
- package/dist/parsing/functions/predicate_sum.js.map +1 -1
- package/dist/parsing/functions/rand.d.ts.map +1 -1
- package/dist/parsing/functions/rand.js +18 -2
- package/dist/parsing/functions/rand.js.map +1 -1
- package/dist/parsing/functions/range.d.ts.map +1 -1
- package/dist/parsing/functions/range.js +21 -2
- package/dist/parsing/functions/range.js.map +1 -1
- package/dist/parsing/functions/replace.d.ts.map +1 -1
- package/dist/parsing/functions/replace.js +22 -2
- package/dist/parsing/functions/replace.js.map +1 -1
- package/dist/parsing/functions/round.d.ts.map +1 -1
- package/dist/parsing/functions/round.js +20 -2
- package/dist/parsing/functions/round.js.map +1 -1
- package/dist/parsing/functions/size.d.ts.map +1 -1
- package/dist/parsing/functions/size.js +20 -2
- package/dist/parsing/functions/size.js.map +1 -1
- package/dist/parsing/functions/split.d.ts.map +1 -1
- package/dist/parsing/functions/split.js +21 -2
- package/dist/parsing/functions/split.js.map +1 -1
- package/dist/parsing/functions/stringify.d.ts.map +1 -1
- package/dist/parsing/functions/stringify.js +20 -2
- package/dist/parsing/functions/stringify.js.map +1 -1
- package/dist/parsing/functions/sum.d.ts.map +1 -1
- package/dist/parsing/functions/sum.js +20 -2
- package/dist/parsing/functions/sum.js.map +1 -1
- package/dist/parsing/functions/to_json.d.ts.map +1 -1
- package/dist/parsing/functions/to_json.js +20 -2
- package/dist/parsing/functions/to_json.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/.env.example +14 -0
- package/misc/apps/RAG/README.md +0 -7
- package/misc/apps/RAG/package.json +16 -7
- package/misc/apps/RAG/public/index.html +18 -0
- package/misc/apps/RAG/src/App.css +42 -0
- package/misc/apps/RAG/src/App.tsx +50 -0
- package/misc/apps/RAG/src/components/ApiKeySettings.tsx +245 -0
- package/misc/apps/RAG/src/components/ChatContainer.css +67 -0
- package/misc/apps/RAG/src/components/ChatContainer.tsx +239 -0
- package/misc/apps/RAG/src/components/ChatInput.css +23 -0
- package/misc/apps/RAG/src/components/ChatInput.tsx +62 -0
- package/misc/apps/RAG/src/components/ChatMessage.css +136 -0
- package/misc/apps/RAG/src/components/ChatMessage.tsx +152 -0
- package/misc/apps/RAG/src/components/FlowQueryAgent.ts +390 -0
- package/misc/apps/RAG/src/components/FlowQueryRunner.css +104 -0
- package/misc/apps/RAG/src/components/FlowQueryRunner.tsx +332 -0
- package/misc/apps/RAG/src/components/index.ts +15 -0
- package/misc/apps/RAG/src/index.tsx +17 -0
- package/misc/apps/RAG/src/plugins/README.md +139 -0
- package/misc/apps/RAG/src/plugins/index.ts +68 -0
- package/misc/apps/RAG/src/plugins/loaders/CatFacts.ts +75 -0
- package/misc/apps/RAG/src/plugins/loaders/FetchJson.ts +67 -0
- package/misc/apps/RAG/src/plugins/loaders/Llm.ts +437 -0
- package/misc/apps/RAG/src/plugins/loaders/MockData.ts +151 -0
- package/misc/apps/RAG/src/prompts/FlowQuerySystemPrompt.ts +385 -0
- package/misc/apps/RAG/src/prompts/index.ts +10 -0
- package/misc/apps/RAG/src/utils/FlowQueryExecutor.ts +131 -0
- package/misc/apps/RAG/src/utils/FlowQueryExtractor.ts +203 -0
- package/misc/apps/RAG/src/utils/index.ts +9 -0
- package/misc/apps/RAG/tsconfig.json +4 -2
- package/misc/apps/RAG/webpack.config.js +23 -12
- package/package.json +7 -1
- package/src/compute/runner.ts +1 -26
- package/src/extensibility.ts +45 -0
- package/src/index.browser.ts +2 -88
- package/src/index.node.ts +3 -92
- package/src/parsing/functions/avg.ts +10 -0
- package/src/parsing/functions/collect.ts +10 -0
- package/src/parsing/functions/function_factory.ts +56 -194
- package/src/parsing/functions/function_metadata.ts +187 -168
- package/src/parsing/functions/functions.ts +27 -0
- package/src/parsing/functions/join.ts +11 -0
- package/src/parsing/functions/predicate_function.ts +4 -0
- package/src/parsing/functions/predicate_sum.ts +13 -0
- package/src/parsing/functions/rand.ts +8 -0
- package/src/parsing/functions/range.ts +11 -0
- package/src/parsing/functions/replace.ts +12 -0
- package/src/parsing/functions/round.ts +10 -0
- package/src/parsing/functions/size.ts +10 -0
- package/src/parsing/functions/split.ts +11 -0
- package/src/parsing/functions/stringify.ts +10 -0
- package/src/parsing/functions/sum.ts +10 -0
- package/src/parsing/functions/to_json.ts +10 -0
- package/src/parsing/parser.ts +1 -2
- package/tests/extensibility.test.ts +563 -0
- package/tsconfig.json +1 -0
- package/dist/parsing/functions/predicate_function_factory.d.ts +0 -6
- package/dist/parsing/functions/predicate_function_factory.d.ts.map +0 -1
- package/dist/parsing/functions/predicate_function_factory.js +0 -19
- package/dist/parsing/functions/predicate_function_factory.js.map +0 -1
- package/misc/apps/RAG/src/index.ts +0 -20
- package/src/parsing/functions/predicate_function_factory.ts +0 -15
- package/tests/parsing/function_plugins.test.ts +0 -369
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
.flowquery-runner-surface {
|
|
2
|
+
max-width: 800px;
|
|
3
|
+
width: 90vw;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.flowquery-runner-content {
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: column;
|
|
9
|
+
gap: 16px;
|
|
10
|
+
padding-top: 16px;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.flowquery-input-container {
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-direction: column;
|
|
16
|
+
gap: 8px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.flowquery-textarea {
|
|
20
|
+
width: 100%;
|
|
21
|
+
min-height: 120px;
|
|
22
|
+
font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;
|
|
23
|
+
font-size: 13px;
|
|
24
|
+
resize: vertical;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.flowquery-actions {
|
|
28
|
+
display: flex;
|
|
29
|
+
gap: 8px;
|
|
30
|
+
align-items: center;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.flowquery-execution-time {
|
|
34
|
+
margin-left: auto;
|
|
35
|
+
font-size: 12px;
|
|
36
|
+
color: #666;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.flowquery-results-container {
|
|
40
|
+
display: flex;
|
|
41
|
+
flex-direction: column;
|
|
42
|
+
gap: 8px;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.flowquery-results-header {
|
|
46
|
+
display: flex;
|
|
47
|
+
justify-content: space-between;
|
|
48
|
+
align-items: center;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.flowquery-results-count {
|
|
52
|
+
font-size: 12px;
|
|
53
|
+
color: #666;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.flowquery-results {
|
|
57
|
+
max-height: 300px;
|
|
58
|
+
overflow: auto;
|
|
59
|
+
border: 1px solid #e0e0e0;
|
|
60
|
+
border-radius: 4px;
|
|
61
|
+
background-color: #f8f8f8;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.flowquery-results-content {
|
|
65
|
+
padding: 12px;
|
|
66
|
+
font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;
|
|
67
|
+
font-size: 12px;
|
|
68
|
+
white-space: pre-wrap;
|
|
69
|
+
word-break: break-word;
|
|
70
|
+
margin: 0;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.flowquery-error {
|
|
74
|
+
color: #c50f1f;
|
|
75
|
+
padding: 12px;
|
|
76
|
+
margin: 0;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.flowquery-no-results {
|
|
80
|
+
color: #666;
|
|
81
|
+
font-style: italic;
|
|
82
|
+
padding: 12px;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.flowquery-loading {
|
|
86
|
+
display: flex;
|
|
87
|
+
align-items: center;
|
|
88
|
+
gap: 8px;
|
|
89
|
+
padding: 12px;
|
|
90
|
+
color: #666;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.flowquery-examples-list {
|
|
94
|
+
display: flex;
|
|
95
|
+
flex-direction: column;
|
|
96
|
+
gap: 4px;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.flowquery-example-button {
|
|
100
|
+
text-align: left;
|
|
101
|
+
justify-content: flex-start;
|
|
102
|
+
font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;
|
|
103
|
+
font-size: 12px;
|
|
104
|
+
}
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlowQuery Runner Component
|
|
3
|
+
*
|
|
4
|
+
* A popup dialog that allows users to run FlowQuery statements directly
|
|
5
|
+
* and see the results in the dialog.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React, { Component } from 'react';
|
|
9
|
+
import {
|
|
10
|
+
Dialog,
|
|
11
|
+
DialogTrigger,
|
|
12
|
+
DialogSurface,
|
|
13
|
+
DialogTitle,
|
|
14
|
+
DialogBody,
|
|
15
|
+
DialogActions,
|
|
16
|
+
DialogContent,
|
|
17
|
+
Button,
|
|
18
|
+
Textarea,
|
|
19
|
+
Label,
|
|
20
|
+
Field,
|
|
21
|
+
Spinner,
|
|
22
|
+
Tooltip,
|
|
23
|
+
} from '@fluentui/react-components';
|
|
24
|
+
import {
|
|
25
|
+
Play24Regular,
|
|
26
|
+
Code24Regular,
|
|
27
|
+
Dismiss24Regular,
|
|
28
|
+
Copy24Regular,
|
|
29
|
+
ArrowClockwise24Regular,
|
|
30
|
+
Checkmark24Regular,
|
|
31
|
+
} from '@fluentui/react-icons';
|
|
32
|
+
import { FlowQueryExecutor, FlowQueryExecutionResult } from '../utils/FlowQueryExecutor';
|
|
33
|
+
import './FlowQueryRunner.css';
|
|
34
|
+
|
|
35
|
+
const flowQueryExecutor = new FlowQueryExecutor();
|
|
36
|
+
|
|
37
|
+
interface FlowQueryRunnerProps {
|
|
38
|
+
/** Initial query to pre-populate the input */
|
|
39
|
+
initialQuery?: string;
|
|
40
|
+
/** Controlled open state - if provided, the component becomes controlled */
|
|
41
|
+
open?: boolean;
|
|
42
|
+
/** Callback when open state changes (for controlled mode) */
|
|
43
|
+
onOpenChange?: (open: boolean) => void;
|
|
44
|
+
/** Callback when the dialog is closed (deprecated, use onOpenChange) */
|
|
45
|
+
onClose?: () => void;
|
|
46
|
+
/** Custom trigger element. If not provided, a default button is shown. Not used in controlled mode. */
|
|
47
|
+
trigger?: React.ReactElement;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
interface FlowQueryRunnerState {
|
|
51
|
+
open: boolean;
|
|
52
|
+
query: string;
|
|
53
|
+
isExecuting: boolean;
|
|
54
|
+
result: FlowQueryExecutionResult | null;
|
|
55
|
+
copied: boolean;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export class FlowQueryRunner extends Component<FlowQueryRunnerProps, FlowQueryRunnerState> {
|
|
59
|
+
constructor(props: FlowQueryRunnerProps) {
|
|
60
|
+
super(props);
|
|
61
|
+
this.state = {
|
|
62
|
+
open: props.open ?? false,
|
|
63
|
+
query: props.initialQuery || '',
|
|
64
|
+
isExecuting: false,
|
|
65
|
+
result: null,
|
|
66
|
+
copied: false,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
componentDidUpdate(prevProps: FlowQueryRunnerProps): void {
|
|
71
|
+
// Handle controlled mode: sync open state from props
|
|
72
|
+
if (this.props.open !== undefined && this.props.open !== prevProps.open) {
|
|
73
|
+
this.setState({ open: this.props.open });
|
|
74
|
+
// If opening with a new initial query, update the query
|
|
75
|
+
if (this.props.open && this.props.initialQuery !== prevProps.initialQuery) {
|
|
76
|
+
this.setState({ query: this.props.initialQuery || '', result: null });
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Handle initialQuery changes when opening
|
|
80
|
+
if (this.props.initialQuery !== prevProps.initialQuery && this.props.open) {
|
|
81
|
+
this.setState({ query: this.props.initialQuery || '', result: null });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Check if the component is in controlled mode
|
|
87
|
+
*/
|
|
88
|
+
isControlled = (): boolean => {
|
|
89
|
+
return this.props.open !== undefined;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
handleOpenChange = (_: unknown, data: { open: boolean }): void => {
|
|
93
|
+
if (this.isControlled()) {
|
|
94
|
+
// In controlled mode, notify parent
|
|
95
|
+
this.props.onOpenChange?.(data.open);
|
|
96
|
+
} else {
|
|
97
|
+
// In uncontrolled mode, manage state internally
|
|
98
|
+
this.setState({ open: data.open });
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (!data.open && this.props.onClose) {
|
|
102
|
+
this.props.onClose();
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
handleClose = (): void => {
|
|
107
|
+
if (this.isControlled()) {
|
|
108
|
+
this.props.onOpenChange?.(false);
|
|
109
|
+
} else {
|
|
110
|
+
this.setState({ open: false });
|
|
111
|
+
}
|
|
112
|
+
this.props.onClose?.();
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
handleQueryChange = (_: unknown, data: { value: string }): void => {
|
|
116
|
+
this.setState({ query: data.value });
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
handleExecute = async (): Promise<void> => {
|
|
120
|
+
const { query } = this.state;
|
|
121
|
+
|
|
122
|
+
if (!query.trim()) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
this.setState({ isExecuting: true, result: null });
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
const result = await flowQueryExecutor.execute(query);
|
|
130
|
+
this.setState({ result, isExecuting: false });
|
|
131
|
+
} catch (error) {
|
|
132
|
+
this.setState({
|
|
133
|
+
result: {
|
|
134
|
+
success: false,
|
|
135
|
+
query,
|
|
136
|
+
error: error instanceof Error ? error.message : String(error),
|
|
137
|
+
executionTime: 0,
|
|
138
|
+
},
|
|
139
|
+
isExecuting: false,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
handleClear = (): void => {
|
|
145
|
+
this.setState({ query: '', result: null });
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
handleCopyResults = (): void => {
|
|
149
|
+
const { result } = this.state;
|
|
150
|
+
if (result?.success && result.results) {
|
|
151
|
+
navigator.clipboard.writeText(JSON.stringify(result.results, null, 2));
|
|
152
|
+
this.setState({ copied: true });
|
|
153
|
+
setTimeout(() => this.setState({ copied: false }), 2000);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
handleKeyDown = (event: React.KeyboardEvent): void => {
|
|
158
|
+
// Execute on Ctrl+Enter or Cmd+Enter
|
|
159
|
+
if ((event.ctrlKey || event.metaKey) && event.key === 'Enter') {
|
|
160
|
+
event.preventDefault();
|
|
161
|
+
this.handleExecute();
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
renderResults(): React.ReactNode {
|
|
166
|
+
const { result, isExecuting, copied } = this.state;
|
|
167
|
+
|
|
168
|
+
if (isExecuting) {
|
|
169
|
+
return (
|
|
170
|
+
<div className="flowquery-loading">
|
|
171
|
+
<Spinner size="tiny" />
|
|
172
|
+
<span>Executing query...</span>
|
|
173
|
+
</div>
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (!result) {
|
|
178
|
+
return (
|
|
179
|
+
<div className="flowquery-no-results">
|
|
180
|
+
Enter a FlowQuery statement and click Run to see results.
|
|
181
|
+
</div>
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (!result.success) {
|
|
186
|
+
return (
|
|
187
|
+
<pre className="flowquery-error">
|
|
188
|
+
Error: {result.error}
|
|
189
|
+
</pre>
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const resultCount = result.results?.length || 0;
|
|
194
|
+
const resultsJson = JSON.stringify(result.results, null, 2);
|
|
195
|
+
|
|
196
|
+
return (
|
|
197
|
+
<div className="flowquery-results-container">
|
|
198
|
+
<div className="flowquery-results-header">
|
|
199
|
+
<span className="flowquery-results-count">
|
|
200
|
+
{resultCount} result{resultCount !== 1 ? 's' : ''}
|
|
201
|
+
{' • '}
|
|
202
|
+
{result.executionTime.toFixed(2)}ms
|
|
203
|
+
</span>
|
|
204
|
+
<Tooltip
|
|
205
|
+
content={copied ? "Copied!" : "Copy results"}
|
|
206
|
+
relationship="label"
|
|
207
|
+
>
|
|
208
|
+
<Button
|
|
209
|
+
appearance="subtle"
|
|
210
|
+
icon={copied ? <Checkmark24Regular /> : <Copy24Regular />}
|
|
211
|
+
size="small"
|
|
212
|
+
onClick={this.handleCopyResults}
|
|
213
|
+
disabled={!result.results?.length}
|
|
214
|
+
/>
|
|
215
|
+
</Tooltip>
|
|
216
|
+
</div>
|
|
217
|
+
<div className="flowquery-results">
|
|
218
|
+
<pre className="flowquery-results-content">
|
|
219
|
+
{resultsJson}
|
|
220
|
+
</pre>
|
|
221
|
+
</div>
|
|
222
|
+
</div>
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
renderDialogSurface(): React.JSX.Element {
|
|
227
|
+
const { query, isExecuting } = this.state;
|
|
228
|
+
|
|
229
|
+
return (
|
|
230
|
+
<DialogSurface className="flowquery-runner-surface">
|
|
231
|
+
<DialogBody>
|
|
232
|
+
<DialogTitle
|
|
233
|
+
action={
|
|
234
|
+
<Button
|
|
235
|
+
appearance="subtle"
|
|
236
|
+
icon={<Dismiss24Regular />}
|
|
237
|
+
onClick={this.handleClose}
|
|
238
|
+
/>
|
|
239
|
+
}
|
|
240
|
+
>
|
|
241
|
+
FlowQuery Runner
|
|
242
|
+
</DialogTitle>
|
|
243
|
+
<DialogContent className="flowquery-runner-content">
|
|
244
|
+
<div className="flowquery-input-container">
|
|
245
|
+
<Field label="FlowQuery Statement">
|
|
246
|
+
<Textarea
|
|
247
|
+
value={query}
|
|
248
|
+
onChange={this.handleQueryChange}
|
|
249
|
+
onKeyDown={this.handleKeyDown}
|
|
250
|
+
placeholder="Enter your FlowQuery statement here..."
|
|
251
|
+
className="flowquery-textarea"
|
|
252
|
+
resize="vertical"
|
|
253
|
+
/>
|
|
254
|
+
</Field>
|
|
255
|
+
<div className="flowquery-actions">
|
|
256
|
+
<Tooltip content="Run query (Ctrl+Enter)" relationship="label">
|
|
257
|
+
<Button
|
|
258
|
+
appearance="primary"
|
|
259
|
+
icon={<Play24Regular />}
|
|
260
|
+
onClick={this.handleExecute}
|
|
261
|
+
disabled={isExecuting || !query.trim()}
|
|
262
|
+
>
|
|
263
|
+
Run
|
|
264
|
+
</Button>
|
|
265
|
+
</Tooltip>
|
|
266
|
+
<Tooltip content="Clear query and results" relationship="label">
|
|
267
|
+
<Button
|
|
268
|
+
appearance="subtle"
|
|
269
|
+
icon={<ArrowClockwise24Regular />}
|
|
270
|
+
onClick={this.handleClear}
|
|
271
|
+
disabled={isExecuting}
|
|
272
|
+
>
|
|
273
|
+
Clear
|
|
274
|
+
</Button>
|
|
275
|
+
</Tooltip>
|
|
276
|
+
</div>
|
|
277
|
+
</div>
|
|
278
|
+
|
|
279
|
+
<Field label="Results">
|
|
280
|
+
<div className="flowquery-results">
|
|
281
|
+
{this.renderResults()}
|
|
282
|
+
</div>
|
|
283
|
+
</Field>
|
|
284
|
+
</DialogContent>
|
|
285
|
+
<DialogActions>
|
|
286
|
+
<Button
|
|
287
|
+
appearance="secondary"
|
|
288
|
+
onClick={this.handleClose}
|
|
289
|
+
>
|
|
290
|
+
Close
|
|
291
|
+
</Button>
|
|
292
|
+
</DialogActions>
|
|
293
|
+
</DialogBody>
|
|
294
|
+
</DialogSurface>
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
render(): React.ReactNode {
|
|
299
|
+
const { open } = this.state;
|
|
300
|
+
const { trigger } = this.props;
|
|
301
|
+
const isControlled = this.isControlled();
|
|
302
|
+
|
|
303
|
+
// In controlled mode, render dialog without trigger
|
|
304
|
+
if (isControlled) {
|
|
305
|
+
return (
|
|
306
|
+
<Dialog open={open} onOpenChange={this.handleOpenChange}>
|
|
307
|
+
{this.renderDialogSurface()}
|
|
308
|
+
</Dialog>
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// In uncontrolled mode, render with trigger
|
|
313
|
+
return (
|
|
314
|
+
<Dialog open={open} onOpenChange={this.handleOpenChange}>
|
|
315
|
+
<DialogTrigger disableButtonEnhancement>
|
|
316
|
+
{trigger || (
|
|
317
|
+
<Button
|
|
318
|
+
appearance="subtle"
|
|
319
|
+
icon={<Code24Regular />}
|
|
320
|
+
title="FlowQuery Runner"
|
|
321
|
+
>
|
|
322
|
+
FlowQuery
|
|
323
|
+
</Button>
|
|
324
|
+
)}
|
|
325
|
+
</DialogTrigger>
|
|
326
|
+
{this.renderDialogSurface()}
|
|
327
|
+
</Dialog>
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
export default FlowQueryRunner;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Chat components exports
|
|
2
|
+
export { ChatContainer } from './ChatContainer';
|
|
3
|
+
export { ChatMessage } from './ChatMessage';
|
|
4
|
+
export { ChatInput } from './ChatInput';
|
|
5
|
+
export { ApiKeySettings } from './ApiKeySettings';
|
|
6
|
+
|
|
7
|
+
// FlowQuery Runner
|
|
8
|
+
export { FlowQueryRunner } from './FlowQueryRunner';
|
|
9
|
+
|
|
10
|
+
// FlowQuery Agent
|
|
11
|
+
export { processQuery, processQueryStream } from './FlowQueryAgent';
|
|
12
|
+
export type { AgentStep, AgentResult, FlowQueryAgentOptions, AgentStreamCallback } from './FlowQueryAgent';
|
|
13
|
+
|
|
14
|
+
// Types
|
|
15
|
+
export type { Message } from './ChatMessage';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { createRoot } from 'react-dom/client';
|
|
3
|
+
import App from './App';
|
|
4
|
+
import { initializePlugins } from './plugins';
|
|
5
|
+
|
|
6
|
+
// Initialize FlowQuery plugins before rendering
|
|
7
|
+
initializePlugins();
|
|
8
|
+
|
|
9
|
+
const container = document.getElementById('root');
|
|
10
|
+
if (container) {
|
|
11
|
+
const root = createRoot(container);
|
|
12
|
+
root.render(
|
|
13
|
+
<React.StrictMode>
|
|
14
|
+
<App />
|
|
15
|
+
</React.StrictMode>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
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
|
|
@@ -0,0 +1,68 @@
|
|
|
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 @AsyncProviderDef decorator 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 loader classes - the @AsyncProviderDef decorator auto-registers them with FlowQuery
|
|
14
|
+
import './loaders/FetchJson';
|
|
15
|
+
import './loaders/CatFacts';
|
|
16
|
+
import './loaders/MockData';
|
|
17
|
+
import './loaders/Llm';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Initialize plugins.
|
|
21
|
+
* Plugins are auto-registered via @AsyncProviderDef decorators when imported.
|
|
22
|
+
* This function just logs the registered plugins for debugging.
|
|
23
|
+
*/
|
|
24
|
+
export function initializePlugins(): void {
|
|
25
|
+
const plugins = getLoadedPluginNames();
|
|
26
|
+
console.log(`FlowQuery plugins loaded: ${plugins.join(', ')}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Get the list of loaded plugin names.
|
|
31
|
+
* Uses FlowQuery's introspection to discover registered async providers.
|
|
32
|
+
*/
|
|
33
|
+
export function getLoadedPluginNames(): string[] {
|
|
34
|
+
return FlowQuery.listFunctions({ asyncOnly: true }).map(f => f.name);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Get metadata for all loaded plugins.
|
|
39
|
+
* Uses FlowQuery's functions() introspection as the single source of truth.
|
|
40
|
+
*/
|
|
41
|
+
export function getAllPluginMetadata(): FunctionMetadata[] {
|
|
42
|
+
return FlowQuery.listFunctions({ asyncOnly: true });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Get all available async loader plugins by querying FlowQuery directly.
|
|
47
|
+
* This is the preferred async method that uses functions() introspection.
|
|
48
|
+
*
|
|
49
|
+
* @returns Promise resolving to array of plugin metadata
|
|
50
|
+
*/
|
|
51
|
+
export async function getAvailableLoaders(): Promise<FunctionMetadata[]> {
|
|
52
|
+
const runner = new FlowQuery(`
|
|
53
|
+
WITH functions() AS funcs
|
|
54
|
+
UNWIND funcs AS f
|
|
55
|
+
WHERE f.isAsyncProvider = true
|
|
56
|
+
RETURN f
|
|
57
|
+
`);
|
|
58
|
+
await runner.run();
|
|
59
|
+
return runner.results.map((r: any) => r.expr0 as FunctionMetadata);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Re-export types for external use
|
|
63
|
+
export type { FunctionMetadata, FunctionDefOptions, ParameterSchema, OutputSchema, AsyncDataProvider } from 'flowquery/extensibility';
|
|
64
|
+
export { FunctionDef } from 'flowquery/extensibility';
|
|
65
|
+
|
|
66
|
+
// Re-export standalone loader functions for use outside of FlowQuery
|
|
67
|
+
export { llm, llmStream, extractContent } from './loaders/Llm';
|
|
68
|
+
export type { LlmOptions, LlmResponse } from './loaders/Llm';
|