flowquery 1.0.7 → 1.0.9

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 (39) hide show
  1. package/dist/flowquery.min.js +1 -1
  2. package/dist/parsing/functions/function_factory.d.ts +1 -0
  3. package/dist/parsing/functions/function_factory.d.ts.map +1 -1
  4. package/dist/parsing/functions/function_factory.js +1 -0
  5. package/dist/parsing/functions/function_factory.js.map +1 -1
  6. package/dist/parsing/functions/function_metadata.d.ts +0 -17
  7. package/dist/parsing/functions/function_metadata.d.ts.map +1 -1
  8. package/dist/parsing/functions/function_metadata.js +61 -86
  9. package/dist/parsing/functions/function_metadata.js.map +1 -1
  10. package/dist/parsing/functions/keys.d.ts +7 -0
  11. package/dist/parsing/functions/keys.d.ts.map +1 -0
  12. package/dist/parsing/functions/keys.js +42 -0
  13. package/dist/parsing/functions/keys.js.map +1 -0
  14. package/docs/flowquery.min.js +1 -1
  15. package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
  16. package/misc/apps/RAG/package.json +3 -1
  17. package/misc/apps/RAG/src/components/AdaptiveCardRenderer.css +172 -0
  18. package/misc/apps/RAG/src/components/AdaptiveCardRenderer.tsx +312 -0
  19. package/misc/apps/RAG/src/components/ChatContainer.tsx +159 -112
  20. package/misc/apps/RAG/src/components/ChatInput.tsx +58 -44
  21. package/misc/apps/RAG/src/components/ChatMessage.tsx +186 -101
  22. package/misc/apps/RAG/src/components/FlowQueryAgent.ts +50 -6
  23. package/misc/apps/RAG/src/components/FlowQueryRunner.css +9 -0
  24. package/misc/apps/RAG/src/components/FlowQueryRunner.tsx +44 -5
  25. package/misc/apps/RAG/src/components/index.ts +4 -0
  26. package/misc/apps/RAG/src/plugins/index.ts +6 -4
  27. package/misc/apps/RAG/src/plugins/loaders/CatFacts.ts +1 -2
  28. package/misc/apps/RAG/src/plugins/loaders/FetchJson.ts +1 -2
  29. package/misc/apps/RAG/src/plugins/loaders/Form.ts +578 -0
  30. package/misc/apps/RAG/src/plugins/loaders/Llm.ts +1 -2
  31. package/misc/apps/RAG/src/plugins/loaders/MockData.ts +2 -4
  32. package/misc/apps/RAG/src/plugins/loaders/Table.ts +271 -0
  33. package/misc/apps/RAG/src/prompts/FlowQuerySystemPrompt.ts +12 -0
  34. package/package.json +1 -1
  35. package/src/parsing/functions/function_factory.ts +1 -0
  36. package/src/parsing/functions/function_metadata.ts +67 -108
  37. package/src/parsing/functions/keys.ts +31 -0
  38. package/tests/compute/runner.test.ts +8 -0
  39. package/tests/extensibility.test.ts +38 -0
@@ -0,0 +1,578 @@
1
+ /**
2
+ * Form loader plugin - transforms configuration into Adaptive Card form format.
3
+ *
4
+ * Adaptive Cards are platform-agnostic UI snippets that can be rendered in
5
+ * Microsoft Teams, Outlook, Windows, and other applications.
6
+ *
7
+ * This loader creates customizable forms with various input types including:
8
+ * - Text inputs (single and multi-line)
9
+ * - Number inputs
10
+ * - Date and time pickers
11
+ * - Dropdown/choice sets
12
+ * - Toggle switches
13
+ * - Choice sets (radio buttons, checkboxes)
14
+ *
15
+ * Usage in FlowQuery:
16
+ * // Create a simple contact form:
17
+ * LOAD JSON FROM form('Contact Us', [
18
+ * { id: 'name', type: 'text', label: 'Your Name', required: true },
19
+ * { id: 'email', type: 'text', label: 'Email', placeholder: 'you@example.com' },
20
+ * { id: 'message', type: 'textarea', label: 'Message' }
21
+ * ]) AS form
22
+ * RETURN form
23
+ */
24
+
25
+ import { FunctionDef } from 'flowquery/extensibility';
26
+
27
+ /**
28
+ * Interface for Adaptive Card structure
29
+ */
30
+ interface AdaptiveCard {
31
+ type: 'AdaptiveCard';
32
+ $schema: string;
33
+ version: string;
34
+ body: AdaptiveCardElement[];
35
+ actions?: AdaptiveCardAction[];
36
+ }
37
+
38
+ interface AdaptiveCardElement {
39
+ type: string;
40
+ [key: string]: any;
41
+ }
42
+
43
+ interface AdaptiveCardAction {
44
+ type: string;
45
+ title: string;
46
+ [key: string]: any;
47
+ }
48
+
49
+ /**
50
+ * Input field configuration
51
+ */
52
+ interface FormFieldConfig {
53
+ /** Unique identifier for the field */
54
+ id: string;
55
+ /** Input type: text, textarea, number, date, time, datetime, toggle, dropdown, radio, checkbox */
56
+ type: 'text' | 'textarea' | 'number' | 'date' | 'time' | 'datetime' | 'toggle' | 'dropdown' | 'radio' | 'checkbox';
57
+ /** Display label for the field */
58
+ label: string;
59
+ /** Placeholder text for input fields */
60
+ placeholder?: string;
61
+ /** Default value */
62
+ defaultValue?: any;
63
+ /** Whether the field is required */
64
+ required?: boolean;
65
+ /** Choices for dropdown/radio/checkbox types */
66
+ choices?: Array<{ title: string; value: string }> | string[];
67
+ /** Minimum value for number inputs */
68
+ min?: number;
69
+ /** Maximum value for number inputs */
70
+ max?: number;
71
+ /** Regex pattern for validation (displayed in error message) */
72
+ pattern?: string;
73
+ /** Error message for validation */
74
+ errorMessage?: string;
75
+ /** Toggle title (for toggle type) */
76
+ toggleTitle?: string;
77
+ /** Whether the field is read-only */
78
+ readOnly?: boolean;
79
+ /** Separator before this field */
80
+ separator?: boolean;
81
+ /** Field width: auto, stretch, or weighted value */
82
+ width?: 'auto' | 'stretch' | number;
83
+ /** Custom style for the label */
84
+ labelStyle?: 'default' | 'heading';
85
+ }
86
+
87
+ /**
88
+ * Form configuration options
89
+ */
90
+ interface FormConfig {
91
+ /** Form title */
92
+ title?: string;
93
+ /** Form description/subtitle */
94
+ description?: string;
95
+ /** Submit button configuration */
96
+ submitButton?: {
97
+ title?: string;
98
+ style?: 'default' | 'positive' | 'destructive';
99
+ /** Action URL for form submission */
100
+ url?: string;
101
+ /** Action type: submit, openUrl, or custom */
102
+ actionType?: 'submit' | 'openUrl' | 'showCard';
103
+ };
104
+ /** Additional action buttons */
105
+ additionalActions?: Array<{
106
+ title: string;
107
+ type: 'submit' | 'openUrl' | 'showCard';
108
+ url?: string;
109
+ style?: 'default' | 'positive' | 'destructive';
110
+ data?: any;
111
+ }>;
112
+ /** Card background style */
113
+ style?: 'default' | 'emphasis' | 'good' | 'attention' | 'warning' | 'accent';
114
+ /** Whether to show a reset/clear button */
115
+ showResetButton?: boolean;
116
+ /** Card schema version */
117
+ version?: string;
118
+ }
119
+
120
+ /**
121
+ * Form loader - creates customizable Adaptive Card forms.
122
+ */
123
+ @FunctionDef({
124
+ description: 'Creates a customizable Adaptive Card form with various input types',
125
+ category: 'async',
126
+ parameters: [
127
+ {
128
+ name: 'title',
129
+ description: 'Form title displayed at the top',
130
+ type: 'string',
131
+ required: true
132
+ },
133
+ {
134
+ name: 'fields',
135
+ description: 'Array of field configurations defining the form inputs',
136
+ type: 'array',
137
+ required: true
138
+ },
139
+ {
140
+ name: 'config',
141
+ description: 'Optional form configuration (submit button, additional actions, styling)',
142
+ type: 'object',
143
+ required: false
144
+ }
145
+ ],
146
+ output: {
147
+ description: 'Adaptive Card JSON object with form elements',
148
+ type: 'object',
149
+ properties: {
150
+ type: { description: 'Always "AdaptiveCard"', type: 'string' },
151
+ $schema: { description: 'Adaptive Card schema URL', type: 'string' },
152
+ version: { description: 'Adaptive Card version', type: 'string' },
153
+ body: { description: 'Card body elements including form inputs', type: 'array' },
154
+ actions: { description: 'Card actions (submit, cancel, etc.)', type: 'array' }
155
+ }
156
+ },
157
+ examples: [
158
+ "LOAD JSON FROM form('Contact Form', [{ id: 'name', type: 'text', label: 'Name', required: true }, { id: 'email', type: 'text', label: 'Email' }]) AS form RETURN form",
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
+ ]
161
+ })
162
+ export class FormLoader {
163
+ /**
164
+ * Creates an Adaptive Card form with the specified fields and configuration.
165
+ *
166
+ * @param title - Form title
167
+ * @param fields - Array of field configurations
168
+ * @param config - Optional form configuration
169
+ */
170
+ async *fetch(
171
+ title: string,
172
+ fields: FormFieldConfig[],
173
+ config?: FormConfig
174
+ ): AsyncGenerator<AdaptiveCard, void, unknown> {
175
+ const card = this.createFormCard(title, fields, config || {});
176
+ yield card;
177
+ }
178
+
179
+ /**
180
+ * Creates the Adaptive Card with form elements.
181
+ */
182
+ private createFormCard(
183
+ title: string,
184
+ fields: FormFieldConfig[],
185
+ config: FormConfig
186
+ ): AdaptiveCard {
187
+ const card: AdaptiveCard = {
188
+ type: 'AdaptiveCard',
189
+ $schema: 'http://adaptivecards.io/schemas/adaptive-card.json',
190
+ version: config.version || '1.5',
191
+ body: [],
192
+ actions: []
193
+ };
194
+
195
+ // Add container with optional background style
196
+ const container: AdaptiveCardElement = {
197
+ type: 'Container',
198
+ style: config.style || 'default',
199
+ items: []
200
+ };
201
+
202
+ // Add title
203
+ container.items.push({
204
+ type: 'TextBlock',
205
+ text: title,
206
+ weight: 'Bolder',
207
+ size: 'Large',
208
+ wrap: true
209
+ });
210
+
211
+ // Add description if provided
212
+ if (config.description) {
213
+ container.items.push({
214
+ type: 'TextBlock',
215
+ text: config.description,
216
+ isSubtle: true,
217
+ wrap: true,
218
+ spacing: 'Small'
219
+ });
220
+ }
221
+
222
+ // Add separator after header
223
+ container.items.push({
224
+ type: 'TextBlock',
225
+ text: ' ',
226
+ separator: true,
227
+ spacing: 'Medium'
228
+ });
229
+
230
+ // Add form fields
231
+ for (const field of fields) {
232
+ const fieldElements = this.createFieldElements(field);
233
+ container.items.push(...fieldElements);
234
+ }
235
+
236
+ card.body.push(container);
237
+
238
+ // Add actions
239
+ card.actions = this.createActions(config);
240
+
241
+ return card;
242
+ }
243
+
244
+ /**
245
+ * Creates the elements for a single form field (label + input).
246
+ */
247
+ private createFieldElements(field: FormFieldConfig): AdaptiveCardElement[] {
248
+ const elements: AdaptiveCardElement[] = [];
249
+
250
+ // Add label
251
+ const labelText = field.required ? `${field.label} *` : field.label;
252
+ elements.push({
253
+ type: 'TextBlock',
254
+ text: labelText,
255
+ weight: field.labelStyle === 'heading' ? 'Bolder' : 'Default',
256
+ wrap: true,
257
+ separator: field.separator || false,
258
+ spacing: field.separator ? 'Large' : 'Default'
259
+ });
260
+
261
+ // Add input based on type
262
+ const inputElement = this.createInputElement(field);
263
+ elements.push(inputElement);
264
+
265
+ return elements;
266
+ }
267
+
268
+ /**
269
+ * Creates the appropriate input element based on field type.
270
+ */
271
+ private createInputElement(field: FormFieldConfig): AdaptiveCardElement {
272
+ switch (field.type) {
273
+ case 'text':
274
+ return this.createTextInput(field, false);
275
+
276
+ case 'textarea':
277
+ return this.createTextInput(field, true);
278
+
279
+ case 'number':
280
+ return this.createNumberInput(field);
281
+
282
+ case 'date':
283
+ return this.createDateInput(field);
284
+
285
+ case 'time':
286
+ return this.createTimeInput(field);
287
+
288
+ case 'datetime':
289
+ return this.createDateTimeInputs(field);
290
+
291
+ case 'toggle':
292
+ return this.createToggleInput(field);
293
+
294
+ case 'dropdown':
295
+ return this.createChoiceSet(field, 'compact');
296
+
297
+ case 'radio':
298
+ return this.createChoiceSet(field, 'expanded');
299
+
300
+ case 'checkbox':
301
+ return this.createChoiceSet(field, 'expanded', true);
302
+
303
+ default:
304
+ return this.createTextInput(field, false);
305
+ }
306
+ }
307
+
308
+ /**
309
+ * Creates a text input element.
310
+ */
311
+ private createTextInput(field: FormFieldConfig, isMultiLine: boolean): AdaptiveCardElement {
312
+ const input: AdaptiveCardElement = {
313
+ type: 'Input.Text',
314
+ id: field.id,
315
+ placeholder: field.placeholder || '',
316
+ isMultiline: isMultiLine,
317
+ isRequired: field.required || false
318
+ };
319
+
320
+ if (field.defaultValue !== undefined) {
321
+ input.value = String(field.defaultValue);
322
+ }
323
+
324
+ if (field.pattern) {
325
+ input.regex = field.pattern;
326
+ }
327
+
328
+ if (field.errorMessage) {
329
+ input.errorMessage = field.errorMessage;
330
+ }
331
+
332
+ if (isMultiLine) {
333
+ input.style = 'text';
334
+ }
335
+
336
+ return input;
337
+ }
338
+
339
+ /**
340
+ * Creates a number input element.
341
+ */
342
+ private createNumberInput(field: FormFieldConfig): AdaptiveCardElement {
343
+ const input: AdaptiveCardElement = {
344
+ type: 'Input.Number',
345
+ id: field.id,
346
+ placeholder: field.placeholder || '',
347
+ isRequired: field.required || false
348
+ };
349
+
350
+ if (field.defaultValue !== undefined) {
351
+ input.value = Number(field.defaultValue);
352
+ }
353
+
354
+ if (field.min !== undefined) {
355
+ input.min = field.min;
356
+ }
357
+
358
+ if (field.max !== undefined) {
359
+ input.max = field.max;
360
+ }
361
+
362
+ if (field.errorMessage) {
363
+ input.errorMessage = field.errorMessage;
364
+ }
365
+
366
+ return input;
367
+ }
368
+
369
+ /**
370
+ * Creates a date input element.
371
+ */
372
+ private createDateInput(field: FormFieldConfig): AdaptiveCardElement {
373
+ const input: AdaptiveCardElement = {
374
+ type: 'Input.Date',
375
+ id: field.id,
376
+ isRequired: field.required || false
377
+ };
378
+
379
+ if (field.defaultValue !== undefined) {
380
+ input.value = String(field.defaultValue);
381
+ }
382
+
383
+ if (field.placeholder) {
384
+ input.placeholder = field.placeholder;
385
+ }
386
+
387
+ return input;
388
+ }
389
+
390
+ /**
391
+ * Creates a time input element.
392
+ */
393
+ private createTimeInput(field: FormFieldConfig): AdaptiveCardElement {
394
+ const input: AdaptiveCardElement = {
395
+ type: 'Input.Time',
396
+ id: field.id,
397
+ isRequired: field.required || false
398
+ };
399
+
400
+ if (field.defaultValue !== undefined) {
401
+ input.value = String(field.defaultValue);
402
+ }
403
+
404
+ if (field.placeholder) {
405
+ input.placeholder = field.placeholder;
406
+ }
407
+
408
+ return input;
409
+ }
410
+
411
+ /**
412
+ * Creates date and time inputs in a column set for datetime fields.
413
+ */
414
+ private createDateTimeInputs(field: FormFieldConfig): AdaptiveCardElement {
415
+ const dateValue = field.defaultValue ? String(field.defaultValue).split('T')[0] : undefined;
416
+ const timeValue = field.defaultValue ? String(field.defaultValue).split('T')[1]?.substring(0, 5) : undefined;
417
+
418
+ return {
419
+ type: 'ColumnSet',
420
+ columns: [
421
+ {
422
+ type: 'Column',
423
+ width: 'stretch',
424
+ items: [{
425
+ type: 'Input.Date',
426
+ id: `${field.id}_date`,
427
+ isRequired: field.required || false,
428
+ value: dateValue
429
+ }]
430
+ },
431
+ {
432
+ type: 'Column',
433
+ width: 'stretch',
434
+ items: [{
435
+ type: 'Input.Time',
436
+ id: `${field.id}_time`,
437
+ isRequired: field.required || false,
438
+ value: timeValue
439
+ }]
440
+ }
441
+ ]
442
+ };
443
+ }
444
+
445
+ /**
446
+ * Creates a toggle input element.
447
+ */
448
+ private createToggleInput(field: FormFieldConfig): AdaptiveCardElement {
449
+ const input: AdaptiveCardElement = {
450
+ type: 'Input.Toggle',
451
+ id: field.id,
452
+ title: field.toggleTitle || field.label,
453
+ valueOn: 'true',
454
+ valueOff: 'false',
455
+ isRequired: field.required || false
456
+ };
457
+
458
+ if (field.defaultValue !== undefined) {
459
+ input.value = field.defaultValue ? 'true' : 'false';
460
+ }
461
+
462
+ return input;
463
+ }
464
+
465
+ /**
466
+ * Creates a choice set (dropdown, radio, or checkbox).
467
+ */
468
+ private createChoiceSet(
469
+ field: FormFieldConfig,
470
+ style: 'compact' | 'expanded',
471
+ isMultiSelect: boolean = false
472
+ ): AdaptiveCardElement {
473
+ const choices = this.normalizeChoices(field.choices || []);
474
+
475
+ const input: AdaptiveCardElement = {
476
+ type: 'Input.ChoiceSet',
477
+ id: field.id,
478
+ style: style,
479
+ isMultiSelect: isMultiSelect,
480
+ isRequired: field.required || false,
481
+ choices: choices
482
+ };
483
+
484
+ if (field.defaultValue !== undefined) {
485
+ input.value = String(field.defaultValue);
486
+ }
487
+
488
+ if (field.placeholder && style === 'compact') {
489
+ input.placeholder = field.placeholder;
490
+ }
491
+
492
+ return input;
493
+ }
494
+
495
+ /**
496
+ * Normalizes choices to the expected format.
497
+ */
498
+ private normalizeChoices(choices: Array<{ title: string; value: string }> | string[]): Array<{ title: string; value: string }> {
499
+ return choices.map(choice => {
500
+ if (typeof choice === 'string') {
501
+ return { title: choice, value: choice };
502
+ }
503
+ return choice;
504
+ });
505
+ }
506
+
507
+ /**
508
+ * Creates the action buttons for the form.
509
+ */
510
+ private createActions(config: FormConfig): AdaptiveCardAction[] {
511
+ const actions: AdaptiveCardAction[] = [];
512
+
513
+ // Add submit button
514
+ const submitConfig = config.submitButton || {};
515
+ const submitAction: AdaptiveCardAction = {
516
+ type: this.getActionType(submitConfig.actionType || 'submit'),
517
+ title: submitConfig.title || 'Submit',
518
+ style: submitConfig.style || 'positive'
519
+ };
520
+
521
+ if (submitConfig.actionType === 'openUrl' && submitConfig.url) {
522
+ submitAction.url = submitConfig.url;
523
+ }
524
+
525
+ actions.push(submitAction);
526
+
527
+ // Add reset button if requested
528
+ if (config.showResetButton) {
529
+ actions.push({
530
+ type: 'Action.Submit',
531
+ title: 'Reset',
532
+ style: 'default',
533
+ data: { action: 'reset' }
534
+ });
535
+ }
536
+
537
+ // Add additional actions
538
+ if (config.additionalActions) {
539
+ for (const actionConfig of config.additionalActions) {
540
+ const action: AdaptiveCardAction = {
541
+ type: this.getActionType(actionConfig.type),
542
+ title: actionConfig.title,
543
+ style: actionConfig.style || 'default'
544
+ };
545
+
546
+ if (actionConfig.type === 'openUrl' && actionConfig.url) {
547
+ action.url = actionConfig.url;
548
+ }
549
+
550
+ if (actionConfig.data) {
551
+ action.data = actionConfig.data;
552
+ }
553
+
554
+ actions.push(action);
555
+ }
556
+ }
557
+
558
+ return actions;
559
+ }
560
+
561
+ /**
562
+ * Gets the Adaptive Card action type string.
563
+ */
564
+ private getActionType(type: string): string {
565
+ switch (type) {
566
+ case 'submit':
567
+ return 'Action.Submit';
568
+ case 'openUrl':
569
+ return 'Action.OpenUrl';
570
+ case 'showCard':
571
+ return 'Action.ShowCard';
572
+ default:
573
+ return 'Action.Submit';
574
+ }
575
+ }
576
+ }
577
+
578
+ export { FormLoader as default };
@@ -81,9 +81,8 @@ export interface LlmResponse {
81
81
  * LLM Loader class - calls OpenAI-compatible APIs for chat completions.
82
82
  */
83
83
  @FunctionDef({
84
- isAsyncProvider: true,
85
84
  description: 'Calls OpenAI-compatible chat completion APIs. Supports GPT models and any OpenAI-compatible endpoint.',
86
- category: 'ai',
85
+ category: 'async',
87
86
  parameters: [
88
87
  {
89
88
  name: 'prompt',
@@ -12,9 +12,8 @@ import { FunctionDef } from 'flowquery/extensibility';
12
12
  * MockUsers loader class - generates mock user data for testing.
13
13
  */
14
14
  @FunctionDef({
15
- isAsyncProvider: true,
16
15
  description: 'Generates mock user data for testing purposes',
17
- category: 'testing',
16
+ category: 'async',
18
17
  parameters: [
19
18
  {
20
19
  name: 'count',
@@ -81,9 +80,8 @@ export class MockUsersLoader {
81
80
  * MockProducts loader class - generates mock product data for testing.
82
81
  */
83
82
  @FunctionDef({
84
- isAsyncProvider: true,
85
83
  description: 'Generates mock product data for testing purposes',
86
- category: 'testing',
84
+ category: 'async',
87
85
  parameters: [
88
86
  {
89
87
  name: 'count',