flowquery 1.0.8 → 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 (33) 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/keys.d.ts +7 -0
  7. package/dist/parsing/functions/keys.d.ts.map +1 -0
  8. package/dist/parsing/functions/keys.js +42 -0
  9. package/dist/parsing/functions/keys.js.map +1 -0
  10. package/docs/flowquery.min.js +1 -1
  11. package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
  12. package/misc/apps/RAG/package.json +3 -1
  13. package/misc/apps/RAG/src/components/AdaptiveCardRenderer.css +172 -0
  14. package/misc/apps/RAG/src/components/AdaptiveCardRenderer.tsx +312 -0
  15. package/misc/apps/RAG/src/components/ChatContainer.tsx +159 -112
  16. package/misc/apps/RAG/src/components/ChatInput.tsx +58 -44
  17. package/misc/apps/RAG/src/components/ChatMessage.tsx +186 -101
  18. package/misc/apps/RAG/src/components/FlowQueryAgent.ts +50 -6
  19. package/misc/apps/RAG/src/components/FlowQueryRunner.css +9 -0
  20. package/misc/apps/RAG/src/components/FlowQueryRunner.tsx +44 -5
  21. package/misc/apps/RAG/src/components/index.ts +4 -0
  22. package/misc/apps/RAG/src/plugins/index.ts +6 -4
  23. package/misc/apps/RAG/src/plugins/loaders/CatFacts.ts +1 -2
  24. package/misc/apps/RAG/src/plugins/loaders/FetchJson.ts +1 -2
  25. package/misc/apps/RAG/src/plugins/loaders/Form.ts +578 -0
  26. package/misc/apps/RAG/src/plugins/loaders/Llm.ts +1 -2
  27. package/misc/apps/RAG/src/plugins/loaders/MockData.ts +2 -4
  28. package/misc/apps/RAG/src/plugins/loaders/Table.ts +271 -0
  29. package/misc/apps/RAG/src/prompts/FlowQuerySystemPrompt.ts +12 -0
  30. package/package.json +1 -1
  31. package/src/parsing/functions/function_factory.ts +1 -0
  32. package/src/parsing/functions/keys.ts +31 -0
  33. package/tests/compute/runner.test.ts +8 -0
@@ -1,4 +1,4 @@
1
- import React, { useState, useCallback, useRef, useEffect } from 'react';
1
+ import React, { Component, createRef, RefObject } from 'react';
2
2
  import { Spinner } from '@fluentui/react-components';
3
3
  import { ChatMessage, Message } from './ChatMessage';
4
4
  import { ChatInput } from './ChatInput';
@@ -16,51 +16,75 @@ interface ChatContainerProps {
16
16
  showIntermediateSteps?: boolean;
17
17
  }
18
18
 
19
- export const ChatContainer: React.FC<ChatContainerProps> = ({
20
- systemPrompt = 'You are a helpful assistant. Be concise and informative in your responses.',
21
- llmOptions = {},
22
- useStreaming = true,
23
- useFlowQueryAgent = true,
24
- showIntermediateSteps = true
25
- }) => {
26
- const [messages, setMessages] = useState<Message[]>([]);
27
- const [isLoading, setIsLoading] = useState(false);
28
- const [error, setError] = useState<string | null>(null);
29
- const messagesEndRef = useRef<HTMLDivElement>(null);
30
-
31
- const scrollToBottom = useCallback(() => {
32
- messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
33
- }, []);
34
-
35
- useEffect(() => {
36
- scrollToBottom();
37
- }, [messages, scrollToBottom]);
38
-
39
- const generateMessageId = () => `msg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
40
-
41
- const buildConversationHistory = useCallback((currentMessages: Message[]) => {
19
+ interface ChatContainerState {
20
+ messages: Message[];
21
+ isLoading: boolean;
22
+ error: string | null;
23
+ }
24
+
25
+ export class ChatContainer extends Component<ChatContainerProps, ChatContainerState> {
26
+ static defaultProps: Partial<ChatContainerProps> = {
27
+ systemPrompt: 'You are a helpful assistant. Be concise and informative in your responses.',
28
+ llmOptions: {},
29
+ useStreaming: true,
30
+ useFlowQueryAgent: true,
31
+ showIntermediateSteps: true
32
+ };
33
+
34
+ private messagesEndRef: RefObject<HTMLDivElement | null>;
35
+
36
+ constructor(props: ChatContainerProps) {
37
+ super(props);
38
+ this.state = {
39
+ messages: [],
40
+ isLoading: false,
41
+ error: null
42
+ };
43
+ this.messagesEndRef = createRef<HTMLDivElement>();
44
+ }
45
+
46
+ componentDidUpdate(_prevProps: ChatContainerProps, prevState: ChatContainerState): void {
47
+ if (prevState.messages !== this.state.messages) {
48
+ this.scrollToBottom();
49
+ }
50
+ }
51
+
52
+ private scrollToBottom = (): void => {
53
+ this.messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
54
+ };
55
+
56
+ private generateMessageId = (): string => {
57
+ return `msg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
58
+ };
59
+
60
+ private buildConversationHistory = (currentMessages: Message[]): Array<{ role: 'user' | 'assistant'; content: string }> => {
42
61
  return currentMessages.map(msg => ({
43
62
  role: msg.role as 'user' | 'assistant',
44
63
  content: msg.content
45
64
  }));
46
- }, []);
65
+ };
66
+
67
+ private handleSendMessage = async (content: string): Promise<void> => {
68
+ const { systemPrompt, llmOptions, useStreaming, useFlowQueryAgent, showIntermediateSteps } = this.props;
69
+ const { messages } = this.state;
47
70
 
48
- const handleSendMessage = useCallback(async (content: string) => {
49
71
  const userMessage: Message = {
50
- id: generateMessageId(),
72
+ id: this.generateMessageId(),
51
73
  role: 'user',
52
74
  content,
53
75
  timestamp: new Date()
54
76
  };
55
77
 
56
- setMessages(prev => [...prev, userMessage]);
57
- setIsLoading(true);
58
- setError(null);
78
+ this.setState(prev => ({
79
+ messages: [...prev.messages, userMessage],
80
+ isLoading: true,
81
+ error: null
82
+ }));
59
83
 
60
- const assistantMessageId = generateMessageId();
84
+ const assistantMessageId = this.generateMessageId();
61
85
 
62
86
  try {
63
- const conversationHistory = buildConversationHistory([...messages, userMessage]);
87
+ const conversationHistory = this.buildConversationHistory([...messages, userMessage]);
64
88
 
65
89
  if (useFlowQueryAgent) {
66
90
  // Use the FlowQuery agent for processing
@@ -71,35 +95,43 @@ export const ChatContainer: React.FC<ChatContainerProps> = ({
71
95
  timestamp: new Date(),
72
96
  isStreaming: true
73
97
  };
74
- setMessages(prev => [...prev, assistantMessage]);
98
+ this.setState(prev => ({
99
+ messages: [...prev.messages, assistantMessage]
100
+ }));
75
101
 
76
102
  let fullContent = '';
103
+ let adaptiveCardFromStream: Record<string, unknown> | undefined;
77
104
 
78
- for await (const { chunk, done } of processQueryStream(content, {
79
- systemPrompt,
105
+ for await (const { chunk, done, adaptiveCard } of processQueryStream(content, {
106
+ systemPrompt: systemPrompt ?? 'You are a helpful assistant. Be concise and informative in your responses.',
80
107
  llmOptions,
81
108
  conversationHistory: conversationHistory.slice(0, -1),
82
109
  showIntermediateSteps
83
110
  })) {
84
111
  if (chunk) {
85
112
  fullContent += chunk;
86
- setMessages(prev =>
87
- prev.map(msg =>
113
+ this.setState(prev => ({
114
+ messages: prev.messages.map(msg =>
88
115
  msg.id === assistantMessageId
89
116
  ? { ...msg, content: fullContent }
90
117
  : msg
91
118
  )
92
- );
119
+ }));
120
+ }
121
+
122
+ // Capture adaptive card if present
123
+ if (adaptiveCard) {
124
+ adaptiveCardFromStream = adaptiveCard;
93
125
  }
94
126
 
95
127
  if (done) {
96
- setMessages(prev =>
97
- prev.map(msg =>
128
+ this.setState(prev => ({
129
+ messages: prev.messages.map(msg =>
98
130
  msg.id === assistantMessageId
99
- ? { ...msg, isStreaming: false }
131
+ ? { ...msg, isStreaming: false, adaptiveCard: adaptiveCardFromStream }
100
132
  : msg
101
133
  )
102
- );
134
+ }));
103
135
  }
104
136
  }
105
137
  } else {
@@ -120,30 +152,32 @@ export const ChatContainer: React.FC<ChatContainerProps> = ({
120
152
  timestamp: new Date(),
121
153
  isStreaming: true
122
154
  };
123
- setMessages(prev => [...prev, assistantMessage]);
155
+ this.setState(prev => ({
156
+ messages: [...prev.messages, assistantMessage]
157
+ }));
124
158
 
125
159
  let fullContent = '';
126
160
  for await (const chunk of llmStream(content, options)) {
127
161
  const deltaContent = chunk.choices?.[0]?.delta?.content || '';
128
162
  if (deltaContent) {
129
163
  fullContent += deltaContent;
130
- setMessages(prev =>
131
- prev.map(msg =>
164
+ this.setState(prev => ({
165
+ messages: prev.messages.map(msg =>
132
166
  msg.id === assistantMessageId
133
167
  ? { ...msg, content: fullContent }
134
168
  : msg
135
169
  )
136
- );
170
+ }));
137
171
  }
138
172
  }
139
173
 
140
- setMessages(prev =>
141
- prev.map(msg =>
174
+ this.setState(prev => ({
175
+ messages: prev.messages.map(msg =>
142
176
  msg.id === assistantMessageId
143
177
  ? { ...msg, isStreaming: false }
144
178
  : msg
145
179
  )
146
- );
180
+ }));
147
181
  } else {
148
182
  const response = await llm(content, options);
149
183
  const assistantContent = response.choices[0]?.message?.content || 'No response received.';
@@ -154,86 +188,99 @@ export const ChatContainer: React.FC<ChatContainerProps> = ({
154
188
  content: assistantContent,
155
189
  timestamp: new Date()
156
190
  };
157
- setMessages(prev => [...prev, assistantMessage]);
191
+ this.setState(prev => ({
192
+ messages: [...prev.messages, assistantMessage]
193
+ }));
158
194
  }
159
195
  }
160
196
  } catch (err) {
161
197
  const errorMessage = err instanceof Error ? err.message : 'An error occurred while processing your request.';
162
- setError(errorMessage);
163
198
 
164
199
  // Add or update error message as assistant response
165
200
  const errorContent = `⚠️ Error: ${errorMessage}`;
166
- setMessages(prev => {
201
+ this.setState(prev => {
167
202
  // Check if we already added a streaming message with this ID
168
- const existingMessageIndex = prev.findIndex(msg => msg.id === assistantMessageId);
203
+ const existingMessageIndex = prev.messages.findIndex(msg => msg.id === assistantMessageId);
169
204
  if (existingMessageIndex !== -1) {
170
205
  // Update existing message
171
- return prev.map(msg =>
172
- msg.id === assistantMessageId
173
- ? { ...msg, content: errorContent, isStreaming: false }
174
- : msg
175
- );
206
+ return {
207
+ messages: prev.messages.map(msg =>
208
+ msg.id === assistantMessageId
209
+ ? { ...msg, content: errorContent, isStreaming: false }
210
+ : msg
211
+ ),
212
+ error: errorMessage
213
+ };
176
214
  } else {
177
215
  // Add new error message
178
- return [...prev, {
179
- id: assistantMessageId,
180
- role: 'assistant' as const,
181
- content: errorContent,
182
- timestamp: new Date()
183
- }];
216
+ return {
217
+ messages: [...prev.messages, {
218
+ id: assistantMessageId,
219
+ role: 'assistant' as const,
220
+ content: errorContent,
221
+ timestamp: new Date()
222
+ }],
223
+ error: errorMessage
224
+ };
184
225
  }
185
226
  });
186
227
  } finally {
187
- setIsLoading(false);
228
+ this.setState({ isLoading: false });
188
229
  }
189
- }, [messages, systemPrompt, llmOptions, useStreaming, useFlowQueryAgent, showIntermediateSteps, buildConversationHistory]);
190
-
191
- const handleClearChat = useCallback(() => {
192
- setMessages([]);
193
- setError(null);
194
- }, []);
195
-
196
- return (
197
- <div className="chat-container">
198
- <div className="chat-messages">
199
- {messages.length === 0 ? (
200
- <div className="chat-empty-state">
201
- <p>Start a conversation by typing a message below.</p>
230
+ };
231
+
232
+ private handleClearChat = (): void => {
233
+ this.setState({
234
+ messages: [],
235
+ error: null
236
+ });
237
+ };
238
+
239
+ render(): React.ReactNode {
240
+ const { messages, isLoading, error } = this.state;
241
+
242
+ return (
243
+ <div className="chat-container">
244
+ <div className="chat-messages">
245
+ {messages.length === 0 ? (
246
+ <div className="chat-empty-state">
247
+ <p>Start a conversation by typing a message below.</p>
248
+ </div>
249
+ ) : (
250
+ messages.map(message => (
251
+ <ChatMessage key={message.id} message={message} />
252
+ ))
253
+ )}
254
+ {isLoading && messages[messages.length - 1]?.role === 'user' && (
255
+ <div className="chat-loading">
256
+ <Spinner size="small" label="Thinking..." />
257
+ </div>
258
+ )}
259
+ <div ref={this.messagesEndRef} />
260
+ </div>
261
+
262
+ {error && !messages.some(m => m.content.includes(error)) && (
263
+ <div className="chat-error">
264
+ {error}
202
265
  </div>
203
- ) : (
204
- messages.map(message => (
205
- <ChatMessage key={message.id} message={message} />
206
- ))
207
266
  )}
208
- {isLoading && messages[messages.length - 1]?.role === 'user' && (
209
- <div className="chat-loading">
210
- <Spinner size="small" label="Thinking..." />
211
- </div>
267
+
268
+ <ChatInput
269
+ onSendMessage={this.handleSendMessage}
270
+ isLoading={isLoading}
271
+ placeholder="Ask me anything..."
272
+ />
273
+
274
+ {messages.length > 0 && (
275
+ <button
276
+ className="chat-clear-button"
277
+ onClick={this.handleClearChat}
278
+ disabled={isLoading}
279
+ >
280
+ Clear conversation
281
+ </button>
212
282
  )}
213
- <div ref={messagesEndRef} />
214
283
  </div>
215
-
216
- {error && !messages.some(m => m.content.includes(error)) && (
217
- <div className="chat-error">
218
- {error}
219
- </div>
220
- )}
221
-
222
- <ChatInput
223
- onSendMessage={handleSendMessage}
224
- isLoading={isLoading}
225
- placeholder="Ask me anything..."
226
- />
227
-
228
- {messages.length > 0 && (
229
- <button
230
- className="chat-clear-button"
231
- onClick={handleClearChat}
232
- disabled={isLoading}
233
- >
234
- Clear conversation
235
- </button>
236
- )}
237
- </div>
238
- );
239
- };
284
+ );
285
+ }
286
+ }
@@ -1,4 +1,4 @@
1
- import React, { useState, useCallback, KeyboardEvent } from 'react';
1
+ import React, { Component, KeyboardEvent } from 'react';
2
2
  import { Textarea, Button } from '@fluentui/react-components';
3
3
  import { SendFilled } from '@fluentui/react-icons';
4
4
  import './ChatInput.css';
@@ -9,54 +9,68 @@ interface ChatInputProps {
9
9
  placeholder?: string;
10
10
  }
11
11
 
12
- export const ChatInput: React.FC<ChatInputProps> = ({
13
- onSendMessage,
14
- isLoading,
15
- placeholder = 'Ask me anything...'
16
- }) => {
17
- const [inputValue, setInputValue] = useState('');
18
-
19
- const handleSend = useCallback(() => {
20
- const trimmedValue = inputValue.trim();
21
- if (trimmedValue && !isLoading) {
22
- onSendMessage(trimmedValue);
23
- setInputValue('');
12
+ interface ChatInputState {
13
+ inputValue: string;
14
+ }
15
+
16
+ export class ChatInput extends Component<ChatInputProps, ChatInputState> {
17
+ static defaultProps = {
18
+ placeholder: 'Ask me anything...'
19
+ };
20
+
21
+ constructor(props: ChatInputProps) {
22
+ super(props);
23
+ this.state = {
24
+ inputValue: ''
25
+ };
26
+ }
27
+
28
+ handleSend = (): void => {
29
+ const trimmedValue = this.state.inputValue.trim();
30
+ if (trimmedValue && !this.props.isLoading) {
31
+ this.props.onSendMessage(trimmedValue);
32
+ this.setState({ inputValue: '' });
24
33
  }
25
- }, [inputValue, isLoading, onSendMessage]);
34
+ };
26
35
 
27
- const handleKeyDown = useCallback((e: KeyboardEvent<HTMLTextAreaElement>) => {
36
+ handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>): void => {
28
37
  if (e.key === 'Enter' && !e.shiftKey) {
29
38
  e.preventDefault();
30
- handleSend();
39
+ this.handleSend();
31
40
  }
32
- }, [handleSend]);
41
+ };
33
42
 
34
- const handleChange = useCallback((
43
+ handleChange = (
35
44
  _e: React.ChangeEvent<HTMLTextAreaElement>,
36
45
  data: { value: string }
37
- ) => {
38
- setInputValue(data.value);
39
- }, []);
40
-
41
- return (
42
- <div className="chat-input-container">
43
- <Textarea
44
- className="chat-input-textarea"
45
- value={inputValue}
46
- onChange={handleChange}
47
- onKeyDown={handleKeyDown}
48
- placeholder={placeholder}
49
- resize="none"
50
- disabled={isLoading}
51
- />
52
- <Button
53
- className="chat-input-send-button"
54
- appearance="primary"
55
- icon={<SendFilled />}
56
- onClick={handleSend}
57
- disabled={isLoading || !inputValue.trim()}
58
- title="Send message (Enter)"
59
- />
60
- </div>
61
- );
62
- };
46
+ ): void => {
47
+ this.setState({ inputValue: data.value });
48
+ };
49
+
50
+ render() {
51
+ const { isLoading, placeholder } = this.props;
52
+ const { inputValue } = this.state;
53
+
54
+ return (
55
+ <div className="chat-input-container">
56
+ <Textarea
57
+ className="chat-input-textarea"
58
+ value={inputValue}
59
+ onChange={this.handleChange}
60
+ onKeyDown={this.handleKeyDown}
61
+ placeholder={placeholder}
62
+ resize="none"
63
+ disabled={isLoading}
64
+ />
65
+ <Button
66
+ className="chat-input-send-button"
67
+ appearance="primary"
68
+ icon={<SendFilled />}
69
+ onClick={this.handleSend}
70
+ disabled={isLoading || !inputValue.trim()}
71
+ title="Send message (Enter)"
72
+ />
73
+ </div>
74
+ );
75
+ }
76
+ }