diff --git a/frontend/src/lib/components/FlowBuilder.svelte b/frontend/src/lib/components/FlowBuilder.svelte index 74cf2eb0cd..17c1f04818 100644 --- a/frontend/src/lib/components/FlowBuilder.svelte +++ b/frontend/src/lib/components/FlowBuilder.svelte @@ -749,12 +749,6 @@ } let flowPreviewButtons: FlowPreviewButtons - - let flowEditor: FlowEditor | undefined = undefined - $: if (flowEditor) { - flowCopilotContext.toggleAiPanel = flowEditor.toggleAiPanel - flowCopilotContext.addSelectedLinesToAiChat = flowEditor.addSelectedLinesToAiChat - } @@ -971,7 +965,6 @@ {#if $flowStateStore} - {#if lang && editor && diffEditor && $testStepStore[mod.id] && selectedJob && 'result' in selectedJob && selectedJob.result && typeof selectedJob.result == 'object' && `error` in selectedJob.result && selectedJob.result.error} - + {#if lang && editor && diffEditor && $testStepStore[mod.id] && selectedJob?.type === 'CompletedJob' && !selectedJob.success && getStringError(selectedJob.result)} + {/if} diff --git a/frontend/src/lib/components/ScriptEditor.svelte b/frontend/src/lib/components/ScriptEditor.svelte index 9fb0098bb9..aaa0510952 100644 --- a/frontend/src/lib/components/ScriptEditor.svelte +++ b/frontend/src/lib/components/ScriptEditor.svelte @@ -312,16 +312,6 @@ let testPanelSize = 30 let storedTestPanelSize = testPanelSize - function addSelectedLinesToAiChat( - e: CustomEvent<{ lines: string; startLine: number; endLine: number }> - ) { - if (!aiChatManager.open) { - aiChatManager.toggleOpen() - } - aiChatManager.addSelectedLinesToContext(e.detail.lines, e.detail.startLine, e.detail.endLine) - // aiChatManager.focusTextArea() TODO: Add this back - } - $: !SUPPORTED_CHAT_SCRIPT_LANGUAGES.includes(lang ?? '') && !aiChatManager.open && aiChatManager.toggleOpen() @@ -530,7 +520,10 @@ }} on:saveDraft on:toggleAiPanel={() => aiChatManager.toggleOpen()} - on:addSelectedLinesToAiChat={addSelectedLinesToAiChat} + on:addSelectedLinesToAiChat={(e) => { + const { lines, startLine, endLine } = e.detail + aiChatManager.addSelectedLinesToContext(lines, startLine, endLine) + }} on:toggleTestPanel={toggleTestPanel} cmdEnterAction={async () => { await inferSchema(code) @@ -678,10 +671,6 @@ { - aiChatManager.fix() - }} - fixChatMode {lang} previewJob={testJob} {pastPreviews} diff --git a/frontend/src/lib/components/copilot/ScriptFix.svelte b/frontend/src/lib/components/copilot/ScriptFix.svelte index a6dd7e2cdb..568abeb507 100644 --- a/frontend/src/lib/components/copilot/ScriptFix.svelte +++ b/frontend/src/lib/components/copilot/ScriptFix.svelte @@ -2,172 +2,23 @@ import { base } from '$lib/base' import { Button } from '../common' - import { SUPPORTED_LANGUAGES, copilot } from './lib' + import { SUPPORTED_LANGUAGES } from './lib' import type { SupportedLanguage } from '$lib/common' - import { sendUserToast } from '$lib/toast' - import type Editor from '../Editor.svelte' - import { dbSchemas, copilotInfo, type DBSchema, workspaceStore } from '$lib/stores' - import type DiffEditor from '../DiffEditor.svelte' - import { scriptLangToEditorLang } from '$lib/scripts' import Popover from '$lib/components/meltComponents/Popover.svelte' - import { writable } from 'svelte/store' - import { WindmillIcon } from '../icons' - import HighlightCode from '../HighlightCode.svelte' - import LoadingIcon from '../apps/svelte-select/lib/LoadingIcon.svelte' import { autoPlacement } from '@floating-ui/core' - import { Check, Wand2, X, RotateCw } from 'lucide-svelte' - import { createEventDispatcher } from 'svelte' + import { WandSparkles } from 'lucide-svelte' + import { aiChatManager } from './chat/AIChatManager.svelte' + import { copilotInfo } from '$lib/stores' - // props - export let lang: SupportedLanguage - export let editor: Editor | undefined - export let diffEditor: DiffEditor | undefined - export let error: string - export let args: Record - export let chatMode: boolean = false - - // state - let genLoading: boolean = false - let generatedCode = writable('') - let generatedExplanation = writable('') - let dbSchema: DBSchema | undefined = undefined - let abortController: AbortController | undefined = undefined - - const dispatch = createEventDispatcher<{ - fix: null - }>() - - async function onFix() { - if (!error) { - return - } - try { - genLoading = true - abortController = new AbortController() - await copilot( - { - language: lang, - code: editor?.getCode() || '', - error, - dbSchema: dbSchema, - type: 'fix', - workspace: $workspaceStore! - }, - generatedCode, - abortController, - generatedExplanation - ) - setupDiff() - diffEditor?.setModified($generatedCode) - showDiff() - } catch (err) { - if (!abortController?.signal.aborted) { - if (err?.message) { - sendUserToast('Failed to generate code: ' + err.message, true) - } else { - sendUserToast('Failed to generate code', true) - console.error(err) - } - } - } finally { - genLoading = false - } - } - - function acceptDiff() { - editor?.setCode(diffEditor?.getModified() || '') - editor?.format() - clear() - } - - function rejectDiff() { - clear() - } - - function setupDiff() { - diffEditor?.setupModel(scriptLangToEditorLang(lang)) - diffEditor?.setOriginal(editor?.getCode() || '') - } - - function showDiff() { - diffEditor?.show() - editor?.hide() - } - - function hideDiff() { - editor?.show() - diffEditor?.hide() - } - - function clear() { - $generatedCode = '' - $generatedExplanation = '' - } - - $: lang && clear() - - $: !$generatedCode && hideDiff() - - function updateSchema(lang, args) { - const schemaRes = lang === 'graphql' ? args.api : args.database - if (typeof schemaRes === 'string') { - dbSchema = $dbSchemas[schemaRes.replace('$res:', '')] - } - } - $: updateSchema(lang, args) - - let popover: Popover | undefined = undefined + let { + lang + }: { + lang: SupportedLanguage + } = $props() {#if SUPPORTED_LANGUAGES.has(lang)} - {#if !genLoading && $generatedCode.length > 0} - - { - popover?.close() - rejectDiff() - }} - variant="contained" - startIcon={{ icon: X }} - propagateEvent={true} - > - Discard - - { - popover?.close() - acceptDiff() - }} - startIcon={{ icon: Check }} - propagateEvent={true} - > - Accept - - { - $generatedExplanation = '' - popover?.open() - onFix() - }} - startIcon={{ icon: RotateCw }} - title="Retry" - btnClasses="text-violet-800 dark:text-violet-400" - /> - - {/if} - + dispatch('fix') - : genLoading - ? () => abortController?.abort() - : $generatedCode.length > 0 - ? () => {} - : () => onFix()} - btnClasses={genLoading - ? '' - : 'text-violet-800 dark:text-violet-400 bg-violet-100 dark:bg-gray-700 min-w-[84px]'} + startIcon={{ icon: WandSparkles }} + on:click={() => { + if ($copilotInfo.enabled) { + aiChatManager.fix() + } + }} + btnClasses="text-violet-800 dark:text-violet-400 bg-violet-100 dark:bg-gray-700 min-w-[84px]" + propagateEvent={!$copilotInfo.enabled} > - {#if genLoading} - - Stop - {:else if $generatedCode.length > 0} - {isOpen ? 'Hide' : 'Show'} - {:else} - AI Fix - {/if} + AI Fix - {#if $copilotInfo.enabled} - - {#if $generatedCode.length > 0 && genLoading} - - - - {:else if genLoading} - - {/if} - {#if $generatedExplanation.length > 0} - Explanation: test {$generatedExplanation} - {/if} - - {:else} - - Enable Windmill AI in the workspace settings - {/if} + + Enable Windmill AI in the workspace settings diff --git a/frontend/src/lib/components/copilot/chat/AIChatManager.svelte.ts b/frontend/src/lib/components/copilot/chat/AIChatManager.svelte.ts index ed7f25acd5..4642c16c5c 100644 --- a/frontend/src/lib/components/copilot/chat/AIChatManager.svelte.ts +++ b/frontend/src/lib/components/copilot/chat/AIChatManager.svelte.ts @@ -474,12 +474,20 @@ class AIChatManager { } fix = () => { + if (!this.open) { + this.toggleOpen() + } + this.changeMode('script') this.instructions = 'Fix the error' this.contextManager?.setFixContext() this.sendRequest() } addSelectedLinesToContext = (lines: string, startLine: number, endLine: number) => { + if (!this.open) { + this.toggleOpen() + } + this.changeMode('script') this.contextManager?.addSelectedLinesToContext(lines, startLine, endLine) } diff --git a/frontend/src/lib/components/copilot/flow.ts b/frontend/src/lib/components/copilot/flow.ts index 09341b6d21..c81d9dcd0f 100644 --- a/frontend/src/lib/components/copilot/flow.ts +++ b/frontend/src/lib/components/copilot/flow.ts @@ -12,6 +12,4 @@ export type FlowCopilotContext = { exprsToSet: Writable<{ [key: string]: InputTransform | undefined }> - toggleAiPanel?: () => void - addSelectedLinesToAiChat?: (lines: string, startLine: number, endLine: number) => void } diff --git a/frontend/src/lib/components/flows/FlowEditor.svelte b/frontend/src/lib/components/flows/FlowEditor.svelte index 4814d5f225..acd5dd7c1b 100644 --- a/frontend/src/lib/components/flows/FlowEditor.svelte +++ b/frontend/src/lib/components/flows/FlowEditor.svelte @@ -39,14 +39,6 @@ pickablePropertiesFiltered: writable(undefined) }) - export function addSelectedLinesToAiChat(lines: string, startLine: number, endLine: number) { - aiChatManager.addSelectedLinesToContext(lines, startLine, endLine) - if (!aiChatManager.open) { - aiChatManager.openChat() - aiChatManager.changeMode('script') - } - } - onMount(() => { aiChatManager.changeMode('flow') }) diff --git a/frontend/src/lib/components/flows/content/FlowModuleComponent.svelte b/frontend/src/lib/components/flows/content/FlowModuleComponent.svelte index 048c09fc1e..0cbf4ebb2d 100644 --- a/frontend/src/lib/components/flows/content/FlowModuleComponent.svelte +++ b/frontend/src/lib/components/flows/content/FlowModuleComponent.svelte @@ -51,7 +51,7 @@ import { workspaceStore } from '$lib/stores' import { checkIfParentLoop } from '../utils' import ModulePreviewResultViewer from '$lib/components/ModulePreviewResultViewer.svelte' - import type { FlowCopilotContext } from '$lib/components/copilot/flow' + import { aiChatManager } from '$lib/components/copilot/chat/AIChatManager.svelte' const { selectedId, @@ -66,9 +66,6 @@ executionCount } = getContext('FlowEditorContext') - const { toggleAiPanel, addSelectedLinesToAiChat } = - getContext('FlowCopilotContext') ?? {} - export let flowModule: FlowModule export let failureModule: boolean = false export let preprocessorModule: boolean = false @@ -392,10 +389,10 @@ { const { lines, startLine, endLine } = e.detail - addSelectedLinesToAiChat?.(lines, startLine, endLine) + aiChatManager.addSelectedLinesToContext(lines, startLine, endLine) }} on:toggleAiPanel={() => { - toggleAiPanel?.() + aiChatManager.toggleOpen() }} loadAsync folding diff --git a/frontend/src/lib/components/scriptEditor/LogPanel.svelte b/frontend/src/lib/components/scriptEditor/LogPanel.svelte index 47f0e96c0f..75f5055953 100644 --- a/frontend/src/lib/components/scriptEditor/LogPanel.svelte +++ b/frontend/src/lib/components/scriptEditor/LogPanel.svelte @@ -29,6 +29,7 @@ import WorkflowTimeline from '../WorkflowTimeline.svelte' import Tooltip from '$lib/components/Tooltip.svelte' import type { PreviewPanelUi } from '../custom_ui' + import { getStringError } from '../copilot/chat/utils' export let lang: Preview['language'] | undefined export let previewIsLoading = false @@ -40,7 +41,6 @@ export let workspace: string | undefined = undefined export let showCaptures: boolean = false export let customUi: PreviewPanelUi | undefined = undefined - export let fixChatMode: boolean = false type DrawerContent = { mode: 'json' | Preview['language'] | 'plain' @@ -141,16 +141,8 @@ language={lang} > - {#if lang && editor && diffEditor && args && previewJob?.result && typeof previewJob?.result == 'object' && `error` in previewJob?.result && previewJob?.result.error} - + {#if lang && editor && diffEditor && args && previewJob && !previewJob.success && getStringError(previewJob.result)} + {/if}
Explanation: test {$generatedExplanation}
Enable Windmill AI in the workspace settings