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 <hugo@casademont.ch>
This commit is contained in:
centdix
2025-04-04 18:33:57 +00:00
committed by GitHub
co-authored by HugoCasa
parent 5bd66b3f1f
commit b47c15165f
4 changed files with 42 additions and 14 deletions
+5 -1
View File
@@ -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)
@@ -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
@@ -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 <EDITABLE_CODE> section.`
const AUTOCOMPLETE_USER_PROMPT = `
WINDMILL LANGUAGE CONTEXT:
{lang_context}
<CODE>
{prefix}<EDITABLE_CODE>
{modifiablePrefix}<CURSOR>{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)
@@ -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 <?php.' +
PHP_RESOURCE_TYPE_SYSTEM +
`${allowResourcesFetch ? `\nTo query the available resource types, you can use the \`search_resource_types\` function.` : ''}` +
`\nIf you need to import libraries, you need to specify them as comments in the following manner before the main function:
\`\`\`
// require:
@@ -366,7 +373,7 @@ export async function prepareUserMessage(
let userMessage = CHAT_USER_PROMPT.replace('{instructions}', instructions).replace(
'{lang_context}',
getLangContext(language)
getLangContext(language, { allowResourcesFetch: true })
)
if (hasCode) {
userMessage += codeContext