windmill-components 1.510.1 → 1.511.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/AppConnectInner.svelte +28 -5
- package/package/components/ArgInput.svelte +14 -4
- package/package/components/Editor.svelte +108 -84
- package/package/components/Editor.svelte.d.ts +30 -55
- package/package/components/FlowPreviewContent.svelte +1 -0
- package/package/components/FlowPreviewContent.svelte.d.ts +3 -0
- package/package/components/FlowStatusViewer.svelte +2 -1
- package/package/components/FlowStatusViewer.svelte.d.ts +3 -0
- package/package/components/FlowStatusViewerInner.svelte +3 -1
- package/package/components/FlowStatusViewerInner.svelte.d.ts +3 -0
- package/package/components/HttpAgentWorkerDrawer.svelte +1 -1
- package/package/components/JsonEditor.svelte +11 -11
- package/package/components/JsonEditor.svelte.d.ts +14 -56
- package/package/components/Label.svelte +6 -11
- package/package/components/Label.svelte.d.ts +14 -39
- package/package/components/NumberTypeNarrowing.svelte +13 -16
- package/package/components/NumberTypeNarrowing.svelte.d.ts +4 -18
- package/package/components/ResourceTypePicker.svelte +20 -17
- package/package/components/ResourceTypePicker.svelte.d.ts +7 -6
- package/package/components/Section.svelte +7 -20
- package/package/components/Section.svelte.d.ts +20 -47
- package/package/components/SimpleEditor.svelte +4 -4
- package/package/components/SimpleEditor.svelte.d.ts +1 -0
- package/package/components/SqlRepl.svelte +0 -1
- package/package/components/Subsection.svelte +10 -12
- package/package/components/Subsection.svelte.d.ts +15 -39
- package/package/components/WorkerGroup.svelte +260 -165
- package/package/components/WorkerGroup.svelte.d.ts +2 -0
- package/package/components/WorkerTagPicker.svelte +3 -3
- package/package/components/WorkerTagSelect.svelte +3 -3
- package/package/components/copilot/AIFormSettings.svelte +3 -4
- package/package/components/copilot/AIFormSettings.svelte.d.ts +5 -19
- package/package/components/copilot/autocomplete/Autocompletor.d.ts +3 -1
- package/package/components/copilot/autocomplete/Autocompletor.js +250 -34
- package/package/components/copilot/autocomplete/request.d.ts +3 -0
- package/package/components/copilot/autocomplete/request.js +15 -7
- package/package/components/copilot/chat/script/core.js +30 -22
- package/package/components/copilot/lib.d.ts +1 -1
- package/package/components/copilot/lib.js +3 -0
- package/package/components/custom_ui.d.ts +1 -0
- package/package/components/flows/content/FlowModuleCache.svelte +4 -4
- package/package/components/flows/content/FlowModuleCache.svelte.d.ts +4 -18
- package/package/components/flows/content/FlowModuleComponent.svelte +1 -1
- package/package/components/flows/content/FlowModuleDeleteAfterUse.svelte +3 -4
- package/package/components/flows/content/FlowModuleDeleteAfterUse.svelte.d.ts +4 -18
- package/package/components/flows/content/FlowModuleSleep.svelte +6 -7
- package/package/components/flows/content/FlowModuleSleep.svelte.d.ts +4 -18
- package/package/components/flows/content/FlowModuleSuspend.svelte +19 -17
- package/package/components/flows/content/FlowModuleSuspend.svelte.d.ts +4 -18
- package/package/components/flows/content/FlowModuleTimeout.svelte +4 -4
- package/package/components/flows/content/FlowModuleTimeout.svelte.d.ts +4 -18
- package/package/components/triggers/gcp/GcpTriggerEditorInner.svelte +4 -4
- package/package/components/triggers/http/OpenAPISpecGenerator.svelte +2 -2
- package/package/components/triggers/http/RouteEditorConfigSection.svelte +26 -23
- package/package/components/triggers/http/RouteEditorConfigSection.svelte.d.ts +5 -19
- package/package/components/triggers/http/RouteEditorInner.svelte +18 -18
- package/package/components/triggers/kafka/KafkaTriggerEditorInner.svelte +4 -4
- package/package/components/triggers/mqtt/MqttTriggerEditorInner.svelte +4 -4
- package/package/components/triggers/nats/NatsTriggerEditorInner.svelte +4 -4
- package/package/components/triggers/schedules/ScheduleEditorInner.svelte +4 -4
- package/package/components/triggers/sqs/SqsTriggerEditorInner.svelte +4 -4
- package/package/components/triggers/websocket/WebsocketTriggerEditorInner.svelte +4 -4
- package/package/gen/core/OpenAPI.js +1 -1
- package/package/gen/schemas.gen.d.ts +26 -18
- package/package/gen/schemas.gen.js +29 -21
- package/package/gen/types.gen.d.ts +25 -6
- package/package/inferArgSig.d.ts +14 -7
- package/package/inferArgSig.js +22 -15
- package/package.json +12 -12
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import { sleep } from '../../../utils';
|
|
2
|
-
import { Position, languages } from 'monaco-editor';
|
|
2
|
+
import { editor as meditor, Position, languages } from 'monaco-editor';
|
|
3
3
|
import { LRUCache } from 'lru-cache';
|
|
4
4
|
import { autocompleteRequest } from './request';
|
|
5
|
-
import { FIM_MAX_TOKENS } from '../lib';
|
|
5
|
+
import { FIM_MAX_TOKENS, getModelContextWindow } from '../lib';
|
|
6
|
+
import { setGlobalCSS } from '../shared';
|
|
7
|
+
import { get } from 'svelte/store';
|
|
8
|
+
import { copilotInfo } from '../../../stores';
|
|
9
|
+
// max ratio of completions to context window
|
|
10
|
+
const COMPLETIONS_MAX_RATIO = 0.1;
|
|
11
|
+
// hard limit to max number of completions to fetch details for, to avoid performance overhead
|
|
12
|
+
const MAX_COMPLETIONS_DETAILS = 50;
|
|
6
13
|
function filterCompletion(completion, suffix, shouldReturnMultiline) {
|
|
7
14
|
const trimmedCompletion = completion.replaceAll('\n', '');
|
|
8
15
|
const trimmedSuffix = suffix.slice(0, FIM_MAX_TOKENS).replaceAll('\n', '');
|
|
@@ -12,10 +19,10 @@ function filterCompletion(completion, suffix, shouldReturnMultiline) {
|
|
|
12
19
|
if (!shouldReturnMultiline) {
|
|
13
20
|
if (completion.startsWith('\n')) {
|
|
14
21
|
// TODO improve cache for this case so that we can use cache when accepting the first line of a multiline completion which starts with \n
|
|
15
|
-
return completion.split('\n').slice(0, 2).join('\n');
|
|
22
|
+
return completion.split('\n').slice(0, 2).join('\n') + '\n';
|
|
16
23
|
}
|
|
17
|
-
else {
|
|
18
|
-
return completion.split('\n').slice(0, 1).join('\n');
|
|
24
|
+
else if (completion.includes('\n')) {
|
|
25
|
+
return completion.split('\n').slice(0, 1).join('\n') + '\n';
|
|
19
26
|
}
|
|
20
27
|
}
|
|
21
28
|
return completion;
|
|
@@ -29,50 +36,103 @@ export class Autocompletor {
|
|
|
29
36
|
#abortController = new AbortController();
|
|
30
37
|
#completionDisposable;
|
|
31
38
|
#cursorDisposable;
|
|
39
|
+
#lastCompletions = [];
|
|
40
|
+
#contextWindow = 0;
|
|
41
|
+
#shouldShowDeletionCue = false;
|
|
42
|
+
#languageClient = undefined;
|
|
32
43
|
constructor(editor, scriptLang) {
|
|
44
|
+
setGlobalCSS('ai-chat-autocomplete', `
|
|
45
|
+
.ai-completion-diff {
|
|
46
|
+
background: var(--vscode-diffEditor-removedTextBackground);
|
|
47
|
+
}
|
|
48
|
+
`);
|
|
33
49
|
this.#scriptLang = scriptLang;
|
|
50
|
+
const deletionsCues = editor.createDecorationsCollection();
|
|
51
|
+
const completionModel = get(copilotInfo).codeCompletionModel;
|
|
52
|
+
this.#contextWindow = getModelContextWindow(completionModel?.model ?? '');
|
|
34
53
|
this.#completionDisposable = languages.registerInlineCompletionsProvider({ pattern: '**' }, {
|
|
54
|
+
handleItemDidShow: (items) => {
|
|
55
|
+
const item = items.items[0];
|
|
56
|
+
const model = editor.getModel();
|
|
57
|
+
if (!item || !item.range || !model) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const toEol = {
|
|
61
|
+
...item.range,
|
|
62
|
+
endColumn: model.getLineMaxColumn(item.range.startLineNumber)
|
|
63
|
+
};
|
|
64
|
+
if (this.#shouldShowDeletionCue) {
|
|
65
|
+
deletionsCues.set([
|
|
66
|
+
{
|
|
67
|
+
range: toEol,
|
|
68
|
+
options: {
|
|
69
|
+
className: 'ai-completion-diff'
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
]);
|
|
73
|
+
this.#shouldShowDeletionCue = false;
|
|
74
|
+
}
|
|
75
|
+
},
|
|
35
76
|
provideInlineCompletions: async (model, position, context, token) => {
|
|
36
77
|
if (token.isCancellationRequested ||
|
|
37
78
|
model.uri.toString() !== editor.getModel()?.uri.toString()) {
|
|
38
79
|
return { items: [] };
|
|
39
80
|
}
|
|
81
|
+
this.#shouldShowDeletionCue = false;
|
|
40
82
|
const shouldReturnMultiline = this.#shouldReturnMultiline(model, position);
|
|
41
83
|
const result = await this.#autocomplete(model, position);
|
|
42
|
-
if (result) {
|
|
43
|
-
|
|
44
|
-
if (!completion) {
|
|
45
|
-
return { items: [] };
|
|
46
|
-
}
|
|
47
|
-
let range = {
|
|
48
|
-
startLineNumber: position.lineNumber,
|
|
49
|
-
startColumn: position.column,
|
|
50
|
-
endLineNumber: position.lineNumber,
|
|
51
|
-
endColumn: position.column
|
|
52
|
-
};
|
|
53
|
-
const multiline = completion.indexOf('\n') !== -1;
|
|
54
|
-
if (multiline) {
|
|
55
|
-
// if multiline the range should span until the end of the line
|
|
56
|
-
range.endColumn = model.getLineMaxColumn(position.lineNumber);
|
|
57
|
-
}
|
|
58
|
-
return {
|
|
59
|
-
items: [
|
|
60
|
-
{
|
|
61
|
-
insertText: completion,
|
|
62
|
-
range
|
|
63
|
-
}
|
|
64
|
-
]
|
|
65
|
-
};
|
|
84
|
+
if (!result) {
|
|
85
|
+
return { items: [] };
|
|
66
86
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
87
|
+
const range = {
|
|
88
|
+
startLineNumber: position.lineNumber,
|
|
89
|
+
startColumn: position.column,
|
|
90
|
+
endLineNumber: position.lineNumber,
|
|
91
|
+
endColumn: position.column
|
|
92
|
+
};
|
|
93
|
+
const toEol = {
|
|
94
|
+
...range,
|
|
95
|
+
endColumn: model.getLineMaxColumn(position.lineNumber)
|
|
96
|
+
};
|
|
97
|
+
// if shouldReturnMultiline is false, only keep first line of a multiline completion (keeps final new line)
|
|
98
|
+
let completion = filterCompletion(result.completion, result.suffix, shouldReturnMultiline);
|
|
99
|
+
if (!completion) {
|
|
100
|
+
return { items: [] };
|
|
71
101
|
}
|
|
102
|
+
// if completion ends with new line, we want the suggestion to replace the end of the current line
|
|
103
|
+
const endsWithNewLine = completion.endsWith('\n');
|
|
104
|
+
if (endsWithNewLine) {
|
|
105
|
+
// remove new line
|
|
106
|
+
completion = completion.slice(0, -1);
|
|
107
|
+
// set deletion cue for content that will be replaced by the suggestion
|
|
108
|
+
if (!completion.includes('\n')) {
|
|
109
|
+
this.#shouldShowDeletionCue = true;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const multiline = completion.indexOf('\n') !== -1;
|
|
113
|
+
return {
|
|
114
|
+
items: [
|
|
115
|
+
{
|
|
116
|
+
insertText: completion,
|
|
117
|
+
range: !endsWithNewLine && multiline ? toEol : range,
|
|
118
|
+
// if completion ends with new line, after applying the suggestion, delete the rest of the line
|
|
119
|
+
additionalTextEdits: endsWithNewLine && !multiline
|
|
120
|
+
? [
|
|
121
|
+
{
|
|
122
|
+
range: toEol,
|
|
123
|
+
text: ''
|
|
124
|
+
}
|
|
125
|
+
]
|
|
126
|
+
: []
|
|
127
|
+
}
|
|
128
|
+
]
|
|
129
|
+
};
|
|
72
130
|
},
|
|
73
131
|
freeInlineCompletions: () => { }
|
|
74
132
|
});
|
|
75
133
|
this.#cursorDisposable = editor.onDidChangeCursorPosition(async (e) => {
|
|
134
|
+
deletionsCues.clear();
|
|
135
|
+
this.#shouldShowDeletionCue = false;
|
|
76
136
|
if (e.source === 'mouse') {
|
|
77
137
|
const model = editor.getModel();
|
|
78
138
|
if (model) {
|
|
@@ -91,6 +151,9 @@ export class Autocompletor {
|
|
|
91
151
|
this.#completionDisposable.dispose();
|
|
92
152
|
this.#cursorDisposable.dispose();
|
|
93
153
|
}
|
|
154
|
+
setLanguageClient(client) {
|
|
155
|
+
this.#languageClient = client;
|
|
156
|
+
}
|
|
94
157
|
#shouldReturnMultiline(model, position) {
|
|
95
158
|
if (position.column === model.getLineMaxColumn(position.lineNumber)) {
|
|
96
159
|
const cachedCompletion = this.#cache.get(position.lineNumber);
|
|
@@ -102,6 +165,146 @@ export class Autocompletor {
|
|
|
102
165
|
}
|
|
103
166
|
return false;
|
|
104
167
|
}
|
|
168
|
+
#markersAtCursor(pos, all) {
|
|
169
|
+
const padding = 1;
|
|
170
|
+
return all.filter((m) => m.startLineNumber >= pos.lineNumber - padding && m.endLineNumber <= pos.lineNumber + padding);
|
|
171
|
+
}
|
|
172
|
+
#partsToText(parts) {
|
|
173
|
+
return parts.map((p) => p.text).join('');
|
|
174
|
+
}
|
|
175
|
+
#formatCompletionEntry(details) {
|
|
176
|
+
let ret = 'SIGNATURE: ' + this.#partsToText(details.displayParts) + '\n';
|
|
177
|
+
for (const doc of details.documentation) {
|
|
178
|
+
ret += 'DOC: ' + doc.text + '\n';
|
|
179
|
+
}
|
|
180
|
+
ret += 'TAGS: ' + JSON.stringify(details.tags);
|
|
181
|
+
return ret;
|
|
182
|
+
}
|
|
183
|
+
#formatTsHelp(help) {
|
|
184
|
+
const signature = this.#partsToText(help.prefixDisplayParts) +
|
|
185
|
+
help.parameters
|
|
186
|
+
.map((p) => this.#partsToText(p.displayParts))
|
|
187
|
+
.join(this.#partsToText(help.separatorDisplayParts)) +
|
|
188
|
+
this.#partsToText(help.suffixDisplayParts);
|
|
189
|
+
const doc = this.#partsToText(help.documentation);
|
|
190
|
+
let ret = 'SIGNATURE: ' + signature + '\n';
|
|
191
|
+
ret += 'DOC: ' + doc + '\n';
|
|
192
|
+
return ret;
|
|
193
|
+
}
|
|
194
|
+
#formatLanguageClientHelp(help) {
|
|
195
|
+
return help.signatures
|
|
196
|
+
.map((s) => 'SIGNATURE: ' + s.label + '\n' + 'DOC: ' + s.documentation.value)
|
|
197
|
+
.join('\n');
|
|
198
|
+
}
|
|
199
|
+
async #getCompletions(model, position) {
|
|
200
|
+
try {
|
|
201
|
+
const line = model.getLineContent(position.lineNumber);
|
|
202
|
+
const word = line.substring(0, position.column);
|
|
203
|
+
let hasDot = false;
|
|
204
|
+
let afterDot = '';
|
|
205
|
+
for (let i = word.length - 1; i >= 0; i--) {
|
|
206
|
+
if (word[i] === ' ') {
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
if (word[i] === '.') {
|
|
210
|
+
hasDot = true;
|
|
211
|
+
afterDot = word.substring(i + 1).split('(')[0];
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (hasDot) {
|
|
216
|
+
if (this.#scriptLang === 'bun') {
|
|
217
|
+
return await this.#getTsCompletions(model, position, afterDot);
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
return await this.#getLanguageClientCompletions(model, position, afterDot);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return [];
|
|
224
|
+
}
|
|
225
|
+
catch (e) {
|
|
226
|
+
console.error('Error getting completions', e);
|
|
227
|
+
return [];
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
async #getTsCompletions(model, position, afterDot) {
|
|
231
|
+
try {
|
|
232
|
+
const offs = model.getOffsetAt(position);
|
|
233
|
+
const workerFactory = await languages.typescript.getTypeScriptWorker();
|
|
234
|
+
const worker = await workerFactory(model.uri);
|
|
235
|
+
const info = await worker.getCompletionsAtPosition(model.uri.toString(), offs);
|
|
236
|
+
let entries = [];
|
|
237
|
+
const filteredEntries = (info?.entries ?? []).filter((e) => afterDot ? e?.name?.startsWith(afterDot) : true);
|
|
238
|
+
const detailedEntries = await Promise.all(filteredEntries
|
|
239
|
+
.slice(0, MAX_COMPLETIONS_DETAILS)
|
|
240
|
+
.map((e) => worker.getCompletionEntryDetails(model.uri.toString(), offs, e.name)));
|
|
241
|
+
entries.push(...detailedEntries.map((e) => this.#formatCompletionEntry(e)));
|
|
242
|
+
// get signature of open parenthesis
|
|
243
|
+
const help = await worker.getSignatureHelpItems(model.uri.toString(), offs, {
|
|
244
|
+
triggerReason: { kind: 'invoked' }
|
|
245
|
+
});
|
|
246
|
+
if (help && help.items?.length > 0) {
|
|
247
|
+
entries.push(this.#formatTsHelp(help.items[0]));
|
|
248
|
+
}
|
|
249
|
+
return entries;
|
|
250
|
+
}
|
|
251
|
+
catch (e) {
|
|
252
|
+
console.error('Error getting ts completions', e);
|
|
253
|
+
return [];
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
async #getLanguageClientCompletions(model, position, afterDot) {
|
|
257
|
+
try {
|
|
258
|
+
if (!this.#languageClient) {
|
|
259
|
+
return [];
|
|
260
|
+
}
|
|
261
|
+
let entries = [];
|
|
262
|
+
const completions = await this.#languageClient.sendRequest('textDocument/completion', {
|
|
263
|
+
textDocument: { uri: model.uri.toString() },
|
|
264
|
+
position: {
|
|
265
|
+
line: position.lineNumber - 1,
|
|
266
|
+
character: position.column - 1
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
// if we failed to resolve a completion, don't try to resolve any more
|
|
270
|
+
let failedToResolve = false;
|
|
271
|
+
const detailedEntries = await Promise.all(completions.items
|
|
272
|
+
.filter((item) => (afterDot ? item.label.startsWith(afterDot) : true))
|
|
273
|
+
.slice(0, MAX_COMPLETIONS_DETAILS)
|
|
274
|
+
.map(async (item) => {
|
|
275
|
+
try {
|
|
276
|
+
if (failedToResolve) {
|
|
277
|
+
return '';
|
|
278
|
+
}
|
|
279
|
+
const resolvedItem = await this.#languageClient.sendRequest('completionItem/resolve', item);
|
|
280
|
+
return this.#formatLanguageClientHelp({
|
|
281
|
+
signatures: [resolvedItem]
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
catch (e) {
|
|
285
|
+
console.error('Failed to resolve completion item:', e);
|
|
286
|
+
failedToResolve = true;
|
|
287
|
+
return '';
|
|
288
|
+
}
|
|
289
|
+
}));
|
|
290
|
+
entries.push(...detailedEntries.filter((e) => e !== ''));
|
|
291
|
+
const help = await this.#languageClient.sendRequest('textDocument/signatureHelp', {
|
|
292
|
+
textDocument: { uri: model.uri.toString() },
|
|
293
|
+
position: {
|
|
294
|
+
line: position.lineNumber - 1, // LSP uses 0-based line numbers
|
|
295
|
+
character: position.column - 1 // LSP uses 0-based character positions
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
if (help && help.signatures.length > 0) {
|
|
299
|
+
entries.push(this.#formatLanguageClientHelp(help));
|
|
300
|
+
}
|
|
301
|
+
return entries;
|
|
302
|
+
}
|
|
303
|
+
catch (e) {
|
|
304
|
+
console.error('Error getting language client completions', e);
|
|
305
|
+
return [];
|
|
306
|
+
}
|
|
307
|
+
}
|
|
105
308
|
async #autocomplete(model, position) {
|
|
106
309
|
const thisTs = Date.now();
|
|
107
310
|
this.#lastTs = thisTs;
|
|
@@ -124,6 +327,12 @@ export class Autocompletor {
|
|
|
124
327
|
endLineNumber: model.getLineCount(),
|
|
125
328
|
endColumn: model.getLineMaxColumn(model.getLineCount())
|
|
126
329
|
});
|
|
330
|
+
const completions = await this.#getCompletions(model, position);
|
|
331
|
+
// reset cache for this line if new completions are available
|
|
332
|
+
if (completions.length > 0 && completions.some((c) => !this.#lastCompletions.includes(c))) {
|
|
333
|
+
this.#cache.delete(position.lineNumber);
|
|
334
|
+
}
|
|
335
|
+
this.#lastCompletions = completions;
|
|
127
336
|
const cachedCompletion = this.#cache.get(position.lineNumber);
|
|
128
337
|
if (cachedCompletion) {
|
|
129
338
|
if (position.column > cachedCompletion.column &&
|
|
@@ -148,10 +357,17 @@ export class Autocompletor {
|
|
|
148
357
|
endLineNumber: position.lineNumber,
|
|
149
358
|
endColumn: position.column
|
|
150
359
|
});
|
|
360
|
+
const markers = meditor.getModelMarkers({ resource: model.uri });
|
|
361
|
+
const markersAtCursor = this.#markersAtCursor(position, markers);
|
|
362
|
+
const librariesCompletions = completions
|
|
363
|
+
.join('\n')
|
|
364
|
+
.slice(0, Math.floor(this.#contextWindow * COMPLETIONS_MAX_RATIO));
|
|
151
365
|
const completion = await autocompleteRequest({
|
|
152
366
|
prefix,
|
|
153
367
|
suffix,
|
|
154
|
-
scriptLang: this.#scriptLang
|
|
368
|
+
scriptLang: this.#scriptLang,
|
|
369
|
+
markers: markersAtCursor,
|
|
370
|
+
libraries: librariesCompletions
|
|
155
371
|
}, this.#abortController);
|
|
156
372
|
if (!completion) {
|
|
157
373
|
return;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { type ScriptLang } from '../../../gen/types.gen';
|
|
2
|
+
import type { editor } from 'monaco-editor';
|
|
2
3
|
export declare function autocompleteRequest(context: {
|
|
3
4
|
prefix: string;
|
|
4
5
|
suffix: string;
|
|
5
6
|
scriptLang: ScriptLang | 'bunnative' | 'jsx' | 'tsx' | 'json';
|
|
7
|
+
markers: editor.IMarker[];
|
|
8
|
+
libraries: string;
|
|
6
9
|
}, abortController: AbortController): Promise<string | undefined>;
|
|
@@ -4,14 +4,22 @@ import { getFimCompletion } from '../lib';
|
|
|
4
4
|
import { getLangContext } from '../chat/script/core';
|
|
5
5
|
import {} from '../../../gen/types.gen';
|
|
6
6
|
import { getCommentSymbol } from '../utils';
|
|
7
|
+
function comment(commentSymbol, text) {
|
|
8
|
+
return text
|
|
9
|
+
.split('\n')
|
|
10
|
+
.map((line) => `${commentSymbol} ${line}`)
|
|
11
|
+
.join('\n');
|
|
12
|
+
}
|
|
7
13
|
export async function autocompleteRequest(context, abortController) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
let commentSymbol = getCommentSymbol(context.scriptLang);
|
|
15
|
+
let contextLines = comment(commentSymbol, 'You are a code completion assistant. You are given three important contexts (<LANGUAGE CONTEXT>, <DIAGNOSTICS>, <LIBRARY METHODS>) to help you complete the code.\n');
|
|
16
|
+
contextLines += comment(commentSymbol, 'LANGUAGE CONTEXT:\n');
|
|
17
|
+
contextLines += comment(commentSymbol, getLangContext(context.scriptLang) + '\n');
|
|
18
|
+
contextLines += comment(commentSymbol, 'DIAGNOSTICS:\n');
|
|
19
|
+
contextLines += comment(commentSymbol, context.markers.map((m) => m.message).join('\n') + '\n');
|
|
20
|
+
contextLines += comment(commentSymbol, 'LIBRARY METHODS:\n');
|
|
21
|
+
contextLines += comment(commentSymbol, context.libraries + '\n');
|
|
22
|
+
context.prefix = contextLines + '\n' + context.prefix;
|
|
15
23
|
const providerModel = get(copilotInfo).codeCompletionModel;
|
|
16
24
|
if (!providerModel) {
|
|
17
25
|
throw new Error('No code completion model selected');
|
|
@@ -54,8 +54,8 @@ const TS_WINDMILL_CLIENT_CONTEXT = `
|
|
|
54
54
|
The windmill client (wmill) can be used to interact with Windmill from the script. Import it with \`import * as wmill from "windmill-client"\`. Key functions include:
|
|
55
55
|
|
|
56
56
|
// Resource operations
|
|
57
|
-
wmill.getResource(path?: string): Promise<any> // Get resource value by path
|
|
58
|
-
wmill.setResource(value: any, path?: string): Promise<void> // Set resource value
|
|
57
|
+
wmill.getResource(path?: string, undefinedIfEmpty?: boolean): Promise<any> // Get resource value by path
|
|
58
|
+
wmill.setResource(value: any, path?: string, initializeToTypeIfNotExist?: string): Promise<void> // Set resource value
|
|
59
59
|
|
|
60
60
|
// State management (persistent across executions)
|
|
61
61
|
wmill.getState(): Promise<any> // Get shared state
|
|
@@ -63,36 +63,39 @@ wmill.setState(state: any): Promise<void> // Set shared state
|
|
|
63
63
|
|
|
64
64
|
// Variables
|
|
65
65
|
wmill.getVariable(path: string): Promise<string> // Get variable value
|
|
66
|
-
wmill.setVariable(path: string, value: string): Promise<void> // Set variable value
|
|
66
|
+
wmill.setVariable(path: string, value: string, isSecretIfNotExist?: boolean, descriptionIfNotExist?: string): Promise<void> // Set variable value
|
|
67
67
|
|
|
68
68
|
// Script execution
|
|
69
|
-
wmill.runScript(path
|
|
70
|
-
wmill.runScriptAsync(path: string, args
|
|
71
|
-
wmill.waitJob(jobId: string): Promise<any> // Wait for job completion and get result
|
|
69
|
+
wmill.runScript(path?: string | null, hash_?: string | null, args?: Record<string, any> | null, verbose?: boolean): Promise<any> // Run script synchronously
|
|
70
|
+
wmill.runScriptAsync(path: string | null, hash_: string | null, args: Record<string, any> | null, scheduledInSeconds?: number | null): Promise<string> // Run script async, returns job ID
|
|
71
|
+
wmill.waitJob(jobId: string, verbose?: boolean): Promise<any> // Wait for job completion and get result
|
|
72
|
+
wmill.getResult(jobId: string): Promise<any> // Get job result by ID
|
|
73
|
+
wmill.getResultMaybe(jobId: string): Promise<any> // Get job result by ID, returns undefined if not found
|
|
74
|
+
wmill.getRootJobId(jobId?: string): Promise<string> // Get root job ID from job ID
|
|
72
75
|
|
|
73
76
|
// S3 file operations (if S3 is configured)
|
|
74
|
-
wmill.loadS3File(s3object: S3Object |
|
|
75
|
-
wmill.
|
|
77
|
+
wmill.loadS3File(s3object: S3Object, s3ResourcePath?: string | undefined): Promise<Uint8Array | undefined> // Load file content from S3
|
|
78
|
+
wmill.loadS3FileStream(s3object: S3Object, s3ResourcePath?: string | undefined): Promise<Blob | undefined> // Load file content from S3 as stream
|
|
79
|
+
wmill.writeS3File(s3object: S3Object | undefined, fileContent: string | Blob, s3ResourcePath?: string | undefined): Promise<S3Object> // Write file to S3
|
|
76
80
|
|
|
77
81
|
// Flow operations
|
|
78
|
-
wmill.setFlowUserState(key: string, value: any): Promise<void> // Set flow user state
|
|
79
|
-
wmill.getFlowUserState(key: string): Promise<any> // Get flow user state
|
|
80
|
-
wmill.getResumeUrls(): Promise<{approvalPage: string, resume: string, cancel: string}> // Get approval URLs
|
|
82
|
+
wmill.setFlowUserState(key: string, value: any, errorIfNotPossible?: boolean): Promise<void> // Set flow user state
|
|
83
|
+
wmill.getFlowUserState(key: string, errorIfNotPossible?: boolean): Promise<any> // Get flow user state
|
|
84
|
+
wmill.getResumeUrls(approver?: string): Promise<{approvalPage: string, resume: string, cancel: string}> // Get approval URLs
|
|
81
85
|
|
|
82
|
-
|
|
83
|
-
wmill.getWorkspace(): string // Get current workspace
|
|
84
|
-
wmill.databaseUrlFromResource(path: string): Promise<string> // Get database URL from resource`;
|
|
86
|
+
`;
|
|
85
87
|
const PYTHON_WINDMILL_CLIENT_CONTEXT = `
|
|
86
88
|
|
|
87
89
|
The windmill client (wmill) can be used to interact with Windmill from the script. Import it with \`import wmill\`. Key functions include:
|
|
88
90
|
|
|
89
91
|
// Resource operations
|
|
90
|
-
wmill.get_resource(path: str) -> dict | None // Get resource value by path
|
|
92
|
+
wmill.get_resource(path: str, none_if_undefined: bool = False) -> dict | None // Get resource value by path
|
|
91
93
|
wmill.set_resource(path: str, value: Any, resource_type: str = "any") -> None // Set resource value
|
|
92
94
|
|
|
93
95
|
// State management (persistent across executions)
|
|
94
96
|
wmill.get_state() -> Any // Get shared state (deprecated, use flow user state)
|
|
95
97
|
wmill.set_state(value: Any) -> None // Set shared state
|
|
98
|
+
wmill.get_state_path() -> str // Get state path
|
|
96
99
|
wmill.get_flow_user_state(key: str) -> Any // Get flow user state
|
|
97
100
|
wmill.set_flow_user_state(key: str, value: Any) -> None // Set flow user state
|
|
98
101
|
|
|
@@ -101,22 +104,27 @@ wmill.get_variable(path: str) -> str // Get variable value
|
|
|
101
104
|
wmill.set_variable(path: str, value: str, is_secret: bool = False) -> None // Set variable value
|
|
102
105
|
|
|
103
106
|
// Script execution
|
|
104
|
-
wmill.run_script(path: str, args: dict = None, timeout = None) -> Any // Run script synchronously
|
|
105
|
-
wmill.run_script_async(path: str, args: dict = None, scheduled_in_secs: int = None) -> str // Run script async, returns job ID
|
|
106
|
-
wmill.wait_job(job_id: str, timeout = None) -> Any // Wait for job completion and get result
|
|
107
|
+
wmill.run_script(path: str = None, hash_: str = None, args: dict = None, timeout = None, verbose: bool = False, cleanup: bool = True, assert_result_is_not_none: bool = True) -> Any // Run script synchronously
|
|
108
|
+
wmill.run_script_async(path: str = None, hash_: str = None, args: dict = None, scheduled_in_secs: int = None) -> str // Run script async, returns job ID
|
|
109
|
+
wmill.wait_job(job_id: str, timeout = None, verbose: bool = False, cleanup: bool = True, assert_result_is_not_none: bool = False) -> Any // Wait for job completion and get result
|
|
110
|
+
wmill.get_result(job_id: str, assert_result_is_not_none: bool = True) -> Any // Get job result by ID
|
|
111
|
+
wmill.get_root_job_id(job_id: str | None = None) -> str // Get root job ID from job ID
|
|
107
112
|
|
|
108
113
|
// S3 file operations (if S3 is configured)
|
|
109
|
-
wmill.load_s3_file(s3object: S3Object | str, s3_resource_path: str = None) -> bytes // Load file content from S3
|
|
110
|
-
wmill.
|
|
114
|
+
wmill.load_s3_file(s3object: S3Object | str, s3_resource_path: str | None = None) -> bytes // Load file content from S3
|
|
115
|
+
wmill.load_s3_file_reader(s3object: S3Object | str, s3_resource_path: str | None = None) -> BufferedReader // Load S3 file as stream reader
|
|
116
|
+
wmill.write_s3_file(s3object: S3Object | str | None, file_content: BufferedReader | bytes, s3_resource_path: str | None = None, content_type: str | None = None, content_disposition: str | None = None) -> S3Object // Write file to S3
|
|
111
117
|
|
|
112
118
|
// Flow operations
|
|
113
|
-
wmill.run_flow_async(path: str, args: dict = None) -> str // Run flow asynchronously
|
|
119
|
+
wmill.run_flow_async(path: str, args: dict = None, scheduled_in_secs: int = None, do_not_track_in_parent: bool = True) -> str // Run flow asynchronously
|
|
114
120
|
wmill.get_resume_urls(approver: str = None) -> dict // Get approval URLs for flow steps
|
|
115
121
|
|
|
116
122
|
// Utilities
|
|
123
|
+
wmill.get_workspace() -> str // Get current workspace
|
|
117
124
|
wmill.whoami() -> dict // Get current user information
|
|
118
125
|
wmill.get_job_status(job_id: str) -> str // Get job status ("RUNNING" | "WAITING" | "COMPLETED")
|
|
119
|
-
wmill.set_progress(value: int) -> None // Set job progress (0-100)
|
|
126
|
+
wmill.set_progress(value: int, job_id: Optional[str] = None) -> None // Set job progress (0-100)
|
|
127
|
+
wmill.get_progress(job_id: Optional[str] = None) -> Any // Get job progress`;
|
|
120
128
|
const PYTHON_RESOURCE_TYPE_SYSTEM = `On Windmill, credentials and configuration are stored in resources and passed as parameters to main.
|
|
121
129
|
If you need credentials, you should add a parameter to \`main\` with the corresponding resource type.
|
|
122
130
|
You need to **redefine** the type of the resources that are needed before the main function as TypedDict, but only include them if they are actually needed to achieve the function purpose.
|
|
@@ -18,7 +18,7 @@ export interface ModelResponse {
|
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
20
|
export declare function fetchAvailableModels(resourcePath: string, workspace: string, provider: AIProvider): Promise<string[]>;
|
|
21
|
-
export declare function getModelContextWindow(model: string): 1000000 | 128000 | 200000;
|
|
21
|
+
export declare function getModelContextWindow(model: string): 1000000 | 128000 | 200000 | 32000;
|
|
22
22
|
export declare const PROVIDER_COMPLETION_CONFIG_MAP: Record<AIProvider, ChatCompletionCreateParams>;
|
|
23
23
|
declare class WorkspacedAIClients {
|
|
24
24
|
private openaiClient;
|
|
@@ -76,6 +76,9 @@ export function getModelContextWindow(model) {
|
|
|
76
76
|
else if (model.startsWith('claude') || model.startsWith('o4-mini') || model.startsWith('o3')) {
|
|
77
77
|
return 200000;
|
|
78
78
|
}
|
|
79
|
+
else if (model.startsWith('codestral')) {
|
|
80
|
+
return 32000;
|
|
81
|
+
}
|
|
79
82
|
else {
|
|
80
83
|
return 128000;
|
|
81
84
|
}
|
|
@@ -3,18 +3,18 @@ import Section from '../../Section.svelte';
|
|
|
3
3
|
import Toggle from '../../Toggle.svelte';
|
|
4
4
|
import Tooltip from '../../Tooltip.svelte';
|
|
5
5
|
import { SecondsInput } from '../../common';
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
let { flowModule = $bindable() } = $props();
|
|
7
|
+
let isCacheEnabled = $derived(Boolean(flowModule.cache_ttl));
|
|
8
8
|
</script>
|
|
9
9
|
|
|
10
10
|
<Section label="Cache" class="flex flex-col gap-4">
|
|
11
|
-
|
|
11
|
+
{#snippet header()}
|
|
12
12
|
<Tooltip documentationLink="https://www.windmill.dev/docs/flows/cache">
|
|
13
13
|
If defined, the result of the step will be cached for the number of seconds defined such that
|
|
14
14
|
if this step were to be re-triggered with the same input it would retrieve and return its
|
|
15
15
|
cached value instead of recomputing it.
|
|
16
16
|
</Tooltip>
|
|
17
|
-
|
|
17
|
+
{/snippet}
|
|
18
18
|
|
|
19
19
|
{#if flowModule.value.type != 'rawscript'}
|
|
20
20
|
<p
|
|
@@ -1,21 +1,7 @@
|
|
|
1
1
|
import type { FlowModule } from '../../../gen';
|
|
2
|
-
interface
|
|
3
|
-
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
4
|
-
$$bindings?: Bindings;
|
|
5
|
-
} & Exports;
|
|
6
|
-
(internal: unknown, props: Props & {
|
|
7
|
-
$$events?: Events;
|
|
8
|
-
$$slots?: Slots;
|
|
9
|
-
}): Exports & {
|
|
10
|
-
$set?: any;
|
|
11
|
-
$on?: any;
|
|
12
|
-
};
|
|
13
|
-
z_$$bindings?: Bindings;
|
|
14
|
-
}
|
|
15
|
-
declare const FlowModuleCache: $$__sveltets_2_IsomorphicComponent<{
|
|
2
|
+
interface Props {
|
|
16
3
|
flowModule: FlowModule;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
type FlowModuleCache = InstanceType<typeof FlowModuleCache>;
|
|
4
|
+
}
|
|
5
|
+
declare const FlowModuleCache: import("svelte").Component<Props, {}, "flowModule">;
|
|
6
|
+
type FlowModuleCache = ReturnType<typeof FlowModuleCache>;
|
|
21
7
|
export default FlowModuleCache;
|
|
@@ -352,7 +352,6 @@ let rawScriptLang = $derived(flowModule.value.type == 'rawscript' ? flowModule.v
|
|
|
352
352
|
bind:this={editor}
|
|
353
353
|
class="h-full relative"
|
|
354
354
|
code={flowModule.value.content}
|
|
355
|
-
lang={scriptLangToEditorLang(flowModule?.value?.language)}
|
|
356
355
|
scriptLang={flowModule?.value?.language}
|
|
357
356
|
automaticLayout={true}
|
|
358
357
|
cmdEnterAction={async () => {
|
|
@@ -797,6 +796,7 @@ let rawScriptLang = $derived(flowModule.value.type == 'rawscript' ? flowModule.v
|
|
|
797
796
|
disableMock={preprocessorModule || failureModule}
|
|
798
797
|
disableHistory={failureModule}
|
|
799
798
|
loadingJob={stepHistoryLoader?.stepStates[flowModule.id]?.loadingJobs}
|
|
799
|
+
tagLabel={customUi?.tagLabel}
|
|
800
800
|
/>
|
|
801
801
|
</Pane>
|
|
802
802
|
{/if}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
<script lang="ts">import Toggle from '../../Toggle.svelte';
|
|
2
2
|
import Tooltip from '../../Tooltip.svelte';
|
|
3
3
|
import Section from '../../Section.svelte';
|
|
4
|
-
|
|
5
|
-
export let disabled = false;
|
|
4
|
+
let { flowModule = $bindable(), disabled = false } = $props();
|
|
6
5
|
</script>
|
|
7
6
|
|
|
8
7
|
<Section label="Delete after use">
|
|
9
|
-
|
|
8
|
+
{#snippet header()}
|
|
10
9
|
<Tooltip>
|
|
11
10
|
The logs, arguments and results of this flow step will be completely deleted from Windmill
|
|
12
11
|
once the flow is complete. They might be temporarily visible in UI while the flow is running.
|
|
@@ -21,7 +20,7 @@ export let disabled = false;
|
|
|
21
20
|
This option is only available on Windmill Enterprise Edition.
|
|
22
21
|
{/if}
|
|
23
22
|
</Tooltip>
|
|
24
|
-
|
|
23
|
+
{/snippet}
|
|
25
24
|
|
|
26
25
|
<Toggle
|
|
27
26
|
{disabled}
|
|
@@ -1,22 +1,8 @@
|
|
|
1
1
|
import type { FlowModule } from '../../../gen';
|
|
2
|
-
interface
|
|
3
|
-
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
4
|
-
$$bindings?: Bindings;
|
|
5
|
-
} & Exports;
|
|
6
|
-
(internal: unknown, props: Props & {
|
|
7
|
-
$$events?: Events;
|
|
8
|
-
$$slots?: Slots;
|
|
9
|
-
}): Exports & {
|
|
10
|
-
$set?: any;
|
|
11
|
-
$on?: any;
|
|
12
|
-
};
|
|
13
|
-
z_$$bindings?: Bindings;
|
|
14
|
-
}
|
|
15
|
-
declare const FlowModuleDeleteAfterUse: $$__sveltets_2_IsomorphicComponent<{
|
|
2
|
+
interface Props {
|
|
16
3
|
flowModule: FlowModule;
|
|
17
4
|
disabled?: boolean;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
type FlowModuleDeleteAfterUse = InstanceType<typeof FlowModuleDeleteAfterUse>;
|
|
5
|
+
}
|
|
6
|
+
declare const FlowModuleDeleteAfterUse: import("svelte").Component<Props, {}, "flowModule">;
|
|
7
|
+
type FlowModuleDeleteAfterUse = ReturnType<typeof FlowModuleDeleteAfterUse>;
|
|
22
8
|
export default FlowModuleDeleteAfterUse;
|