From b47c15165f93ca68a58f81cf2b86fc9467155482 Mon Sep 17 00:00:00 2001 From: centdix <40307056+centdix@users.noreply.github.com> Date: Fri, 4 Apr 2025 20:33:57 +0200 Subject: [PATCH] feat: add windmill context to autocomplete (#5548) * add windmill context to autocomplete * fix formatting * remove console log * do not mention tool call for autocomplete * apply logic to php --------- Co-authored-by: HugoCasa --- frontend/src/lib/components/Editor.svelte | 6 ++++- .../copilot/autocomplete/monaco-adapter.ts | 11 ++++++-- .../copilot/autocomplete/request.ts | 12 ++++++++- .../src/lib/components/copilot/chat/core.ts | 27 ++++++++++++------- 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/frontend/src/lib/components/Editor.svelte b/frontend/src/lib/components/Editor.svelte index d7be9ec884..c03666b2fe 100644 --- a/frontend/src/lib/components/Editor.svelte +++ b/frontend/src/lib/components/Editor.svelte @@ -635,7 +635,10 @@ if (completorDisposable) { completorDisposable.dispose() } - autocompletor = new Autocompletor(editor, lang) + if (!scriptLang) { + throw new Error('No script lang') + } + autocompletor = new Autocompletor(editor, lang, scriptLang) // last user events (currently disabled): // let lastTs = Date.now() @@ -690,6 +693,7 @@ $codeCompletionSessionEnabled && initialized && editor && + scriptLang && addSuperCompletor(editor) $: $copilotInfo.enabled && initialized && editor && addChatHandler(editor) diff --git a/frontend/src/lib/components/copilot/autocomplete/monaco-adapter.ts b/frontend/src/lib/components/copilot/autocomplete/monaco-adapter.ts index 9c108cc655..8d421b450f 100644 --- a/frontend/src/lib/components/copilot/autocomplete/monaco-adapter.ts +++ b/frontend/src/lib/components/copilot/autocomplete/monaco-adapter.ts @@ -3,6 +3,7 @@ import { type editor as meditor } from 'monaco-editor' import { autocompleteRequest } from './request' import { sleep } from '$lib/utils' import { displayVisualChanges, getLines, setGlobalCSS, type VisualChange } from '../shared' +import type { ScriptLang } from '$lib/gen' function lineChangesToVisualChanges(changes: Change[], startLineNumber: number) { let originalLineNumber = startLineNumber @@ -153,7 +154,7 @@ const MAX_PATCHES = 4 export class Autocompletor { editor: meditor.IStandaloneCodeEditor language: string - + scriptLang: ScriptLang | 'bunnative' viewZoneIds: string[] = [] decorationsCollection: meditor.IEditorDecorationsCollection | undefined = undefined visualChanges: VisualChange[] = [] @@ -188,9 +189,14 @@ export class Autocompletor { | undefined = undefined tabWidget: meditor.IContentWidget | undefined = undefined - constructor(editor: meditor.IStandaloneCodeEditor, language: string) { + constructor( + editor: meditor.IStandaloneCodeEditor, + language: string, + scriptLang: ScriptLang | 'bunnative' + ) { this.editor = editor this.language = language + this.scriptLang = scriptLang this.lastCodeValue = editor.getModel()?.getValue() || '' } @@ -445,6 +451,7 @@ export class Autocompletor { modifiableSuffix, suffix, language: this.language, + scriptLang: this.scriptLang, events: this.patches }, this.abortController diff --git a/frontend/src/lib/components/copilot/autocomplete/request.ts b/frontend/src/lib/components/copilot/autocomplete/request.ts index 1c552e0ce6..b670f5ed06 100644 --- a/frontend/src/lib/components/copilot/autocomplete/request.ts +++ b/frontend/src/lib/components/copilot/autocomplete/request.ts @@ -2,6 +2,8 @@ import { codeCompletionLoading, copilotInfo } from '$lib/stores' import { get } from 'svelte/store' import { getNonStreamingCompletion } from '../lib' +import { getLangContext } from '../chat/core' +import { type ScriptLang } from '$lib/gen/types.gen' const AUTOCOMPLETE_SYSTEM_PROMPT = `You're a code assistant. Your task is to help the user write code by suggesting the next edit for the user. @@ -31,6 +33,9 @@ Follow the following criteria. - Never remove line breaks inside the section.` const AUTOCOMPLETE_USER_PROMPT = ` +WINDMILL LANGUAGE CONTEXT: +{lang_context} + {prefix} {modifiablePrefix}{modifiableSuffix} @@ -59,13 +64,18 @@ export async function autocompleteRequest( modifiableSuffix: string suffix: string language: string + scriptLang: ScriptLang | 'bunnative' events: string[] }, abortController: AbortController ) { codeCompletionLoading.set(true) const systemPrompt = AUTOCOMPLETE_SYSTEM_PROMPT - const userPrompt = AUTOCOMPLETE_USER_PROMPT.replace('{prefix}', context.prefix) + const userPrompt = AUTOCOMPLETE_USER_PROMPT.replace( + '{lang_context}', + getLangContext(context.scriptLang) + ) + .replace('{prefix}', context.prefix) .replace('{modifiablePrefix}', context.modifiablePrefix) .replace('{modifiableSuffix}', context.modifiableSuffix) .replace('{suffix}', context.suffix) diff --git a/frontend/src/lib/components/copilot/chat/core.ts b/frontend/src/lib/components/copilot/chat/core.ts index d315b7c65d..ed5c968b88 100644 --- a/frontend/src/lib/components/copilot/chat/core.ts +++ b/frontend/src/lib/components/copilot/chat/core.ts @@ -58,12 +58,10 @@ async function getResourceTypes(prompt: string, workspace: string) { const TS_RESOURCE_TYPE_SYSTEM = `On Windmill, credentials and configuration are stored in resources and passed as parameters to main. If you need credentials, you should add a parameter to \`main\` with the corresponding resource type inside the \`RT\` namespace: for instance \`RT.Stripe\`. -You should only them if you need them to satisfy the user's instructions. Always use the RT namespace. -To query the RT namespace, you can use the \`search_resource_types\` function.` +You should only use them if you need them to satisfy the user's instructions. Always use the RT namespace.` const PYTHON_RESOURCE_TYPE_SYSTEM = `On Windmill, credentials and configuration are stored in resources and passed as parameters to main. If you need credentials, you should add a parameter to \`main\` with the corresponding resource type. -To query the available resource types, you can use the \`search_resource_types\` function. 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. The resource type name has to be exactly as specified (has to be IN LOWERCASE). If an import conflicts with a resource type name, **you have to rename the imported object, not the type name**. @@ -71,7 +69,6 @@ Make sure to import TypedDict from typing **if you're using it**` const PHP_RESOURCE_TYPE_SYSTEM = `On Windmill, credentials and configuration are stored in resources and passed as parameters to main. If you need credentials, you should add a parameter to \`main\` with the corresponding resource type -The available resource types are provided by the user under the \`RESOURCE_TYPE_CONTEXT\` key. You need to **redefine** the type of the resources that are needed before the main function, but only include them if they are actually needed to achieve the function purpose. Before defining each type, check if the class already exists using class_exists. The resource type name has to be exactly as specified.` @@ -95,34 +92,44 @@ export const SUPPORTED_CHAT_SCRIPT_LANGUAGES = [ 'powershell' ] -function getLangContext(lang: ScriptLang | 'bunnative') { +export function getLangContext( + lang: ScriptLang | 'bunnative', + { allowResourcesFetch = false }: { allowResourcesFetch?: boolean } = {} +) { + const tsContext = + TS_RESOURCE_TYPE_SYSTEM + + (allowResourcesFetch + ? `\nTo query the RT namespace, you can use the \`search_resource_types\` function.` + : '') switch (lang) { case 'bunnative': case 'nativets': return ( 'The user is coding in TypeScript. On Windmill, it is expected that the script exports a single **async** function called `main`. You should use fetch (available globally, no need to import) and are not allowed to import any libraries.\n' + - TS_RESOURCE_TYPE_SYSTEM + tsContext ) case 'bun': return ( 'The user is coding in TypeScript (bun runtime). On Windmill, it is expected that the script exports a single **async** function called `main`. Do not call the main function. Libraries are installed automatically, do not show how to install them.\n' + - TS_RESOURCE_TYPE_SYSTEM + tsContext ) case 'deno': return ( 'The user is coding in TypeScript (deno runtime). On Windmill, it is expected that the script exports a single **async** function called `main`. Do not call the main function. Libraries are installed automatically, do not show how to install them.\n' + - TS_RESOURCE_TYPE_SYSTEM + + tsContext + '\nYou can import deno libraries or you can import npm libraries like that: `import ... from "npm:{package}";`.' ) case 'python3': return ( 'The user is coding in Python. On Windmill, it is expected the script contains at least one function called `main`. Do not call the main function. Libraries are installed automatically, do not show how to install them.' + - PYTHON_RESOURCE_TYPE_SYSTEM + PYTHON_RESOURCE_TYPE_SYSTEM + + `${allowResourcesFetch ? `\nTo query the available resource types, you can use the \`search_resource_types\` function.` : ''}` ) case 'php': return ( 'The user is coding in PHP. On Windmill, it is expected the script contains at least one function called `main`. The script must start with