windmill-components 1.510.1 → 1.511.0

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 (55) hide show
  1. package/package/components/AppConnectInner.svelte +28 -5
  2. package/package/components/Editor.svelte +108 -84
  3. package/package/components/Editor.svelte.d.ts +30 -55
  4. package/package/components/HttpAgentWorkerDrawer.svelte +1 -1
  5. package/package/components/JsonEditor.svelte +11 -11
  6. package/package/components/JsonEditor.svelte.d.ts +14 -56
  7. package/package/components/Label.svelte +6 -11
  8. package/package/components/Label.svelte.d.ts +14 -39
  9. package/package/components/NumberTypeNarrowing.svelte +13 -16
  10. package/package/components/NumberTypeNarrowing.svelte.d.ts +4 -18
  11. package/package/components/ResourceTypePicker.svelte +20 -17
  12. package/package/components/ResourceTypePicker.svelte.d.ts +7 -6
  13. package/package/components/Section.svelte +7 -20
  14. package/package/components/Section.svelte.d.ts +20 -47
  15. package/package/components/SimpleEditor.svelte +4 -4
  16. package/package/components/SimpleEditor.svelte.d.ts +1 -0
  17. package/package/components/SqlRepl.svelte +0 -1
  18. package/package/components/Subsection.svelte +10 -12
  19. package/package/components/Subsection.svelte.d.ts +15 -39
  20. package/package/components/WorkerGroup.svelte +260 -165
  21. package/package/components/WorkerGroup.svelte.d.ts +2 -0
  22. package/package/components/WorkerTagPicker.svelte +3 -3
  23. package/package/components/WorkerTagSelect.svelte +3 -3
  24. package/package/components/copilot/AIFormSettings.svelte +3 -4
  25. package/package/components/copilot/AIFormSettings.svelte.d.ts +5 -19
  26. package/package/components/copilot/autocomplete/Autocompletor.d.ts +3 -1
  27. package/package/components/copilot/autocomplete/Autocompletor.js +250 -34
  28. package/package/components/copilot/autocomplete/request.d.ts +3 -0
  29. package/package/components/copilot/autocomplete/request.js +15 -7
  30. package/package/components/copilot/chat/script/core.js +30 -22
  31. package/package/components/copilot/lib.d.ts +1 -1
  32. package/package/components/copilot/lib.js +3 -0
  33. package/package/components/flows/content/FlowModuleCache.svelte +4 -4
  34. package/package/components/flows/content/FlowModuleCache.svelte.d.ts +4 -18
  35. package/package/components/flows/content/FlowModuleComponent.svelte +0 -1
  36. package/package/components/flows/content/FlowModuleDeleteAfterUse.svelte +3 -4
  37. package/package/components/flows/content/FlowModuleDeleteAfterUse.svelte.d.ts +4 -18
  38. package/package/components/flows/content/FlowModuleSleep.svelte +6 -7
  39. package/package/components/flows/content/FlowModuleSleep.svelte.d.ts +4 -18
  40. package/package/components/flows/content/FlowModuleSuspend.svelte +19 -17
  41. package/package/components/flows/content/FlowModuleSuspend.svelte.d.ts +4 -18
  42. package/package/components/flows/content/FlowModuleTimeout.svelte +4 -4
  43. package/package/components/flows/content/FlowModuleTimeout.svelte.d.ts +4 -18
  44. package/package/components/triggers/gcp/GcpTriggerEditorInner.svelte +4 -4
  45. package/package/components/triggers/http/OpenAPISpecGenerator.svelte +2 -2
  46. package/package/components/triggers/http/RouteEditorConfigSection.svelte +26 -23
  47. package/package/components/triggers/http/RouteEditorConfigSection.svelte.d.ts +5 -19
  48. package/package/components/triggers/http/RouteEditorInner.svelte +18 -18
  49. package/package/components/triggers/kafka/KafkaTriggerEditorInner.svelte +4 -4
  50. package/package/components/triggers/mqtt/MqttTriggerEditorInner.svelte +4 -4
  51. package/package/components/triggers/nats/NatsTriggerEditorInner.svelte +4 -4
  52. package/package/components/triggers/schedules/ScheduleEditorInner.svelte +4 -4
  53. package/package/components/triggers/sqs/SqsTriggerEditorInner.svelte +4 -4
  54. package/package/components/triggers/websocket/WebsocketTriggerEditorInner.svelte +4 -4
  55. package/package.json +1 -1
@@ -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
- const completion = filterCompletion(result.completion, result.suffix, shouldReturnMultiline);
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
- else {
68
- return {
69
- items: []
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
- const langContext = getLangContext(context.scriptLang);
9
- const commentSymbol = getCommentSymbol(context.scriptLang);
10
- if (langContext) {
11
- const contextLines = langContext.split('\n');
12
- const commentedContext = contextLines.map((line) => `${commentSymbol} ${line}`).join('\n');
13
- context.prefix = commentedContext + '\n' + context.prefix;
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: string, args?: Record<string, any>): Promise<any> // Run script synchronously
70
- wmill.runScriptAsync(path: string, args?: Record<string, any>): Promise<string> // Run script async, returns job ID
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 | string): Promise<Uint8Array> // Load file content from S3
75
- wmill.writeS3File(s3object: S3Object | string, content: string | Blob): Promise<S3Object> // Write file to S3
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
- // Utilities
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.write_s3_file(s3object: S3Object | str, file_content: bytes, s3_resource_path: str = None) -> S3Object // Write file to S3
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
- export let flowModule;
7
- $: isCacheEnabled = Boolean(flowModule.cache_ttl);
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
- <svelte:fragment slot="header">
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
- </svelte:fragment>
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 $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
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
- [evt: string]: CustomEvent<any>;
19
- }, {}, {}, string>;
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 () => {
@@ -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
- export let flowModule;
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
- <svelte:fragment slot="header">
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
- </svelte:fragment>
23
+ {/snippet}
25
24
 
26
25
  <Toggle
27
26
  {disabled}
@@ -1,22 +1,8 @@
1
1
  import type { FlowModule } from '../../../gen';
2
- interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
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
- [evt: string]: CustomEvent<any>;
20
- }, {}, {}, string>;
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;