diff --git a/frontend/src/lib/components/EditorBar.svelte b/frontend/src/lib/components/EditorBar.svelte index 5b5681b3b3..91044ead7a 100644 --- a/frontend/src/lib/components/EditorBar.svelte +++ b/frontend/src/lib/components/EditorBar.svelte @@ -76,6 +76,7 @@ diffMode?: boolean showHistoryDrawer?: boolean right?: import('svelte').Snippet + openAiChat?: boolean } let { @@ -98,7 +99,8 @@ lastDeployedCode = undefined, diffMode = false, showHistoryDrawer = $bindable(false), - right + right, + openAiChat = false }: Props = $props() let contextualVariablePicker: ItemPicker | undefined = $state() @@ -810,7 +812,7 @@ JsonNode ${windmillPathToCamelCaseName(path)} = JsonNode.Parse(await client.GetS {/if} {#if customUi?.aiGen != false} - + {/if} diff --git a/frontend/src/lib/components/copilot/ScriptGen.svelte b/frontend/src/lib/components/copilot/ScriptGen.svelte index 02e48cf20a..cb7ab6c946 100644 --- a/frontend/src/lib/components/copilot/ScriptGen.svelte +++ b/frontend/src/lib/components/copilot/ScriptGen.svelte @@ -28,6 +28,7 @@ import { twMerge } from 'tailwind-merge' import { onDestroy } from 'svelte' import ProviderModelSelector from './chat/ProviderModelSelector.svelte' + import { aiChatManager, AIMode } from './chat/AIChatManager.svelte' interface Props { // props @@ -38,6 +39,7 @@ inlineScript?: boolean args: Record transformer?: boolean + openAiChat?: boolean } let { @@ -47,7 +49,8 @@ diffEditor, inlineScript = false, args, - transformer = false + transformer = false, + openAiChat = false }: Props = $props() run(() => { @@ -72,6 +75,54 @@ run(() => { trimmedDesc = funcDesc.trim() }) + async function callCopilot() { + if (mode === 'edit') { + await copilot( + { + // @ts-ignore + language: transformer && lang === 'frontend' ? 'transformer' : lang!, + description: trimmedDesc, + code: editor?.getCode() || '', + dbSchema: dbSchema, + type: 'edit', + workspace: $workspaceStore! + }, + generatedCode, + abortController + ) + } else { + await copilot( + { + // @ts-ignore + language: transformer && lang === 'frontend' ? 'transformer' : lang!, + description: trimmedDesc, + dbSchema: dbSchema, + type: 'gen', + workspace: $workspaceStore! + }, + generatedCode, + abortController + ) + } + } + + function handleAiButtonClick() { + if (editor && isInitialCode(editor.getCode())) { + mode = 'gen' + } else { + mode = 'edit' + } + + if (openAiChat) { + // Open the AI chat in script mode + aiChatManager.openChat() + aiChatManager.changeMode(AIMode.SCRIPT) + } else { + setTimeout(() => { + autoResize() + }, 0) + } + } async function onGenerate(closePopup: () => void) { if (trimmedDesc.length <= 0) { @@ -82,34 +133,7 @@ genLoading = true blockPopupOpen = true abortController = new AbortController() - if (mode === 'edit') { - await copilot( - { - // @ts-ignore - language: transformer && lang === 'frontend' ? 'transformer' : lang!, - description: trimmedDesc, - code: editor?.getCode() || '', - dbSchema: dbSchema, - type: 'edit', - workspace: $workspaceStore! - }, - generatedCode, - abortController - ) - } else { - await copilot( - { - // @ts-ignore - language: transformer && lang === 'frontend' ? 'transformer' : lang!, - description: trimmedDesc, - dbSchema: dbSchema, - type: 'gen', - workspace: $workspaceStore! - }, - generatedCode, - abortController - ) - } + await callCopilot() setupDiff() diffEditor?.setModified($generatedCode) blockPopupOpen = false @@ -205,14 +229,27 @@ } let promptHistory: string[] = $state([]) - function getPromptHistory() { + + function getPromptStorageKey() { + return 'prompts-' + lang + } + + function safeLocalStorageOperation(operation: () => T, defaultValue?: T): T | undefined { try { - promptHistory = JSON.parse(localStorage.getItem('prompts-' + lang) || '[]') + return operation() } catch (e) { console.error('error interacting with local storage', e) + return defaultValue } } + function getPromptHistory() { + const storageKey = getPromptStorageKey() + promptHistory = + safeLocalStorageOperation(() => JSON.parse(localStorage.getItem(storageKey) || '[]'), []) || + [] + } + function savePrompt() { if (promptHistory.includes(trimmedDesc)) { return @@ -221,20 +258,14 @@ while (promptHistory.length > 5) { promptHistory.pop() } - try { - localStorage.setItem('prompts-' + lang, JSON.stringify(promptHistory)) - } catch (e) { - console.error('error interacting with local storage', e) - } + const storageKey = getPromptStorageKey() + safeLocalStorageOperation(() => localStorage.setItem(storageKey, JSON.stringify(promptHistory))) } function clearPromptHistory() { promptHistory = [] - try { - localStorage.setItem('prompts-' + lang, JSON.stringify(promptHistory)) - } catch (e) { - console.error('error interacting with local storage', e) - } + const storageKey = getPromptStorageKey() + safeLocalStorageOperation(() => localStorage.setItem(storageKey, JSON.stringify(promptHistory))) } run(() => { lang && getPromptHistory() @@ -266,6 +297,12 @@ ;(dbSchema as any).publicOnly = detail === 'true' } + const aiChatScriptModeClasses = $derived( + aiChatManager.mode === AIMode.SCRIPT && aiChatManager.isOpen + ? 'dark:bg-violet-900 bg-violet-100' + : '' + ) + onDestroy(() => { abortController?.abort() }) @@ -343,22 +380,9 @@