windmill-components 1.555.0 → 1.558.1
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/package/components/AIAgentLogViewer.svelte.d.ts +3 -3
- package/package/components/AIProviderPicker.svelte.d.ts +3 -3
- package/package/components/ArgInput.svelte +2 -0
- package/package/components/DBManager.svelte.d.ts +3 -3
- package/package/components/DBManagerDrawer.svelte.d.ts +3 -3
- package/package/components/DBSchemaExplorer.svelte.d.ts +3 -3
- package/package/components/DBTable.svelte.d.ts +3 -3
- package/package/components/DBTableEditor.svelte +9 -12
- package/package/components/DBTableEditor.svelte.d.ts +3 -3
- package/package/components/DateTimeInput.svelte +19 -13
- package/package/components/DateTimeInput.svelte.d.ts +5 -0
- package/package/components/DucklakePicker.svelte +32 -0
- package/package/components/DucklakePicker.svelte.d.ts +13 -0
- package/package/components/Editor.svelte +1 -1
- package/package/components/EditorBar.svelte +14 -1
- package/package/components/FakeMonacoPlaceHolder.svelte +1 -1
- package/package/components/FlowGraphViewerStep.svelte +1 -1
- package/package/components/FlowPreviewContent.svelte +1 -1
- package/package/components/HighlightCode.svelte +21 -10
- package/package/components/HighlightCode.svelte.d.ts +12 -22
- package/package/components/InputTransformForm.svelte +9 -41
- package/package/components/InstanceSetting.svelte +1 -6
- package/package/components/ResourceEditor.svelte +1 -1
- package/package/components/ResourcePicker.svelte +0 -5
- package/package/components/apps/components/display/dbtable/AppDbExplorer.svelte +50 -34
- package/package/components/apps/components/display/dbtable/DbExplorerCount.svelte +7 -5
- package/package/components/apps/components/display/dbtable/DbExplorerCount.svelte.d.ts +2 -2
- package/package/components/apps/components/display/dbtable/DeleteRow.svelte +2 -2
- package/package/components/apps/components/display/dbtable/DeleteRow.svelte.d.ts +3 -2
- package/package/components/apps/components/display/dbtable/InsertRow.svelte +13 -7
- package/package/components/apps/components/display/dbtable/InsertRowRunnable.svelte +6 -3
- package/package/components/apps/components/display/dbtable/InsertRowRunnable.svelte.d.ts +2 -1
- package/package/components/apps/components/display/dbtable/UpdateCell.svelte +2 -2
- package/package/components/apps/components/display/dbtable/UpdateCell.svelte.d.ts +3 -2
- package/package/components/apps/components/display/dbtable/queries/count.d.ts +2 -1
- package/package/components/apps/components/display/dbtable/queries/count.js +28 -18
- package/package/components/apps/components/display/dbtable/queries/createTable.d.ts +1 -1
- package/package/components/apps/components/display/dbtable/queries/createTable.js +1 -1
- package/package/components/apps/components/display/dbtable/queries/delete.d.ts +2 -1
- package/package/components/apps/components/display/dbtable/queries/delete.js +19 -10
- package/package/components/apps/components/display/dbtable/queries/insert.d.ts +2 -1
- package/package/components/apps/components/display/dbtable/queries/insert.js +16 -10
- package/package/components/apps/components/display/dbtable/queries/select.d.ts +2 -1
- package/package/components/apps/components/display/dbtable/queries/select.js +20 -16
- package/package/components/apps/components/display/dbtable/queries/update.d.ts +2 -1
- package/package/components/apps/components/display/dbtable/queries/update.js +19 -10
- package/package/components/apps/components/display/dbtable/utils.d.ts +1 -1
- package/package/components/apps/components/display/dbtable/utils.js +12 -3
- package/package/components/apps/components/display/table/AppAggridExplorerTable.svelte +9 -1
- package/package/components/apps/components/display/table/AppAggridExplorerTable.svelte.d.ts +1 -0
- package/package/components/apps/components/display/table/AppAggridInfiniteTable.svelte +2 -1
- package/package/components/apps/components/display/table/AppAggridInfiniteTable.svelte.d.ts +1 -0
- package/package/components/apps/components/display/table/AppAggridInfiniteTableEe.svelte +2 -1
- package/package/components/apps/components/display/table/AppAggridInfiniteTableEe.svelte.d.ts +1 -0
- package/package/components/apps/components/display/table/AppAggridTable.svelte +9 -1
- package/package/components/apps/components/display/table/AppAggridTable.svelte.d.ts +1 -0
- package/package/components/apps/components/display/table/AppAggridTableEe.svelte +2 -1
- package/package/components/apps/components/display/table/AppAggridTableEe.svelte.d.ts +1 -0
- package/package/components/apps/components/helpers/RunnableComponent.svelte +3 -1
- package/package/components/apps/components/inputs/AppDateInput.svelte +1 -0
- package/package/components/apps/editor/AppEditor.svelte +6 -1
- package/package/components/apps/editor/AppEditorHeader.svelte +12 -8
- package/package/components/apps/editor/AppJobsDrawer.svelte +5 -5
- package/package/components/apps/editor/component/ComponentInner.svelte +4 -0
- package/package/components/apps/editor/component/components.d.ts +16 -0
- package/package/components/apps/editor/component/components.js +17 -1
- package/package/components/apps/editor/settingsPanel/AGChartRichEditor.svelte.d.ts +3 -3
- package/package/components/apps/editor/settingsPanel/CSSMigrationModal.svelte.d.ts +3 -3
- package/package/components/apps/editor/settingsPanel/ChartJSRichEditor.svelte.d.ts +3 -3
- package/package/components/apps/editor/settingsPanel/ComponentInputTypeEditor.svelte +23 -23
- package/package/components/apps/editor/settingsPanel/EventHandlers.svelte +7 -2
- package/package/components/apps/editor/settingsPanel/InputsSpecEditor.svelte +1 -0
- package/package/components/apps/editor/settingsPanel/InputsSpecsEditor.svelte +2 -1
- package/package/components/apps/editor/settingsPanel/inputEditor/DBTableSelect.svelte.d.ts +3 -3
- package/package/components/apps/editor/settingsPanel/inputEditor/StaticInputEditor.svelte +10 -0
- package/package/components/apps/inputType.d.ts +2 -2
- package/package/components/auditLogs/AuditLogsFilters.svelte.d.ts +1 -1
- package/package/components/common/button/ConnectionButton.svelte +12 -14
- package/package/components/common/button/ConnectionButton.svelte.d.ts +5 -18
- package/package/components/copilot/AIFormAssistant.svelte.d.ts +3 -3
- package/package/components/copilot/AIFormSettings.svelte.d.ts +3 -3
- package/package/components/copilot/FlowInlineScriptAIButton.svelte.d.ts +3 -3
- package/package/components/copilot/StepInputsGen.svelte +1 -1
- package/package/components/copilot/TestAIKey.svelte.d.ts +3 -3
- package/package/components/copilot/chat/AIChat.svelte.d.ts +3 -3
- package/package/components/copilot/chat/AIChatDisplay.svelte.d.ts +3 -3
- package/package/components/copilot/chat/AIChatInlineWidget.svelte.d.ts +3 -3
- package/package/components/copilot/chat/AIChatInput.svelte.d.ts +3 -3
- package/package/components/copilot/chat/AIChatMessage.svelte.d.ts +3 -3
- package/package/components/copilot/chat/ContextElementBadge.svelte +2 -2
- package/package/components/copilot/chat/flow/AIChangesWarningModal.svelte.d.ts +3 -3
- package/package/components/copilot/chat/flow/FlowAIButton.svelte.d.ts +3 -3
- package/package/components/copilot/chat/flow/FlowAIChat.svelte +4 -1
- package/package/components/copilot/chat/flow/FlowAIChat.svelte.d.ts +3 -3
- package/package/components/copilot/chat/script/CodeDisplay.svelte +30 -9
- package/package/components/copilot/chat/script/core.d.ts +2 -1
- package/package/components/copilot/chat/script/core.js +6 -1
- package/package/components/details/DetailPageLayout.svelte +11 -3
- package/package/components/details/DetailPageLayout.svelte.d.ts +1 -0
- package/package/components/flows/content/DynamicInputHelpBox.svelte +4 -4
- package/package/components/flows/content/FlowInput.svelte +1 -1
- package/package/components/flows/content/FlowInputsQuick.svelte +1 -1
- package/package/components/flows/content/FlowLoop.svelte +143 -10
- package/package/components/flows/conversations/FlowChatInterface.svelte +110 -0
- package/package/components/flows/{FlowChatInterface.svelte.d.ts → conversations/FlowChatInterface.svelte.d.ts} +1 -1
- package/package/components/flows/conversations/FlowChatManager.svelte.d.ts +52 -0
- package/package/components/flows/conversations/FlowChatManager.svelte.js +422 -0
- package/package/components/flows/conversations/FlowChatMessage.svelte +68 -0
- package/package/components/flows/{FlowChatMessage.svelte.d.ts → conversations/FlowChatMessage.svelte.d.ts} +2 -4
- package/package/components/flows/{FlowConversationsSidebar.svelte → conversations/FlowConversationsSidebar.svelte} +6 -6
- package/package/components/flows/flowInfers.js +1 -1
- package/package/components/flows/scheduleUtils.js +2 -1
- package/package/components/graph/renderers/nodes/AIToolNode.svelte.d.ts +3 -3
- package/package/components/graph/renderers/nodes/NewAIToolNode.svelte.d.ts +3 -3
- package/package/components/icons/CACertificate.svelte.d.ts +3 -3
- package/package/components/icons/MSSqlServerIcon.svelte.d.ts +3 -3
- package/package/components/icons/MSTeamsIcon.svelte.d.ts +3 -3
- package/package/components/icons/OracleDBIcon.svelte.d.ts +3 -3
- package/package/components/icons/PHPIcon.svelte.d.ts +3 -3
- package/package/components/icons/QRCodeIcon.svelte.d.ts +3 -3
- package/package/components/instanceSettings.js +11 -2
- package/package/components/runs/JobsLoader.svelte +3 -3
- package/package/components/runs/RunRow.svelte +1 -1
- package/package/components/schema/SchemaFormDND.svelte.d.ts +3 -3
- package/package/components/settings/AIUserSettings.svelte.d.ts +3 -3
- package/package/components/sidebar/SidebarContent.svelte +2 -2
- package/package/components/text_input/TextInput.svelte.d.ts +1 -1
- package/package/components/triggers/http/OpenAPISpecGenerator.svelte.d.ts +3 -3
- package/package/components/triggers/schedules/ScheduleEditorInner.svelte +42 -1
- package/package/components/vscode.js +16 -12
- package/package/components/wizards/ChartJSWizard.svelte.d.ts +3 -3
- package/package/components/wizards/DBExplorerWizard.svelte.d.ts +3 -3
- package/package/components/wizards/LoggedWizardResult.svelte +95 -0
- package/package/components/wizards/LoggedWizardResult.svelte.d.ts +17 -0
- package/package/components/workspaceSettings/AISettings.svelte.d.ts +3 -3
- package/package/components/workspaceSettings/DucklakeSettings.svelte +223 -89
- package/package/gen/core/OpenAPI.js +1 -1
- package/package/gen/schemas.gen.d.ts +73 -5
- package/package/gen/schemas.gen.js +73 -5
- package/package/gen/services.gen.d.ts +8 -8
- package/package/gen/services.gen.js +14 -12
- package/package/gen/types.gen.d.ts +69 -18
- package/package/svelte5Utils.svelte.d.ts +1 -0
- package/package/svelte5Utils.svelte.js +6 -0
- package/package/utils.js +2 -5
- package/package.json +13 -15
- package/package/components/flows/FlowChatInterface.svelte +0 -404
- package/package/components/flows/FlowChatMessage.svelte +0 -41
- package/package/components/meltComponents/Menubar.svelte.d.ts +0 -503
- /package/package/components/flows/{FlowConversationsSidebar.svelte.d.ts → conversations/FlowConversationsSidebar.svelte.d.ts} +0 -0
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
import { FlowConversationService } from '../../../gen';
|
|
2
|
+
import { sendUserToast } from '../../../toast';
|
|
3
|
+
import { waitJob } from '../../waitJob';
|
|
4
|
+
import { tick } from 'svelte';
|
|
5
|
+
class FlowChatManager {
|
|
6
|
+
// State
|
|
7
|
+
messages = $state([]);
|
|
8
|
+
inputMessage = $state('');
|
|
9
|
+
isLoading = $state(false);
|
|
10
|
+
isLoadingMessages = $state(false);
|
|
11
|
+
isWaitingForResponse = $state(false);
|
|
12
|
+
messagesContainer = $state(undefined);
|
|
13
|
+
inputElement = $state(undefined);
|
|
14
|
+
page = $state(1);
|
|
15
|
+
hasMoreMessages = $state(false);
|
|
16
|
+
loadingMoreMessages = $state(false);
|
|
17
|
+
currentEventSource = $state(undefined);
|
|
18
|
+
pollingInterval = $state(undefined);
|
|
19
|
+
// Private state
|
|
20
|
+
#conversationsCache = $state({});
|
|
21
|
+
#scrollTimeout = undefined;
|
|
22
|
+
#perPage = 50;
|
|
23
|
+
#workspace = $state(undefined);
|
|
24
|
+
// Options
|
|
25
|
+
#onRunFlow;
|
|
26
|
+
#createConversation;
|
|
27
|
+
#refreshConversations;
|
|
28
|
+
#conversationId = $state(undefined);
|
|
29
|
+
#useStreaming = $state(false);
|
|
30
|
+
#path = $state(undefined);
|
|
31
|
+
initialize(options, workspace) {
|
|
32
|
+
this.#onRunFlow = options.onRunFlow;
|
|
33
|
+
this.#createConversation = options.createConversation;
|
|
34
|
+
this.#refreshConversations = options.refreshConversations;
|
|
35
|
+
this.#conversationId = options.conversationId;
|
|
36
|
+
this.#useStreaming = options.useStreaming ?? false;
|
|
37
|
+
this.#path = options.path;
|
|
38
|
+
this.#workspace = workspace;
|
|
39
|
+
}
|
|
40
|
+
updateConversationId(conversationId) {
|
|
41
|
+
this.#conversationId = conversationId;
|
|
42
|
+
}
|
|
43
|
+
cleanup() {
|
|
44
|
+
if (this.currentEventSource) {
|
|
45
|
+
this.currentEventSource.close();
|
|
46
|
+
this.currentEventSource = undefined;
|
|
47
|
+
}
|
|
48
|
+
this.stopPolling();
|
|
49
|
+
this.isLoading = false;
|
|
50
|
+
this.isWaitingForResponse = false;
|
|
51
|
+
}
|
|
52
|
+
// Public methods for component to call
|
|
53
|
+
fillInputMessage(message) {
|
|
54
|
+
this.inputMessage = message;
|
|
55
|
+
}
|
|
56
|
+
focusInput() {
|
|
57
|
+
this.inputElement?.focus();
|
|
58
|
+
}
|
|
59
|
+
clearMessages() {
|
|
60
|
+
this.messages = [];
|
|
61
|
+
this.inputMessage = '';
|
|
62
|
+
this.page = 1;
|
|
63
|
+
}
|
|
64
|
+
async loadConversationMessages(conversationId) {
|
|
65
|
+
this.page = 1;
|
|
66
|
+
await this.loadMessages(true, conversationId);
|
|
67
|
+
}
|
|
68
|
+
// Message loading
|
|
69
|
+
async loadMessages(reset, conversationId) {
|
|
70
|
+
let conversationIdToUse = conversationId ?? this.#conversationId;
|
|
71
|
+
if (!this.#workspace || !conversationIdToUse)
|
|
72
|
+
return;
|
|
73
|
+
if (reset) {
|
|
74
|
+
if (this.#conversationsCache[conversationIdToUse]) {
|
|
75
|
+
this.messages = this.#conversationsCache[conversationIdToUse];
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
this.isLoadingMessages = true;
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
this.loadingMoreMessages = true;
|
|
82
|
+
}
|
|
83
|
+
const pageToFetch = reset ? 1 : this.page + 1;
|
|
84
|
+
try {
|
|
85
|
+
const previousScrollHeight = this.messagesContainer?.scrollHeight || 0;
|
|
86
|
+
const response = await FlowConversationService.listConversationMessages({
|
|
87
|
+
workspace: this.#workspace,
|
|
88
|
+
conversationId: conversationIdToUse,
|
|
89
|
+
page: pageToFetch,
|
|
90
|
+
perPage: this.#perPage
|
|
91
|
+
});
|
|
92
|
+
if (reset) {
|
|
93
|
+
this.#conversationsCache[conversationIdToUse] = response;
|
|
94
|
+
this.messages = response;
|
|
95
|
+
this.isLoadingMessages = false;
|
|
96
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
97
|
+
this.scrollToBottom();
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
this.messages = [...response, ...this.messages];
|
|
101
|
+
this.page = pageToFetch;
|
|
102
|
+
// Restore scroll position
|
|
103
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
104
|
+
if (this.messagesContainer) {
|
|
105
|
+
this.messagesContainer.scrollTop =
|
|
106
|
+
this.messagesContainer.scrollHeight - previousScrollHeight;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
this.hasMoreMessages = response.length === this.#perPage;
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
console.error('Failed to load messages:', error);
|
|
113
|
+
sendUserToast('Failed to load messages: ' + error);
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
this.isLoadingMessages = false;
|
|
117
|
+
this.loadingMoreMessages = false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
handleScroll = () => {
|
|
121
|
+
if (this.#scrollTimeout)
|
|
122
|
+
clearTimeout(this.#scrollTimeout);
|
|
123
|
+
this.#scrollTimeout = setTimeout(() => {
|
|
124
|
+
if (!this.messagesContainer || !this.hasMoreMessages || this.loadingMoreMessages)
|
|
125
|
+
return;
|
|
126
|
+
if (this.messagesContainer.scrollTop <= 10) {
|
|
127
|
+
this.loadMessages(false);
|
|
128
|
+
}
|
|
129
|
+
}, 200);
|
|
130
|
+
};
|
|
131
|
+
scrollToBottom() {
|
|
132
|
+
if (this.messagesContainer) {
|
|
133
|
+
this.messagesContainer.scrollTop = this.messagesContainer.scrollHeight;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
scrollToUserMessage(messageId) {
|
|
137
|
+
if (!this.messagesContainer)
|
|
138
|
+
return;
|
|
139
|
+
const messageElement = this.messagesContainer.querySelector(`[data-message-id="${messageId}"]`);
|
|
140
|
+
if (messageElement) {
|
|
141
|
+
messageElement.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// Polling
|
|
145
|
+
async pollJobResult(jobId) {
|
|
146
|
+
try {
|
|
147
|
+
await waitJob(jobId);
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
console.error('Error polling job result:', error);
|
|
151
|
+
}
|
|
152
|
+
finally {
|
|
153
|
+
// Do a final poll to get all messages from database
|
|
154
|
+
try {
|
|
155
|
+
if (this.#conversationId) {
|
|
156
|
+
await this.pollConversationMessages(this.#conversationId);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
catch { }
|
|
160
|
+
this.cleanup();
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
parseStreamDeltas(streamData) {
|
|
164
|
+
let type = 'message';
|
|
165
|
+
const lines = streamData.trim().split('\n');
|
|
166
|
+
let content = '';
|
|
167
|
+
let success = true;
|
|
168
|
+
for (const line of lines) {
|
|
169
|
+
if (!line.trim())
|
|
170
|
+
continue;
|
|
171
|
+
try {
|
|
172
|
+
const parsed = JSON.parse(line);
|
|
173
|
+
if (parsed.type === 'tool_result') {
|
|
174
|
+
type = 'tool_result';
|
|
175
|
+
const toolName = parsed.function_name;
|
|
176
|
+
success = parsed.success;
|
|
177
|
+
content = success ? `Used ${toolName} tool` : `Failed to use ${toolName} tool`;
|
|
178
|
+
}
|
|
179
|
+
if (parsed.type === 'token_delta' && parsed.content) {
|
|
180
|
+
type = 'message';
|
|
181
|
+
content += parsed.content;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
catch (e) {
|
|
185
|
+
console.error('Failed to parse stream line:', line, e);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return { type, content, success };
|
|
189
|
+
}
|
|
190
|
+
async pollConversationMessages(conversationId, isNewConversation) {
|
|
191
|
+
if (!this.#workspace)
|
|
192
|
+
return;
|
|
193
|
+
try {
|
|
194
|
+
const lastId = this.messages[this.messages.length - 1].id;
|
|
195
|
+
const response = await FlowConversationService.listConversationMessages({
|
|
196
|
+
workspace: this.#workspace,
|
|
197
|
+
conversationId: conversationId,
|
|
198
|
+
page: 1,
|
|
199
|
+
perPage: 50,
|
|
200
|
+
afterId: lastId
|
|
201
|
+
});
|
|
202
|
+
if (isNewConversation) {
|
|
203
|
+
await this.#refreshConversations?.();
|
|
204
|
+
}
|
|
205
|
+
const filteredResponse = response.filter((msg) => msg.message_type !== 'user');
|
|
206
|
+
// Add any new intermediate messages not already present
|
|
207
|
+
for (const msg of filteredResponse) {
|
|
208
|
+
if (!this.messages.find((m) => m.id === msg.id)) {
|
|
209
|
+
this.messages = [...this.messages, msg];
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
// Remove temporary messages
|
|
213
|
+
this.messages = this.messages.filter((msg) => !msg.id.startsWith('temp-'));
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
console.error('Polling error:', error);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
startPolling(conversationId, isNewConversation) {
|
|
220
|
+
if (this.pollingInterval)
|
|
221
|
+
return;
|
|
222
|
+
this.pollingInterval = setInterval(() => {
|
|
223
|
+
this.pollConversationMessages(conversationId, isNewConversation);
|
|
224
|
+
}, 500); // Poll every 0.5 seconds
|
|
225
|
+
setTimeout(() => {
|
|
226
|
+
this.stopPolling();
|
|
227
|
+
}, 2 * 60 * 1000); // Stop polling after 2 minutes
|
|
228
|
+
}
|
|
229
|
+
stopPolling() {
|
|
230
|
+
if (this.pollingInterval) {
|
|
231
|
+
clearInterval(this.pollingInterval);
|
|
232
|
+
this.pollingInterval = undefined;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
// Message sending
|
|
236
|
+
async sendMessage() {
|
|
237
|
+
if (!this.inputMessage.trim() || this.isLoading)
|
|
238
|
+
return;
|
|
239
|
+
const isNewConversation = this.messages.length === 0;
|
|
240
|
+
// Reset state for new message
|
|
241
|
+
this.stopPolling();
|
|
242
|
+
// Generate a new conversation ID if we don't have one
|
|
243
|
+
let currentConversationId = this.#conversationId;
|
|
244
|
+
if (!this.#conversationId && this.#createConversation) {
|
|
245
|
+
const newConversationId = await this.#createConversation({ clearMessages: false });
|
|
246
|
+
currentConversationId = newConversationId;
|
|
247
|
+
}
|
|
248
|
+
if (!currentConversationId) {
|
|
249
|
+
console.error('No conversation ID found');
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
// Invalidate the conversation cache
|
|
253
|
+
delete this.#conversationsCache[currentConversationId];
|
|
254
|
+
const userMessage = {
|
|
255
|
+
id: crypto.randomUUID(),
|
|
256
|
+
content: this.inputMessage.trim(),
|
|
257
|
+
created_at: new Date().toISOString(),
|
|
258
|
+
message_type: 'user',
|
|
259
|
+
conversation_id: currentConversationId
|
|
260
|
+
};
|
|
261
|
+
this.messages = [...this.messages, userMessage];
|
|
262
|
+
const messageContent = this.inputMessage.trim();
|
|
263
|
+
this.inputMessage = '';
|
|
264
|
+
this.isLoading = true;
|
|
265
|
+
this.isWaitingForResponse = true;
|
|
266
|
+
try {
|
|
267
|
+
await tick();
|
|
268
|
+
this.scrollToUserMessage(userMessage.id);
|
|
269
|
+
if (this.#useStreaming && this.#path) {
|
|
270
|
+
await this.handleStreamingMessage(messageContent, currentConversationId, isNewConversation);
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
await this.handlePollingMessage(messageContent, currentConversationId, isNewConversation);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
catch (error) {
|
|
277
|
+
console.error('Error running flow:', error);
|
|
278
|
+
sendUserToast('Failed to run flow: ' + error, true);
|
|
279
|
+
}
|
|
280
|
+
finally {
|
|
281
|
+
if (!this.#useStreaming) {
|
|
282
|
+
this.isLoading = false;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
await tick();
|
|
286
|
+
this.focusInput();
|
|
287
|
+
}
|
|
288
|
+
async handleStreamingMessage(messageContent, currentConversationId, isNewConversation) {
|
|
289
|
+
// Close any existing EventSource
|
|
290
|
+
if (this.currentEventSource) {
|
|
291
|
+
this.currentEventSource.close();
|
|
292
|
+
}
|
|
293
|
+
// Track stream state for this message
|
|
294
|
+
let accumulatedContent = '';
|
|
295
|
+
let assistantMessageId = '';
|
|
296
|
+
let isCompleted = false;
|
|
297
|
+
try {
|
|
298
|
+
// Encode the payload as base64
|
|
299
|
+
const payload = { user_message: messageContent };
|
|
300
|
+
const payloadBase64 = btoa(JSON.stringify(payload));
|
|
301
|
+
// Build the EventSource URL
|
|
302
|
+
const streamUrl = `/api/w/${this.#workspace}/jobs/run_and_stream/f/${this.#path}`;
|
|
303
|
+
const url = new URL(streamUrl, window.location.origin);
|
|
304
|
+
url.searchParams.set('payload', payloadBase64);
|
|
305
|
+
url.searchParams.set('memory_id', currentConversationId);
|
|
306
|
+
url.searchParams.set('poll_delay_ms', '50');
|
|
307
|
+
// Create EventSource connection
|
|
308
|
+
const eventSource = new EventSource(url.toString());
|
|
309
|
+
this.currentEventSource = eventSource;
|
|
310
|
+
// start polling
|
|
311
|
+
this.startPolling(currentConversationId, isNewConversation);
|
|
312
|
+
eventSource.onmessage = async (event) => {
|
|
313
|
+
try {
|
|
314
|
+
const data = JSON.parse(event.data);
|
|
315
|
+
if (data.type === 'update') {
|
|
316
|
+
// Process new stream content
|
|
317
|
+
if (data.new_result_stream) {
|
|
318
|
+
// Stop polling since we are receiving last step streaming
|
|
319
|
+
this.stopPolling();
|
|
320
|
+
const { type, content: newContent, success } = this.parseStreamDeltas(data.new_result_stream);
|
|
321
|
+
accumulatedContent += newContent;
|
|
322
|
+
if (accumulatedContent.length > 0 || type === 'tool_result') {
|
|
323
|
+
this.isWaitingForResponse = false;
|
|
324
|
+
}
|
|
325
|
+
// Create tool message if type is tool_result
|
|
326
|
+
if (type === 'tool_result') {
|
|
327
|
+
// set last message streaming to false
|
|
328
|
+
this.messages = this.messages.map((msg) => msg.id === this.messages[this.messages.length - 1].id
|
|
329
|
+
? { ...msg, streaming: false }
|
|
330
|
+
: msg);
|
|
331
|
+
this.messages = [
|
|
332
|
+
...this.messages,
|
|
333
|
+
{
|
|
334
|
+
id: 'temp-' + crypto.randomUUID(),
|
|
335
|
+
content: newContent,
|
|
336
|
+
created_at: new Date().toISOString(),
|
|
337
|
+
message_type: 'tool',
|
|
338
|
+
conversation_id: currentConversationId,
|
|
339
|
+
job_id: '',
|
|
340
|
+
loading: false,
|
|
341
|
+
streaming: false,
|
|
342
|
+
success
|
|
343
|
+
}
|
|
344
|
+
];
|
|
345
|
+
// Reset assistant message ID since we are creating a tool message
|
|
346
|
+
assistantMessageId = '';
|
|
347
|
+
accumulatedContent = '';
|
|
348
|
+
}
|
|
349
|
+
// Create message on first content
|
|
350
|
+
else if (type === 'message' &&
|
|
351
|
+
assistantMessageId.length === 0 &&
|
|
352
|
+
accumulatedContent.length > 0) {
|
|
353
|
+
assistantMessageId = 'temp-' + crypto.randomUUID();
|
|
354
|
+
this.messages = [
|
|
355
|
+
...this.messages,
|
|
356
|
+
{
|
|
357
|
+
id: assistantMessageId,
|
|
358
|
+
content: accumulatedContent,
|
|
359
|
+
created_at: new Date().toISOString(),
|
|
360
|
+
message_type: 'assistant',
|
|
361
|
+
conversation_id: currentConversationId,
|
|
362
|
+
job_id: '',
|
|
363
|
+
loading: false,
|
|
364
|
+
streaming: true
|
|
365
|
+
}
|
|
366
|
+
];
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
// Update existing message
|
|
370
|
+
this.messages = this.messages.map((msg) => msg.id === assistantMessageId ? { ...msg, content: accumulatedContent } : msg);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
// Handle completion
|
|
374
|
+
if (data.completed) {
|
|
375
|
+
isCompleted = true;
|
|
376
|
+
// Do a final poll to get all messages from database
|
|
377
|
+
if (this.#conversationId) {
|
|
378
|
+
await this.pollConversationMessages(this.#conversationId);
|
|
379
|
+
}
|
|
380
|
+
this.cleanup();
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
catch (error) {
|
|
385
|
+
console.error('Error processing stream event:', error);
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
eventSource.onerror = (error) => {
|
|
389
|
+
if (isCompleted)
|
|
390
|
+
return;
|
|
391
|
+
console.error('EventSource error:', error);
|
|
392
|
+
sendUserToast('Stream error occurred', true);
|
|
393
|
+
this.cleanup();
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
catch (error) {
|
|
397
|
+
console.error('Stream connection error:', error);
|
|
398
|
+
sendUserToast('Failed to connect to stream', true);
|
|
399
|
+
this.cleanup();
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
async handlePollingMessage(messageContent, currentConversationId, isNewConversation) {
|
|
403
|
+
const jobId = await this.#onRunFlow?.(messageContent, currentConversationId);
|
|
404
|
+
if (!jobId) {
|
|
405
|
+
console.error('No jobId returned from onRunFlow');
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
if (isNewConversation) {
|
|
409
|
+
await this.#refreshConversations?.();
|
|
410
|
+
}
|
|
411
|
+
// Start polling for intermediate messages in non-streaming mode too
|
|
412
|
+
this.startPolling(currentConversationId);
|
|
413
|
+
this.pollJobResult(jobId);
|
|
414
|
+
}
|
|
415
|
+
handleKeyDown = (event) => {
|
|
416
|
+
if (event.key === 'Enter' && !event.shiftKey) {
|
|
417
|
+
event.preventDefault();
|
|
418
|
+
this.sendMessage();
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
export const createFlowChatManager = () => new FlowChatManager();
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<script lang="ts">import { Markdown } from 'svelte-exmarkdown';
|
|
2
|
+
import { gfmPlugin } from 'svelte-exmarkdown/gfm';
|
|
3
|
+
import { Loader2, CheckCircle2, AlertTriangle } from 'lucide-svelte';
|
|
4
|
+
import CodeDisplay from '../../copilot/chat/script/CodeDisplay.svelte';
|
|
5
|
+
import LinkRenderer from '../../copilot/chat/LinkRenderer.svelte';
|
|
6
|
+
import {} from './FlowChatManager.svelte';
|
|
7
|
+
let { message } = $props();
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<div
|
|
11
|
+
class={`flex ${message.message_type === 'user' ? 'justify-end' : 'justify-start'} ${message.loading || message.streaming ? 'min-h-[200px] items-start' : ''}`}
|
|
12
|
+
data-message-id={message.id}
|
|
13
|
+
>
|
|
14
|
+
<div
|
|
15
|
+
class="max-w-[90%] min-w-0 rounded-lg
|
|
16
|
+
{message.message_type === 'user'
|
|
17
|
+
? 'bg-surface-secondary p-3'
|
|
18
|
+
: `bg-surface border ${message.success !== false ? 'border-gray-200 dark:border-gray-600' : '!border-red-500'}`}"
|
|
19
|
+
>
|
|
20
|
+
{#if message.step_name}
|
|
21
|
+
<div
|
|
22
|
+
class="bg-surface-secondary text-2xs text-tertiary mb-2 font-medium py-1 px-2 rounded-t-lg"
|
|
23
|
+
>{message.step_name}</div
|
|
24
|
+
>
|
|
25
|
+
{/if}
|
|
26
|
+
|
|
27
|
+
{#if message.message_type === 'user'}
|
|
28
|
+
<p class="whitespace-pre-wrap text-sm break-words">{message.content}</p>
|
|
29
|
+
{:else if message.loading}
|
|
30
|
+
<div class="flex items-center gap-2 text-tertiary">
|
|
31
|
+
<Loader2 size={16} class="animate-spin" />
|
|
32
|
+
<span>Processing...</span>
|
|
33
|
+
</div>
|
|
34
|
+
{:else if message.content}
|
|
35
|
+
<div
|
|
36
|
+
class="flex flex-row items-center gap-2 px-3 pb-3 text-sm {!message.step_name
|
|
37
|
+
? 'pt-3'
|
|
38
|
+
: ''}"
|
|
39
|
+
>
|
|
40
|
+
{#if message.message_type === 'tool'}
|
|
41
|
+
{#if message.success !== false}
|
|
42
|
+
<CheckCircle2 class="w-3.5 h-3.5 text-green-500" />
|
|
43
|
+
{:else}
|
|
44
|
+
<AlertTriangle class="w-3.5 h-3.5 text-red-500" />
|
|
45
|
+
{/if}
|
|
46
|
+
{/if}
|
|
47
|
+
<div
|
|
48
|
+
class="prose prose-sm dark:prose-invert break-words whitespace-pre-wrap prose-headings:!text-base"
|
|
49
|
+
>
|
|
50
|
+
<Markdown
|
|
51
|
+
md={message.content}
|
|
52
|
+
plugins={[
|
|
53
|
+
gfmPlugin(),
|
|
54
|
+
{
|
|
55
|
+
renderer: {
|
|
56
|
+
pre: CodeDisplay,
|
|
57
|
+
a: LinkRenderer
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
]}
|
|
61
|
+
/>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
{:else}
|
|
65
|
+
<p class="text-tertiary text-sm">No result</p>
|
|
66
|
+
{/if}
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ChatMessage } from './FlowChatManager.svelte';
|
|
2
2
|
interface Props {
|
|
3
|
-
message:
|
|
4
|
-
loading?: boolean;
|
|
5
|
-
};
|
|
3
|
+
message: ChatMessage;
|
|
6
4
|
}
|
|
7
5
|
declare const FlowChatMessage: import("svelte").Component<Props, {}, "">;
|
|
8
6
|
type FlowChatMessage = ReturnType<typeof FlowChatMessage>;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
<script lang="ts">import { Button } from '
|
|
1
|
+
<script lang="ts">import { Button } from '../../common';
|
|
2
2
|
import { MessageCircle, Plus, Trash2, PanelLeftClose, PanelLeftOpen, Loader2 } from 'lucide-svelte';
|
|
3
|
-
import { workspaceStore } from '
|
|
4
|
-
import { FlowConversationService } from '
|
|
5
|
-
import { sendUserToast } from '
|
|
6
|
-
import CountBadge from '
|
|
7
|
-
import InfiniteList from '
|
|
3
|
+
import { workspaceStore } from '../../../stores';
|
|
4
|
+
import { FlowConversationService } from '../../../gen';
|
|
5
|
+
import { sendUserToast } from '../../../toast';
|
|
6
|
+
import CountBadge from '../../common/badge/CountBadge.svelte';
|
|
7
|
+
import InfiniteList from '../../InfiniteList.svelte';
|
|
8
8
|
import { untrack } from 'svelte';
|
|
9
9
|
import { twMerge } from 'tailwind-merge';
|
|
10
10
|
let { flowPath, selectedConversationId, onNewConversation, onSelectConversation, onDeleteConversation } = $props();
|
|
@@ -141,7 +141,8 @@ export async function saveScheduleFromCfg(scheduleCfg, edit, workspace) {
|
|
|
141
141
|
no_flow_overlap: scheduleCfg.no_flow_overlap,
|
|
142
142
|
tag: scheduleCfg.tag,
|
|
143
143
|
paused_until: scheduleCfg.paused_until,
|
|
144
|
-
cron_version: scheduleCfg.cron_version
|
|
144
|
+
cron_version: scheduleCfg.cron_version,
|
|
145
|
+
dynamic_skip: scheduleCfg.dynamic_skip
|
|
145
146
|
};
|
|
146
147
|
try {
|
|
147
148
|
if (edit) {
|
|
@@ -19,6 +19,6 @@ import type { GraphModuleState } from '../../model';
|
|
|
19
19
|
interface Props {
|
|
20
20
|
data: AiToolN['data'];
|
|
21
21
|
}
|
|
22
|
-
declare const
|
|
23
|
-
type
|
|
24
|
-
export default
|
|
22
|
+
declare const AIToolNode: import("svelte").Component<Props, {}, "">;
|
|
23
|
+
type AIToolNode = ReturnType<typeof AIToolNode>;
|
|
24
|
+
export default AIToolNode;
|
|
@@ -2,6 +2,6 @@ import { type NewAiToolN } from '../../graphBuilder.svelte';
|
|
|
2
2
|
interface Props {
|
|
3
3
|
data: NewAiToolN['data'];
|
|
4
4
|
}
|
|
5
|
-
declare const
|
|
6
|
-
type
|
|
7
|
-
export default
|
|
5
|
+
declare const NewAIToolNode: import("svelte").Component<Props, {}, "">;
|
|
6
|
+
type NewAIToolNode = ReturnType<typeof NewAIToolNode>;
|
|
7
|
+
export default NewAIToolNode;
|
|
@@ -2,6 +2,6 @@ interface Props {
|
|
|
2
2
|
height?: string;
|
|
3
3
|
width?: string;
|
|
4
4
|
}
|
|
5
|
-
declare const
|
|
6
|
-
type
|
|
7
|
-
export default
|
|
5
|
+
declare const CACertificate: import("svelte").Component<Props, {}, "">;
|
|
6
|
+
type CACertificate = ReturnType<typeof CACertificate>;
|
|
7
|
+
export default CACertificate;
|
|
@@ -2,6 +2,6 @@ interface Props {
|
|
|
2
2
|
height?: string;
|
|
3
3
|
width?: string;
|
|
4
4
|
}
|
|
5
|
-
declare const
|
|
6
|
-
type
|
|
7
|
-
export default
|
|
5
|
+
declare const MSSqlServerIcon: import("svelte").Component<Props, {}, "">;
|
|
6
|
+
type MSSqlServerIcon = ReturnType<typeof MSSqlServerIcon>;
|
|
7
|
+
export default MSSqlServerIcon;
|
|
@@ -2,6 +2,6 @@ interface Props {
|
|
|
2
2
|
height?: string;
|
|
3
3
|
width?: string;
|
|
4
4
|
}
|
|
5
|
-
declare const
|
|
6
|
-
type
|
|
7
|
-
export default
|
|
5
|
+
declare const MSTeamsIcon: import("svelte").Component<Props, {}, "">;
|
|
6
|
+
type MSTeamsIcon = ReturnType<typeof MSTeamsIcon>;
|
|
7
|
+
export default MSTeamsIcon;
|
|
@@ -2,6 +2,6 @@ interface Props {
|
|
|
2
2
|
height?: string;
|
|
3
3
|
width?: string;
|
|
4
4
|
}
|
|
5
|
-
declare const
|
|
6
|
-
type
|
|
7
|
-
export default
|
|
5
|
+
declare const OracleDBIcon: import("svelte").Component<Props, {}, "">;
|
|
6
|
+
type OracleDBIcon = ReturnType<typeof OracleDBIcon>;
|
|
7
|
+
export default OracleDBIcon;
|
|
@@ -2,6 +2,6 @@ interface Props {
|
|
|
2
2
|
height?: string;
|
|
3
3
|
width?: string;
|
|
4
4
|
}
|
|
5
|
-
declare const
|
|
6
|
-
type
|
|
7
|
-
export default
|
|
5
|
+
declare const PHPIcon: import("svelte").Component<Props, {}, "">;
|
|
6
|
+
type PHPIcon = ReturnType<typeof PHPIcon>;
|
|
7
|
+
export default PHPIcon;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
interface Props {
|
|
2
2
|
height?: number;
|
|
3
3
|
}
|
|
4
|
-
declare const
|
|
5
|
-
type
|
|
6
|
-
export default
|
|
4
|
+
declare const QRCodeIcon: import("svelte").Component<Props, {}, "">;
|
|
5
|
+
type QRCodeIcon = ReturnType<typeof QRCodeIcon>;
|
|
6
|
+
export default QRCodeIcon;
|
|
@@ -128,7 +128,7 @@ export const settings = {
|
|
|
128
128
|
},
|
|
129
129
|
{
|
|
130
130
|
label: 'Private Hub base url',
|
|
131
|
-
description: 'Base URL of your
|
|
131
|
+
description: 'Base URL of your Private Hub instance, without trailing slash. <a href="https://www.windmill.dev/docs/core_concepts/private_hub">Learn more</a>',
|
|
132
132
|
placeholder: 'https://hub.company.com',
|
|
133
133
|
key: 'hub_base_url',
|
|
134
134
|
fieldType: 'text',
|
|
@@ -159,6 +159,15 @@ export const settings = {
|
|
|
159
159
|
ee_only: '',
|
|
160
160
|
requiresReloadOnChange: true
|
|
161
161
|
},
|
|
162
|
+
{
|
|
163
|
+
label: 'Private Hub API secret',
|
|
164
|
+
description: 'If access to your Private Hub is restricted, you can set the hub API secret here. <a href="https://www.windmill.dev/docs/core_concepts/private_hub">Learn more</a>',
|
|
165
|
+
key: 'hub_api_secret',
|
|
166
|
+
fieldType: 'password',
|
|
167
|
+
storage: 'setting',
|
|
168
|
+
ee_only: '',
|
|
169
|
+
requiresReloadOnChange: true
|
|
170
|
+
},
|
|
162
171
|
{
|
|
163
172
|
label: 'App workspace prefix',
|
|
164
173
|
description: 'When enabled apps will be accessible at /a/{workspace_id}/{custom_path} instead of /a/{custom_path} allowing you to define same custom path for apps in different workspace without conflict',
|
|
@@ -285,7 +294,7 @@ export const settings = {
|
|
|
285
294
|
label: 'PowerShell Repository PAT',
|
|
286
295
|
description: 'Add private PowerShell repository Personal Access Token',
|
|
287
296
|
key: 'powershell_repo_pat',
|
|
288
|
-
fieldType: '
|
|
297
|
+
fieldType: 'password',
|
|
289
298
|
storage: 'setting',
|
|
290
299
|
ee_only: ''
|
|
291
300
|
}
|