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.
- package/dist/flowquery.min.js +1 -1
- package/dist/parsing/functions/function_factory.d.ts +1 -0
- package/dist/parsing/functions/function_factory.d.ts.map +1 -1
- package/dist/parsing/functions/function_factory.js +1 -0
- package/dist/parsing/functions/function_factory.js.map +1 -1
- package/dist/parsing/functions/keys.d.ts +7 -0
- package/dist/parsing/functions/keys.d.ts.map +1 -0
- package/dist/parsing/functions/keys.js +42 -0
- package/dist/parsing/functions/keys.js.map +1 -0
- package/docs/flowquery.min.js +1 -1
- package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
- package/misc/apps/RAG/package.json +3 -1
- package/misc/apps/RAG/src/components/AdaptiveCardRenderer.css +172 -0
- package/misc/apps/RAG/src/components/AdaptiveCardRenderer.tsx +312 -0
- package/misc/apps/RAG/src/components/ChatContainer.tsx +159 -112
- package/misc/apps/RAG/src/components/ChatInput.tsx +58 -44
- package/misc/apps/RAG/src/components/ChatMessage.tsx +186 -101
- package/misc/apps/RAG/src/components/FlowQueryAgent.ts +50 -6
- package/misc/apps/RAG/src/components/FlowQueryRunner.css +9 -0
- package/misc/apps/RAG/src/components/FlowQueryRunner.tsx +44 -5
- package/misc/apps/RAG/src/components/index.ts +4 -0
- package/misc/apps/RAG/src/plugins/index.ts +6 -4
- package/misc/apps/RAG/src/plugins/loaders/CatFacts.ts +1 -2
- package/misc/apps/RAG/src/plugins/loaders/FetchJson.ts +1 -2
- package/misc/apps/RAG/src/plugins/loaders/Form.ts +578 -0
- package/misc/apps/RAG/src/plugins/loaders/Llm.ts +1 -2
- package/misc/apps/RAG/src/plugins/loaders/MockData.ts +2 -4
- package/misc/apps/RAG/src/plugins/loaders/Table.ts +271 -0
- package/misc/apps/RAG/src/prompts/FlowQuerySystemPrompt.ts +12 -0
- package/package.json +1 -1
- package/src/parsing/functions/function_factory.ts +1 -0
- package/src/parsing/functions/keys.ts +31 -0
- package/tests/compute/runner.test.ts +8 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import 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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
172
|
-
msg
|
|
173
|
-
|
|
174
|
-
|
|
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
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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
|
-
|
|
228
|
+
this.setState({ isLoading: false });
|
|
188
229
|
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
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
|
-
|
|
217
|
-
|
|
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, {
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
}
|
|
34
|
+
};
|
|
26
35
|
|
|
27
|
-
|
|
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
|
-
}
|
|
41
|
+
};
|
|
33
42
|
|
|
34
|
-
|
|
43
|
+
handleChange = (
|
|
35
44
|
_e: React.ChangeEvent<HTMLTextAreaElement>,
|
|
36
45
|
data: { value: string }
|
|
37
|
-
) => {
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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
|
+
}
|