windmill-components 1.700.2 → 1.700.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/appPolicy/myFunction.es.js +1337 -0
- package/dist/sharedUtils/common.d.ts +2 -5
- package/dist/sharedUtils/components/apps/components/display/dbtable/queries/select.d.ts +0 -2
- package/dist/sharedUtils/components/apps/components/display/dbtable/utils.d.ts +3 -14
- package/dist/sharedUtils/components/apps/editor/appPolicy.d.ts +1 -1
- package/dist/sharedUtils/components/apps/editor/appUtilsS3.d.ts +1 -12
- package/dist/sharedUtils/components/apps/editor/component/components.d.ts +2 -68
- package/dist/sharedUtils/components/apps/inputType.d.ts +2 -4
- package/dist/sharedUtils/components/apps/sharedTypes.d.ts +0 -2
- package/dist/sharedUtils/components/dbTypes.d.ts +0 -3
- package/dist/sharedUtils/components/raw_apps/rawAppPolicy.d.ts +1 -1
- package/dist/sharedUtils/components/raw_apps/utils.d.ts +1 -1
- package/dist/sharedUtils/components/triggers/utils.d.ts +3 -2
- package/dist/sharedUtils/gen/schemas.gen.d.ts +71 -915
- package/dist/sharedUtils/gen/services.gen.d.ts +23 -329
- package/dist/sharedUtils/gen/types.gen.d.ts +141 -1870
- package/dist/sharedUtils/hub.d.ts +0 -1
- package/dist/sharedUtils/jsr.json +5 -5
- package/dist/sharedUtils/lib.d.ts +1 -1
- package/dist/sharedUtils/lib.es.js +79 -241
- package/dist/sharedUtils/package.json +11 -11
- package/dist/sharedUtils/stores.d.ts +0 -1
- package/dist/sharedUtils/svelte5Utils.svelte.d.ts +1 -32
- package/dist/sharedUtils/utils.d.ts +4 -19
- package/package/components/DisplayResultControlBar.svelte +26 -11
- package/package/components/JobArgs.svelte +43 -24
- package/package/components/ShareModal.svelte.d.ts +1 -1
- package/package/components/apps/components/helpers/RunnableComponent.svelte.d.ts +0 -3
- package/package/components/copilot/CustomAIPrompts.svelte +3 -2
- package/package/components/copilot/chat/AIChatInput.svelte +2 -0
- package/package/components/copilot/chat/AIChatManager.svelte.js +52 -14
- package/package/components/copilot/chat/CreatedResourceActionDrawers.svelte +15 -0
- package/package/components/copilot/chat/ToolMessageActions.svelte +4 -2
- package/package/components/copilot/chat/app/core.js +2 -30
- package/package/components/copilot/chat/flow/core.js +13 -351
- package/package/components/copilot/chat/flow/editableFlowJson.d.ts +52 -0
- package/package/components/copilot/chat/flow/editableFlowJson.js +328 -0
- package/package/components/copilot/chat/flow/inlineScriptsUtils.js +2 -2
- package/package/components/copilot/chat/global/core.d.ts +5 -0
- package/package/components/copilot/chat/global/core.js +1739 -0
- package/package/components/copilot/chat/global/core.test.d.ts +1 -0
- package/package/components/copilot/chat/global/core.test.js +123 -0
- package/package/components/copilot/chat/global/deployRequests.d.ts +7 -0
- package/package/components/copilot/chat/global/deployRequests.js +76 -0
- package/package/components/copilot/chat/global/deployRequests.test.d.ts +1 -0
- package/package/components/copilot/chat/global/deployRequests.test.js +142 -0
- package/package/components/copilot/chat/global/draftStore.svelte.d.ts +55 -0
- package/package/components/copilot/chat/global/draftStore.svelte.js +78 -0
- package/package/components/copilot/chat/global/draftStore.test.d.ts +1 -0
- package/package/components/copilot/chat/global/draftStore.test.js +44 -0
- package/package/components/copilot/chat/global/gate.d.ts +1 -0
- package/package/components/copilot/chat/global/gate.js +27 -0
- package/package/components/copilot/chat/shared.d.ts +16 -2
- package/package/components/copilot/chat/shared.js +40 -0
- package/package/components/copilot/chat/workspaceToolsZod.gen.d.ts +28 -9
- package/package/components/copilot/chat/workspaceToolsZod.gen.js +19 -0
- package/package/components/raw_apps/templates.d.ts +77 -0
- package/package/components/raw_apps/templates.js +618 -0
- package/package/components/runs/runsFilter.d.ts +1 -1
- package/package/components/settings/AIPromptsModal.svelte +5 -2
- package/package/components/triggers/azure/AzureTriggerEditorConfigSection.svelte.d.ts +1 -1
- package/package/gen/core/OpenAPI.js +1 -1
- package/package/gen/schemas.gen.d.ts +37 -355
- package/package/gen/schemas.gen.js +39 -359
- package/package/gen/services.gen.d.ts +4 -280
- package/package/gen/services.gen.js +7 -565
- package/package/gen/types.gen.d.ts +77 -1135
- package/package/system_prompts/index.d.ts +2 -0
- package/package/system_prompts/index.js +8 -0
- package/package/system_prompts/prompts.d.ts +2 -0
- package/package/system_prompts/prompts.js +381 -0
- package/package/utils_deployable.d.ts +5 -318
- package/package.json +1 -1
- package/dist/sharedUtils/components/assets/lib.d.ts +0 -25
- package/dist/sharedUtils/components/icons/index.d.ts +0 -101
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import * as runed from 'runed/kit';
|
|
3
|
-
import type z from 'zod';
|
|
1
|
+
import type { StateStore } from './utils';
|
|
4
2
|
export declare function withProps<Component, Props>(component: Component, props: Props): {
|
|
5
3
|
component: Component;
|
|
6
4
|
props: Props;
|
|
@@ -32,9 +30,6 @@ export type UsePromiseOptions = {
|
|
|
32
30
|
loadInit?: boolean;
|
|
33
31
|
clearValueOnRefresh?: boolean;
|
|
34
32
|
};
|
|
35
|
-
/**
|
|
36
|
-
* @deprecated Use `resource` from `runed` instead
|
|
37
|
-
*/
|
|
38
33
|
export declare function usePromise<T>(createPromise: () => Promise<T>, { loadInit, clearValueOnRefresh }?: UsePromiseOptions): UsePromiseResult<T>;
|
|
39
34
|
/**
|
|
40
35
|
* Generic change tracker class that monitors changes in state using deep equality comparison
|
|
@@ -52,29 +47,3 @@ export declare class ChangeTracker<T> {
|
|
|
52
47
|
*/
|
|
53
48
|
track(value: T): boolean;
|
|
54
49
|
}
|
|
55
|
-
/**
|
|
56
|
-
* This allows using async resources that only fetch missing data based on a set of keys.
|
|
57
|
-
* It maintains a Record of the fetched data and only calls the fetcher for keys that
|
|
58
|
-
* are not already present in the map.
|
|
59
|
-
* The fetcher takes a record of keys to allow fetching multiple items in a single call.
|
|
60
|
-
*/
|
|
61
|
-
export declare class MapResource<U, T> {
|
|
62
|
-
private _cached;
|
|
63
|
-
private _fetcherResource;
|
|
64
|
-
constructor(getValues: () => Record<string, U>, fetcher: (toFetch: Record<string, U>) => Promise<Record<string, T>>);
|
|
65
|
-
get current(): Record<string, T> | undefined;
|
|
66
|
-
get loading(): boolean;
|
|
67
|
-
get error(): Error | undefined;
|
|
68
|
-
}
|
|
69
|
-
export declare class ChangeOnDeepInequality<T> {
|
|
70
|
-
private _cached;
|
|
71
|
-
constructor(compute: () => T);
|
|
72
|
-
get value(): T;
|
|
73
|
-
}
|
|
74
|
-
export declare function useSearchParams<S extends z.ZodType>(schema: S, options?: runed.SearchParamsOptions): runed.ReturnUseSearchParams<S>;
|
|
75
|
-
export declare class StaleWhileLoading<T> {
|
|
76
|
-
private _current;
|
|
77
|
-
private _currentTimeout;
|
|
78
|
-
constructor(getter: () => T, timeout?: number);
|
|
79
|
-
get current(): T | undefined;
|
|
80
|
-
}
|
|
@@ -38,7 +38,7 @@ export declare function validateUsername(username: string): string;
|
|
|
38
38
|
export declare function parseQueryParams(url: string | undefined): Record<string, string>;
|
|
39
39
|
export declare function displayDateOnly(dateString: string | Date | undefined): string;
|
|
40
40
|
export declare function retrieveCommonWorkerPrefix(workerName: string): string;
|
|
41
|
-
export declare function subtractDaysFromDateString(dateString: string |
|
|
41
|
+
export declare function subtractDaysFromDateString(dateString: string | undefined, days: number): string | undefined;
|
|
42
42
|
export declare function displayDate(dateString: string | Date | undefined, displaySecond?: boolean, displayDate?: boolean): string;
|
|
43
43
|
export declare function displayTime(dateString: string | Date | undefined): string;
|
|
44
44
|
export declare function displaySize(sizeInBytes: number | undefined): string | undefined;
|
|
@@ -63,7 +63,6 @@ export declare function clickOutside(node: Node, options?: ClickOutsideOptions |
|
|
|
63
63
|
destroy(): void;
|
|
64
64
|
update(newOptions: ClickOutsideOptions | boolean): void;
|
|
65
65
|
};
|
|
66
|
-
export declare function undefinedIfEmpty(obj: any): any;
|
|
67
66
|
export declare function pointerDownOutside(node: Node, options?: ClickOutsideOptions): {
|
|
68
67
|
destroy(): void;
|
|
69
68
|
update(newOptions: ClickOutsideOptions): void;
|
|
@@ -137,12 +136,6 @@ export declare function throttle<T>(func: (...args: any[]) => T, wait: number):
|
|
|
137
136
|
export declare function isMac(): boolean;
|
|
138
137
|
export declare function getModifierKey(): string;
|
|
139
138
|
export declare function isValidHexColor(color: string): boolean;
|
|
140
|
-
/**
|
|
141
|
-
* Generates a text color with the same hue as the background but adjusted lightness for good contrast
|
|
142
|
-
* @param backgroundColor Hex color string (e.g., "#FF0000" or "#F00")
|
|
143
|
-
* @returns Hex color string with same hue but good contrast, or undefined if invalid
|
|
144
|
-
*/
|
|
145
|
-
export declare function getContrastTextColor(backgroundColor: string | null | undefined): string | undefined;
|
|
146
139
|
export declare function sortObject<T>(o: T & object): T;
|
|
147
140
|
export declare function sortArray<T>(array: T[], compareFn?: (a: T, b: T) => number): T[];
|
|
148
141
|
export declare function generateRandomString(len?: number): string;
|
|
@@ -187,7 +180,7 @@ export declare function getSchemaFromProperties(properties: {
|
|
|
187
180
|
}): Schema;
|
|
188
181
|
export declare function validateFileExtension(ext: string): boolean;
|
|
189
182
|
export declare function isFlowPreview(job_kind: Job['job_kind'] | undefined): job_kind is "flowpreview" | "flownode";
|
|
190
|
-
export declare function isNotFlow(job_kind: Job['job_kind'] | undefined): job_kind is "script" | "aiagent" | "identity" | "preview" | "dependencies" | "flowdependencies" | "appdependencies" | "script_hub" | "deploymentcallback" | "flowscript" | "appscript" |
|
|
183
|
+
export declare function isNotFlow(job_kind: Job['job_kind'] | undefined): job_kind is "script" | "aiagent" | "identity" | "preview" | "dependencies" | "flowdependencies" | "appdependencies" | "script_hub" | "deploymentcallback" | "flowscript" | "appscript" | undefined;
|
|
191
184
|
export declare function isScriptPreview(job_kind: Job['job_kind'] | undefined): job_kind is "preview" | "flowscript" | "appscript";
|
|
192
185
|
export declare function conditionalMelt(node: HTMLElement, meltItem: AnyMeltElement | undefined): void | import("svelte/action").ActionReturn<undefined, Record<never, any>>;
|
|
193
186
|
export type Item = {
|
|
@@ -202,7 +195,6 @@ export type Item = {
|
|
|
202
195
|
hide?: boolean | undefined;
|
|
203
196
|
extra?: Snippet;
|
|
204
197
|
id?: string;
|
|
205
|
-
tooltip?: string;
|
|
206
198
|
};
|
|
207
199
|
export declare function isObjectTooBig(obj: any): boolean;
|
|
208
200
|
export declare function localeConcatAnd(items: string[]): string;
|
|
@@ -210,9 +202,11 @@ export declare function formatDate(dateString: string | undefined): string;
|
|
|
210
202
|
export declare function formatDateShort(dateString: string | undefined): string;
|
|
211
203
|
export declare function toJsonStr(result: any): string;
|
|
212
204
|
export declare function getOS(): "Windows" | "macOS" | "iOS" | "Android" | "Linux" | "Unknown OS";
|
|
205
|
+
import { type ClassValue } from 'clsx';
|
|
213
206
|
import type { Component, Snippet } from 'svelte';
|
|
214
207
|
import { OpenAPIV2, type OpenAPI, type OpenAPIV3, type OpenAPIV3_1 } from 'openapi-types';
|
|
215
208
|
import type { IPosition } from 'monaco-editor';
|
|
209
|
+
export declare function cn(...inputs: ClassValue[]): string;
|
|
216
210
|
export type StateStore<T> = {
|
|
217
211
|
val: T;
|
|
218
212
|
};
|
|
@@ -247,7 +241,6 @@ export declare function wait(ms: number): Promise<unknown>;
|
|
|
247
241
|
export declare function validateRetryConfig(retry: Retry | undefined): string | null;
|
|
248
242
|
export type CssColor = keyof (typeof tokensFile)['tokens']['light'];
|
|
249
243
|
import tokensFile from './assets/tokens/tokens.json';
|
|
250
|
-
import { Package } from 'lucide-svelte';
|
|
251
244
|
export declare function getCssColor(color: CssColor, { alpha, format }: {
|
|
252
245
|
alpha?: number;
|
|
253
246
|
format?: 'css-var' | 'hex-dark' | 'hex-light';
|
|
@@ -255,11 +248,3 @@ export declare function getCssColor(color: CssColor, { alpha, format }: {
|
|
|
255
248
|
export type IconType = Component<{
|
|
256
249
|
size?: number;
|
|
257
250
|
}> | typeof import('lucide-svelte').Dot;
|
|
258
|
-
export declare function getJobKindIcon(jobKind: Job['job_kind']): import("svelte/legacy").LegacyComponentType | typeof Package | undefined;
|
|
259
|
-
export declare function chunkBy<T>(array: T[], getKey: (key: T) => string): T[][];
|
|
260
|
-
export declare function getQueryStmtCountHeuristic(query: string): number;
|
|
261
|
-
export declare function countChars(str: string, char: string): number;
|
|
262
|
-
export declare function buildReactiveObj<T extends object>(fields: {
|
|
263
|
-
[name in keyof T]: [() => T[name], (v: T[name]) => void];
|
|
264
|
-
}): T;
|
|
265
|
-
export declare function pick<T extends object, K extends keyof T>(obj: T, keys: readonly K[]): Pick<T, K>;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { Download, InfoIcon, ClipboardCopy, Expand } from 'lucide-svelte';
|
|
3
3
|
import Popover from './Popover.svelte';
|
|
4
4
|
import { copyToClipboard } from '../utils';
|
|
5
|
+
import { downloadViaClient, shouldDownloadViaClient } from '../utils/downloadFile';
|
|
5
6
|
import { createEventDispatcher } from 'svelte';
|
|
6
7
|
let { customUi = undefined, filename = undefined, workspaceId = undefined, jobId = undefined, nodeId = undefined, base, result, disableTooltips = false } = $props();
|
|
7
8
|
const dispatch = createEventDispatcher();
|
|
@@ -13,21 +14,35 @@ function toJsonStr(result) {
|
|
|
13
14
|
return 'error stringifying object: ' + e.toString();
|
|
14
15
|
}
|
|
15
16
|
}
|
|
17
|
+
let resultApiPath = $derived(workspaceId && jobId
|
|
18
|
+
? nodeId
|
|
19
|
+
? `/w/${workspaceId}/jobs/result_by_id/${jobId}/${nodeId}`
|
|
20
|
+
: `/w/${workspaceId}/jobs_u/completed/get_result/${jobId}`
|
|
21
|
+
: undefined);
|
|
22
|
+
let downloadName = $derived(`${filename ?? 'result'}.json`);
|
|
16
23
|
</script>
|
|
17
24
|
|
|
18
25
|
<div class={twMerge('flex flex-row gap-2.5 z-10 text-primary -mt-1 items-center')}>
|
|
19
26
|
{#if customUi?.disableDownload !== true}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
<
|
|
30
|
-
|
|
27
|
+
{#if resultApiPath && shouldDownloadViaClient()}
|
|
28
|
+
<button
|
|
29
|
+
class="text-current"
|
|
30
|
+
onclick={() => downloadViaClient(resultApiPath!, downloadName)}
|
|
31
|
+
aria-label="Download result"
|
|
32
|
+
>
|
|
33
|
+
<Download size={14} />
|
|
34
|
+
</button>
|
|
35
|
+
{:else}
|
|
36
|
+
<a
|
|
37
|
+
download={downloadName}
|
|
38
|
+
class="text-current"
|
|
39
|
+
href={resultApiPath
|
|
40
|
+
? `${base}/api${resultApiPath}`
|
|
41
|
+
: `data:text/json;charset=utf-8,${encodeURIComponent(toJsonStr(result))}`}
|
|
42
|
+
>
|
|
43
|
+
<Download size={14} />
|
|
44
|
+
</a>
|
|
45
|
+
{/if}
|
|
31
46
|
{/if}
|
|
32
47
|
{#if disableTooltips !== true}
|
|
33
48
|
<Popover documentationLink="https://www.windmill.dev/docs/core_concepts/rich_display_rendering">
|
|
@@ -11,10 +11,14 @@ import Row from './table/Row.svelte';
|
|
|
11
11
|
import HighlightTheme from './HighlightTheme.svelte';
|
|
12
12
|
import { deepEqual } from 'fast-equals';
|
|
13
13
|
import { isWindmillTooBigObject } from './job_args';
|
|
14
|
+
import { downloadViaClient, shouldDownloadViaClient } from '../utils/downloadFile';
|
|
14
15
|
let { id = undefined, args, argLabel = undefined, workspace = undefined } = $props();
|
|
15
16
|
let jsonViewer = $state();
|
|
16
17
|
let runLocally = $state();
|
|
17
18
|
let jsonStr = $state('');
|
|
19
|
+
const argsDownloadName = 'windmill-args.json';
|
|
20
|
+
let argsApiPath = $derived(id && workspace ? `/w/${workspace}/jobs_u/get_args/${id}` : undefined);
|
|
21
|
+
let argsDataHref = $derived(`data:text/json;charset=utf-8,${encodeURIComponent(jsonStr)}`);
|
|
18
22
|
function pythonCode() {
|
|
19
23
|
return `
|
|
20
24
|
if __name__ == "__main__":
|
|
@@ -47,10 +51,12 @@ ${Object.entries(args)
|
|
|
47
51
|
{#if args && typeof args === 'object' && deepEqual( Object.keys(args ?? {}), ['reason'] ) && args['reason'] == 'PREPROCESSOR_ARGS_ARE_DISCARDED'}
|
|
48
52
|
Preprocessor args are discarded
|
|
49
53
|
{:else if id && workspace && args && typeof args === 'object' && deepEqual( Object.keys(args ?? {}), ['reason'] ) && args['reason'] == 'WINDMILL_TOO_BIG'}
|
|
50
|
-
The args are too big in size to be able to fetch alongside job. Please <
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
+
The args are too big in size to be able to fetch alongside job. Please {#if shouldDownloadViaClient()}<button
|
|
55
|
+
class="text-blue-500 hover:underline"
|
|
56
|
+
onclick={() => downloadViaClient(argsApiPath!, argsDownloadName)}
|
|
57
|
+
>download the JSON file to view them</button
|
|
58
|
+
>{:else}<a href="/api{argsApiPath}" target="_blank">download the JSON file to view them</a
|
|
59
|
+
>{/if}.
|
|
54
60
|
{:else}
|
|
55
61
|
<div class="relative">
|
|
56
62
|
<DataTable size="sm" containerClass="bg-surface-tertiary">
|
|
@@ -107,17 +113,26 @@ ${Object.entries(args)
|
|
|
107
113
|
<Drawer bind:this={jsonViewer} size="900px">
|
|
108
114
|
<DrawerContent title="Expanded Args" on:close={jsonViewer.closeDrawer}>
|
|
109
115
|
{#snippet actions()}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
116
|
+
{#if argsApiPath && shouldDownloadViaClient()}
|
|
117
|
+
<Button
|
|
118
|
+
on:click={() => downloadViaClient(argsApiPath!, argsDownloadName)}
|
|
119
|
+
startIcon={{ icon: Download }}
|
|
120
|
+
size="xs"
|
|
121
|
+
color="light"
|
|
122
|
+
>
|
|
123
|
+
Download
|
|
124
|
+
</Button>
|
|
125
|
+
{:else}
|
|
126
|
+
<Button
|
|
127
|
+
download={argsDownloadName}
|
|
128
|
+
href={argsApiPath ? `/api${argsApiPath}` : argsDataHref}
|
|
129
|
+
startIcon={{ icon: Download }}
|
|
130
|
+
size="xs"
|
|
131
|
+
color="light"
|
|
132
|
+
>
|
|
133
|
+
Download
|
|
134
|
+
</Button>
|
|
135
|
+
{/if}
|
|
121
136
|
<Button
|
|
122
137
|
on:click={() => runLocally?.openDrawer()}
|
|
123
138
|
color="light"
|
|
@@ -137,15 +152,19 @@ ${Object.entries(args)
|
|
|
137
152
|
{/snippet}
|
|
138
153
|
{#if jsonStr.length > 100000 || (id && workspace && args && isWindmillTooBigObject(args))}
|
|
139
154
|
<div class="text-sm mb-2 text-primary">
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
155
|
+
{#if argsApiPath && shouldDownloadViaClient()}
|
|
156
|
+
<button
|
|
157
|
+
class="underline"
|
|
158
|
+
onclick={() => downloadViaClient(argsApiPath!, argsDownloadName)}
|
|
159
|
+
>
|
|
160
|
+
JSON is too large to be displayed in full.
|
|
161
|
+
</button>
|
|
162
|
+
{:else}
|
|
163
|
+
<a download={argsDownloadName} href={argsApiPath ? `/api${argsApiPath}` : argsDataHref}>
|
|
164
|
+
JSON is too large to be displayed in full.
|
|
165
|
+
</a>
|
|
166
|
+
{/if}
|
|
167
|
+
</div>
|
|
149
168
|
{:else}
|
|
150
169
|
<Highlight language={json} code={jsonStr.replace(/\\n/g, '\n')} />
|
|
151
170
|
{/if}
|
|
@@ -16,7 +16,7 @@ declare const ShareModal: $$__sveltets_2_IsomorphicComponent<Record<string, neve
|
|
|
16
16
|
} & {
|
|
17
17
|
[evt: string]: CustomEvent<any>;
|
|
18
18
|
}, {}, {
|
|
19
|
-
openDrawer: (newPath: string, kind_l: "resource" | "volume" | "script" | "flow" | "app" | "variable" | "schedule" | "raw_app" | "http_trigger" | "websocket_trigger" | "kafka_trigger" | "nats_trigger" | "postgres_trigger" | "mqtt_trigger" | "
|
|
19
|
+
openDrawer: (newPath: string, kind_l: "resource" | "volume" | "script" | "flow" | "app" | "variable" | "schedule" | "raw_app" | "group_" | "http_trigger" | "websocket_trigger" | "kafka_trigger" | "nats_trigger" | "postgres_trigger" | "mqtt_trigger" | "gcp_trigger" | "sqs_trigger" | "email_trigger" | "azure_trigger", isOwnerOverride?: boolean) => Promise<void>;
|
|
20
20
|
}, "">;
|
|
21
21
|
type ShareModal = InstanceType<typeof ShareModal>;
|
|
22
22
|
export default ShareModal;
|
|
@@ -84,7 +84,6 @@ declare const RunnableComponent: $$__sveltets_2_IsomorphicComponent<Props, {
|
|
|
84
84
|
path?: string;
|
|
85
85
|
lock?: string;
|
|
86
86
|
cache_ttl?: number;
|
|
87
|
-
tag?: string;
|
|
88
87
|
};
|
|
89
88
|
id?: number;
|
|
90
89
|
force_viewer_static_fields?: {
|
|
@@ -94,8 +93,6 @@ declare const RunnableComponent: $$__sveltets_2_IsomorphicComponent<Props, {
|
|
|
94
93
|
[key: string]: unknown;
|
|
95
94
|
};
|
|
96
95
|
force_viewer_allow_user_resources?: Array<(string)>;
|
|
97
|
-
force_viewer_sensitive_inputs?: Array<(string)>;
|
|
98
|
-
force_viewer_delete_after_secs?: number;
|
|
99
96
|
run_query_params?: {
|
|
100
97
|
[key: string]: unknown;
|
|
101
98
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<script lang="ts">import { AIMode } from './chat/AIChatManager.svelte';
|
|
1
|
+
<script lang="ts">import { AIMode, getVisibleAIModes } from './chat/AIChatManager.svelte';
|
|
2
2
|
import ToggleButtonGroup from '../common/toggleButton-v2/ToggleButtonGroup.svelte';
|
|
3
3
|
import ToggleButton from '../common/toggleButton-v2/ToggleButton.svelte';
|
|
4
4
|
import Label from '../Label.svelte';
|
|
@@ -6,6 +6,7 @@ import autosize from '../../autosize';
|
|
|
6
6
|
const MAX_CUSTOM_PROMPT_LENGTH = 5000;
|
|
7
7
|
let { customPrompts = $bindable(), title, description } = $props();
|
|
8
8
|
let selectedAiMode = $state(AIMode.ASK);
|
|
9
|
+
let visibleModes = $derived(getVisibleAIModes());
|
|
9
10
|
</script>
|
|
10
11
|
|
|
11
12
|
<div class="flex flex-col gap-2">
|
|
@@ -17,7 +18,7 @@ let selectedAiMode = $state(AIMode.ASK);
|
|
|
17
18
|
<Label label="AI Mode">
|
|
18
19
|
<ToggleButtonGroup bind:selected={selectedAiMode}>
|
|
19
20
|
{#snippet children({ item })}
|
|
20
|
-
{#each
|
|
21
|
+
{#each visibleModes as mode (mode)}
|
|
21
22
|
<div class="relative">
|
|
22
23
|
<ToggleButton
|
|
23
24
|
value={mode}
|
|
@@ -30,6 +30,8 @@ const modePlaceholder = $derived.by(() => {
|
|
|
30
30
|
return 'Navigate Windmill UI...';
|
|
31
31
|
case AIMode.API:
|
|
32
32
|
return 'Make API calls...';
|
|
33
|
+
case AIMode.GLOBAL:
|
|
34
|
+
return 'Work across workspace items...';
|
|
33
35
|
case AIMode.ASK:
|
|
34
36
|
return 'Ask questions about Windmill...';
|
|
35
37
|
default:
|
|
@@ -22,6 +22,8 @@ import { createAppBackendRunnableContextElement, createAppFrontendFileContextEle
|
|
|
22
22
|
import { prepareApiSystemMessage, prepareApiUserMessage } from './api/core';
|
|
23
23
|
import { runChatLoop } from './chatLoop';
|
|
24
24
|
import { getCurrentModel, tryGetCurrentModel, getCombinedCustomPrompt } from '../../../aiStore';
|
|
25
|
+
import { globalTools, prepareGlobalSystemMessage, prepareGlobalUserMessage } from './global/core';
|
|
26
|
+
import { isGlobalAiEnabled } from './global/gate';
|
|
25
27
|
// If the estimated token usage is greater than the model context window - the threshold, we delete the oldest message
|
|
26
28
|
const MAX_TOKENS_THRESHOLD_PERCENTAGE = 0.05;
|
|
27
29
|
const MAX_TOKENS_HARD_LIMIT = 5000;
|
|
@@ -32,8 +34,19 @@ export var AIMode;
|
|
|
32
34
|
AIMode["APP"] = "app";
|
|
33
35
|
AIMode["NAVIGATOR"] = "navigator";
|
|
34
36
|
AIMode["API"] = "API";
|
|
37
|
+
AIMode["GLOBAL"] = "global";
|
|
35
38
|
AIMode["ASK"] = "ask";
|
|
36
39
|
})(AIMode || (AIMode = {}));
|
|
40
|
+
const ALL_AI_MODES = Object.values(AIMode);
|
|
41
|
+
export function isAIMode(mode) {
|
|
42
|
+
return ALL_AI_MODES.includes(mode);
|
|
43
|
+
}
|
|
44
|
+
export function isAIModeVisible(mode) {
|
|
45
|
+
return mode !== AIMode.GLOBAL || isGlobalAiEnabled();
|
|
46
|
+
}
|
|
47
|
+
export function getVisibleAIModes() {
|
|
48
|
+
return ALL_AI_MODES.filter(isAIModeVisible);
|
|
49
|
+
}
|
|
37
50
|
function isWorkspacePath(path) {
|
|
38
51
|
return path?.startsWith('f/') === true || path?.startsWith('u/') === true;
|
|
39
52
|
}
|
|
@@ -82,7 +95,9 @@ class AIChatManager {
|
|
|
82
95
|
app: this.appAiChatHelpers !== undefined,
|
|
83
96
|
navigator: true,
|
|
84
97
|
ask: true,
|
|
85
|
-
API: true
|
|
98
|
+
API: true,
|
|
99
|
+
// Dev-only gate. See `./global/gate.ts` for how to enable.
|
|
100
|
+
global: isAIModeVisible(AIMode.GLOBAL)
|
|
86
101
|
});
|
|
87
102
|
open = $derived(chatState.size > 0);
|
|
88
103
|
checkTokenUsageOverLimit = (messages) => {
|
|
@@ -182,6 +197,8 @@ class AIChatManager {
|
|
|
182
197
|
};
|
|
183
198
|
};
|
|
184
199
|
changeMode(mode, pendingPrompt, options) {
|
|
200
|
+
if (!isAIModeVisible(mode))
|
|
201
|
+
return;
|
|
185
202
|
if (mode === AIMode.SCRIPT && !tryGetCurrentModel())
|
|
186
203
|
return;
|
|
187
204
|
this.mode = mode;
|
|
@@ -251,6 +268,12 @@ class AIChatManager {
|
|
|
251
268
|
this.tools = [...this.apiTools];
|
|
252
269
|
this.helpers = {};
|
|
253
270
|
}
|
|
271
|
+
else if (mode === AIMode.GLOBAL) {
|
|
272
|
+
const customPrompt = getCombinedCustomPrompt(mode);
|
|
273
|
+
this.systemMessage = prepareGlobalSystemMessage(customPrompt);
|
|
274
|
+
this.tools = [...globalTools];
|
|
275
|
+
this.helpers = {};
|
|
276
|
+
}
|
|
254
277
|
else if (mode === AIMode.APP) {
|
|
255
278
|
const customPrompt = getCombinedCustomPrompt(mode);
|
|
256
279
|
this.systemMessage = prepareAppSystemMessage(customPrompt);
|
|
@@ -264,14 +287,24 @@ class AIChatManager {
|
|
|
264
287
|
type: 'function',
|
|
265
288
|
function: {
|
|
266
289
|
name: 'change_mode',
|
|
267
|
-
description: 'Change the AI mode to the one specified. Script mode is used to create scripts. Flow mode is used to create flows.
|
|
290
|
+
description: 'Change the AI mode to the one specified. Script mode is used to create scripts. Flow mode is used to create flows.' +
|
|
291
|
+
(isGlobalAiEnabled()
|
|
292
|
+
? ' Global mode is used to inspect workspace scripts and flows and create draft changes.'
|
|
293
|
+
: '') +
|
|
294
|
+
' Navigator mode is used to navigate the application and help the user find what they are looking for. API mode is used to make API calls to the Windmill backend.',
|
|
268
295
|
parameters: {
|
|
269
296
|
type: 'object',
|
|
270
297
|
properties: {
|
|
271
298
|
mode: {
|
|
272
299
|
type: 'string',
|
|
273
300
|
description: 'The mode to change to',
|
|
274
|
-
enum: [
|
|
301
|
+
enum: [
|
|
302
|
+
'script',
|
|
303
|
+
'flow',
|
|
304
|
+
...(isGlobalAiEnabled() ? ['global'] : []),
|
|
305
|
+
'navigator',
|
|
306
|
+
'API'
|
|
307
|
+
]
|
|
275
308
|
},
|
|
276
309
|
pendingPrompt: {
|
|
277
310
|
type: 'string',
|
|
@@ -284,6 +317,9 @@ class AIChatManager {
|
|
|
284
317
|
}
|
|
285
318
|
},
|
|
286
319
|
fn: async ({ args, toolId, toolCallbacks }) => {
|
|
320
|
+
if (!isAIMode(args.mode) || !isAIModeVisible(args.mode)) {
|
|
321
|
+
throw new Error(`AI mode "${args.mode}" is not enabled`);
|
|
322
|
+
}
|
|
287
323
|
toolCallbacks.setToolStatus(toolId, { content: 'Switching to ' + args.mode + ' mode...' });
|
|
288
324
|
this.changeMode(args.mode, args.pendingPrompt, {
|
|
289
325
|
closeScriptSettings: true
|
|
@@ -393,6 +429,9 @@ class AIChatManager {
|
|
|
393
429
|
else if (this.mode === AIMode.NAVIGATOR) {
|
|
394
430
|
return prepareNavigatorUserMessage(pendingPrompt);
|
|
395
431
|
}
|
|
432
|
+
else if (this.mode === AIMode.GLOBAL) {
|
|
433
|
+
return prepareGlobalUserMessage(pendingPrompt);
|
|
434
|
+
}
|
|
396
435
|
return undefined;
|
|
397
436
|
},
|
|
398
437
|
onBeforeIteration: async (tools) => {
|
|
@@ -493,18 +532,14 @@ class AIChatManager {
|
|
|
493
532
|
}
|
|
494
533
|
};
|
|
495
534
|
sendRequest = async (options = {}) => {
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
isPreprocessor: options.isPreprocessor
|
|
500
|
-
});
|
|
501
|
-
}
|
|
502
|
-
else {
|
|
503
|
-
this.changeMode(this.mode, undefined, {
|
|
504
|
-
lang: options.lang,
|
|
505
|
-
isPreprocessor: options.isPreprocessor
|
|
506
|
-
});
|
|
535
|
+
const requestedMode = options.mode ?? this.mode;
|
|
536
|
+
if (!isAIModeVisible(requestedMode)) {
|
|
537
|
+
return;
|
|
507
538
|
}
|
|
539
|
+
this.changeMode(requestedMode, undefined, {
|
|
540
|
+
lang: options.lang,
|
|
541
|
+
isPreprocessor: options.isPreprocessor
|
|
542
|
+
});
|
|
508
543
|
if (options.instructions) {
|
|
509
544
|
this.instructions = options.instructions;
|
|
510
545
|
}
|
|
@@ -579,6 +614,9 @@ class AIChatManager {
|
|
|
579
614
|
case AIMode.API:
|
|
580
615
|
userMessage = prepareApiUserMessage(oldInstructions);
|
|
581
616
|
break;
|
|
617
|
+
case AIMode.GLOBAL:
|
|
618
|
+
userMessage = prepareGlobalUserMessage(oldInstructions);
|
|
619
|
+
break;
|
|
582
620
|
case AIMode.APP:
|
|
583
621
|
userMessage = prepareAppUserMessage(oldInstructions, this.appAiChatHelpers?.getSelectedContext(), oldSelectedContext);
|
|
584
622
|
break;
|
|
@@ -2,12 +2,16 @@
|
|
|
2
2
|
import { Drawer } from '../../common';
|
|
3
3
|
import DrawerContent from '../../common/drawer/DrawerContent.svelte';
|
|
4
4
|
import { Loader2 } from 'lucide-svelte';
|
|
5
|
+
import ResourceEditorDrawer from '../../ResourceEditorDrawer.svelte';
|
|
6
|
+
import VariableEditor from '../../VariableEditor.svelte';
|
|
5
7
|
import { registerToolDisplayActionHandler } from './createdResourceActions.svelte';
|
|
6
8
|
const DRAWER_SIZE = '800px';
|
|
7
9
|
let drawer = $state(undefined);
|
|
8
10
|
let editor = $state(undefined);
|
|
9
11
|
let activeDrawer = $state(undefined);
|
|
10
12
|
let nextActiveDrawerId = 0;
|
|
13
|
+
let resourceEditorDrawer = $state(undefined);
|
|
14
|
+
let variableEditor = $state(undefined);
|
|
11
15
|
const drawerConfigs = {
|
|
12
16
|
schedule: {
|
|
13
17
|
label: 'schedule',
|
|
@@ -84,6 +88,14 @@ async function openCreatedResource(action) {
|
|
|
84
88
|
if (action.type !== 'open_created_resource') {
|
|
85
89
|
return;
|
|
86
90
|
}
|
|
91
|
+
if (action.resource === 'resource') {
|
|
92
|
+
await resourceEditorDrawer?.initEdit(action.path);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (action.resource === 'variable') {
|
|
96
|
+
await variableEditor?.editVariable(action.path);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
87
99
|
const key = action.resource === 'schedule' ? 'schedule' : action.triggerKind;
|
|
88
100
|
if (!key) {
|
|
89
101
|
throw new Error('Missing trigger kind');
|
|
@@ -127,3 +139,6 @@ onDestroy(() => {
|
|
|
127
139
|
{/if}
|
|
128
140
|
</DrawerContent>
|
|
129
141
|
</Drawer>
|
|
142
|
+
|
|
143
|
+
<ResourceEditorDrawer bind:this={resourceEditorDrawer} />
|
|
144
|
+
<VariableEditor bind:this={variableEditor} />
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">import { Button } from '../../common';
|
|
2
|
-
import { Calendar, Database, Route, SquarePen, Unplug, Webhook } from 'lucide-svelte';
|
|
2
|
+
import { Calendar, Database, KeyRound, Package, Route, SquarePen, Unplug, Webhook } from 'lucide-svelte';
|
|
3
3
|
import AwsIcon from '../../icons/AwsIcon.svelte';
|
|
4
4
|
import AzureIcon from '../../icons/AzureIcon.svelte';
|
|
5
5
|
import GoogleCloudIcon from '../../icons/GoogleCloudIcon.svelte';
|
|
@@ -11,6 +11,8 @@ let { actions } = $props();
|
|
|
11
11
|
let runningActionId = $state(undefined);
|
|
12
12
|
const actionCardConfigs = {
|
|
13
13
|
schedule: { title: 'Schedule', icon: Calendar },
|
|
14
|
+
resource: { title: 'Resource', icon: Package },
|
|
15
|
+
variable: { title: 'Variable', icon: KeyRound },
|
|
14
16
|
http: { title: 'HTTP trigger', icon: Route },
|
|
15
17
|
websocket: { title: 'WebSocket trigger', icon: Unplug },
|
|
16
18
|
postgres: { title: 'Postgres trigger', icon: Database },
|
|
@@ -22,7 +24,7 @@ const actionCardConfigs = {
|
|
|
22
24
|
azure: { title: 'Azure Event Grid trigger', icon: AzureIcon }
|
|
23
25
|
};
|
|
24
26
|
function getActionCardConfig(action) {
|
|
25
|
-
const key = action.resource === '
|
|
27
|
+
const key = action.resource === 'trigger' ? action.triggerKind : action.resource;
|
|
26
28
|
return key
|
|
27
29
|
? actionCardConfigs[key]
|
|
28
30
|
: { title: action.label.replace(/^Open\s+/i, ''), icon: Webhook };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { createSearchHubScriptsTool, createToolDef, createSearchWorkspaceTool, createGetRunnableDetailsTool } from '../shared';
|
|
2
|
+
import { createSearchHubScriptsTool, createToolDef, createSearchWorkspaceTool, createGetRunnableDetailsTool, findAndReplace } from '../shared';
|
|
3
3
|
import { aiChatManager } from '../AIChatManager.svelte';
|
|
4
4
|
import { formatAppDatatableContextTitle } from '../context';
|
|
5
5
|
// ============= Utility =============
|
|
@@ -8,25 +8,6 @@ const memo = (factory) => {
|
|
|
8
8
|
let cached;
|
|
9
9
|
return () => (cached ??= factory());
|
|
10
10
|
};
|
|
11
|
-
function countExactMatches(content, search) {
|
|
12
|
-
if (search.length === 0) {
|
|
13
|
-
return 0;
|
|
14
|
-
}
|
|
15
|
-
let count = 0;
|
|
16
|
-
let index = 0;
|
|
17
|
-
while ((index = content.indexOf(search, index)) !== -1) {
|
|
18
|
-
count += 1;
|
|
19
|
-
index += search.length;
|
|
20
|
-
}
|
|
21
|
-
return count;
|
|
22
|
-
}
|
|
23
|
-
function replaceFirstExactMatch(content, search, replace) {
|
|
24
|
-
const index = content.indexOf(search);
|
|
25
|
-
if (index === -1) {
|
|
26
|
-
return content;
|
|
27
|
-
}
|
|
28
|
-
return content.slice(0, index) + replace + content.slice(index + search.length);
|
|
29
|
-
}
|
|
30
11
|
function resolveAppPatchTarget(rawPath) {
|
|
31
12
|
const trimmedPath = rawPath.trim();
|
|
32
13
|
const backendMatch = trimmedPath.match(/^backend\/([^/]+)\/main\.(ts|py)$/);
|
|
@@ -309,16 +290,7 @@ export const getAppTools = memo(() => [
|
|
|
309
290
|
}
|
|
310
291
|
currentContent = backendRunnable.inlineScript.content ?? '';
|
|
311
292
|
}
|
|
312
|
-
const
|
|
313
|
-
if (matchCount === 0) {
|
|
314
|
-
throw new Error('old_string was not found in the current file content.');
|
|
315
|
-
}
|
|
316
|
-
if (!replaceAll && matchCount !== 1) {
|
|
317
|
-
throw new Error(`old_string matched ${matchCount} locations. Make it more specific or set replace_all to true.`);
|
|
318
|
-
}
|
|
319
|
-
const updatedContent = replaceAll
|
|
320
|
-
? currentContent.split(oldString).join(newString)
|
|
321
|
-
: replaceFirstExactMatch(currentContent, oldString, newString);
|
|
293
|
+
const updatedContent = findAndReplace(currentContent, oldString, newString, replaceAll, 'current file content');
|
|
322
294
|
toolCallbacks.setToolStatus(toolId, {
|
|
323
295
|
content: `Patching '${target.path}'...`
|
|
324
296
|
});
|