diff --git a/backend/.sqlx/query-d7d368f9ef2587c6abd3daaec93401615a53e3d7d949b65ebf01ef8760ba46b8.json b/backend/.sqlx/query-034583442e6f8ae38d6c4e4aac26f17c8d9d0e657f28276228fc90d3e22e1304.json similarity index 60% rename from backend/.sqlx/query-d7d368f9ef2587c6abd3daaec93401615a53e3d7d949b65ebf01ef8760ba46b8.json rename to backend/.sqlx/query-034583442e6f8ae38d6c4e4aac26f17c8d9d0e657f28276228fc90d3e22e1304.json index 18e4388d6e..e17ea413db 100644 --- a/backend/.sqlx/query-d7d368f9ef2587c6abd3daaec93401615a53e3d7d949b65ebf01ef8760ba46b8.json +++ b/backend/.sqlx/query-034583442e6f8ae38d6c4e4aac26f17c8d9d0e657f28276228fc90d3e22e1304.json @@ -1,15 +1,16 @@ { "db_name": "PostgreSQL", - "query": "UPDATE workspace_settings SET openai_resource_path = $1 WHERE workspace_id = $2", + "query": "UPDATE workspace_settings SET openai_resource_path = $1, code_completion_enabled = $2 WHERE workspace_id = $3", "describe": { "columns": [], "parameters": { "Left": [ "Varchar", + "Bool", "Text" ] }, "nullable": [] }, - "hash": "d7d368f9ef2587c6abd3daaec93401615a53e3d7d949b65ebf01ef8760ba46b8" + "hash": "034583442e6f8ae38d6c4e4aac26f17c8d9d0e657f28276228fc90d3e22e1304" } diff --git a/backend/.sqlx/query-123c0608e229c29187009b7961355ddd99c4ad1f46b876dd86e372b84d806ecd.json b/backend/.sqlx/query-123c0608e229c29187009b7961355ddd99c4ad1f46b876dd86e372b84d806ecd.json index 1b8084742c..7718e05ccf 100644 --- a/backend/.sqlx/query-123c0608e229c29187009b7961355ddd99c4ad1f46b876dd86e372b84d806ecd.json +++ b/backend/.sqlx/query-123c0608e229c29187009b7961355ddd99c4ad1f46b876dd86e372b84d806ecd.json @@ -37,7 +37,6 @@ "bash", "postgresql", "nativets", - "Nativets", "bun", "mysql", "bigquery", diff --git a/backend/.sqlx/query-1730f39fd1793d45fbb41b21389c61296a3ff7489ae12f52a19f9543173ac597.json b/backend/.sqlx/query-1730f39fd1793d45fbb41b21389c61296a3ff7489ae12f52a19f9543173ac597.json index 9c390a5889..5c4e95ddc6 100644 --- a/backend/.sqlx/query-1730f39fd1793d45fbb41b21389c61296a3ff7489ae12f52a19f9543173ac597.json +++ b/backend/.sqlx/query-1730f39fd1793d45fbb41b21389c61296a3ff7489ae12f52a19f9543173ac597.json @@ -67,6 +67,11 @@ "ordinal": 12, "name": "openai_resource_path", "type_info": "Varchar" + }, + { + "ordinal": 13, + "name": "code_completion_enabled", + "type_info": "Bool" } ], "parameters": { @@ -87,7 +92,8 @@ true, true, true, - true + true, + false ] }, "hash": "1730f39fd1793d45fbb41b21389c61296a3ff7489ae12f52a19f9543173ac597" diff --git a/backend/.sqlx/query-25bef6a248f3ee0ea2cbcc376c217cbcf1013ae311c36b42d423bf6a02fa016c.json b/backend/.sqlx/query-25bef6a248f3ee0ea2cbcc376c217cbcf1013ae311c36b42d423bf6a02fa016c.json index bf591ef11c..9d082a6772 100644 --- a/backend/.sqlx/query-25bef6a248f3ee0ea2cbcc376c217cbcf1013ae311c36b42d423bf6a02fa016c.json +++ b/backend/.sqlx/query-25bef6a248f3ee0ea2cbcc376c217cbcf1013ae311c36b42d423bf6a02fa016c.json @@ -67,7 +67,6 @@ "bash", "postgresql", "nativets", - "Nativets", "bun", "mysql", "bigquery", diff --git a/backend/.sqlx/query-438b5b5d29b05846c2e074cad2404e797527841cd97dba80c271cbefafae65cc.json b/backend/.sqlx/query-438b5b5d29b05846c2e074cad2404e797527841cd97dba80c271cbefafae65cc.json index a5dee163e5..1166260449 100644 --- a/backend/.sqlx/query-438b5b5d29b05846c2e074cad2404e797527841cd97dba80c271cbefafae65cc.json +++ b/backend/.sqlx/query-438b5b5d29b05846c2e074cad2404e797527841cd97dba80c271cbefafae65cc.json @@ -28,7 +28,6 @@ "bash", "postgresql", "nativets", - "Nativets", "bun", "mysql", "bigquery", diff --git a/backend/.sqlx/query-5445083864b2b092b012e894bff7630a1d7b9deb8d33e9f909061f351f96844e.json b/backend/.sqlx/query-5445083864b2b092b012e894bff7630a1d7b9deb8d33e9f909061f351f96844e.json index 2f7d4ad946..d8e4729e06 100644 --- a/backend/.sqlx/query-5445083864b2b092b012e894bff7630a1d7b9deb8d33e9f909061f351f96844e.json +++ b/backend/.sqlx/query-5445083864b2b092b012e894bff7630a1d7b9deb8d33e9f909061f351f96844e.json @@ -67,6 +67,11 @@ "ordinal": 12, "name": "openai_resource_path", "type_info": "Varchar" + }, + { + "ordinal": 13, + "name": "code_completion_enabled", + "type_info": "Bool" } ], "parameters": { @@ -87,7 +92,8 @@ true, true, true, - true + true, + false ] }, "hash": "5445083864b2b092b012e894bff7630a1d7b9deb8d33e9f909061f351f96844e" diff --git a/backend/.sqlx/query-5cd89ab614d3cac80fb81627267ee85b191263989b0c78b2bfce77e796e96825.json b/backend/.sqlx/query-5cd89ab614d3cac80fb81627267ee85b191263989b0c78b2bfce77e796e96825.json index 1517c8d1d4..eabf671894 100644 --- a/backend/.sqlx/query-5cd89ab614d3cac80fb81627267ee85b191263989b0c78b2bfce77e796e96825.json +++ b/backend/.sqlx/query-5cd89ab614d3cac80fb81627267ee85b191263989b0c78b2bfce77e796e96825.json @@ -42,7 +42,6 @@ "bash", "postgresql", "nativets", - "Nativets", "bun", "mysql", "bigquery", diff --git a/backend/.sqlx/query-28eef409e9f25e4c037dd716d6515e96e8962acb59d5e64f9cc3227e0f5fd058.json b/backend/.sqlx/query-6268eabd561502a44e273d6391102278974623f7a7bcad6891d7abadf4d3ea03.json similarity index 58% rename from backend/.sqlx/query-28eef409e9f25e4c037dd716d6515e96e8962acb59d5e64f9cc3227e0f5fd058.json rename to backend/.sqlx/query-6268eabd561502a44e273d6391102278974623f7a7bcad6891d7abadf4d3ea03.json index 5be92aa3c6..fe7c2cf5c3 100644 --- a/backend/.sqlx/query-28eef409e9f25e4c037dd716d6515e96e8962acb59d5e64f9cc3227e0f5fd058.json +++ b/backend/.sqlx/query-6268eabd561502a44e273d6391102278974623f7a7bcad6891d7abadf4d3ea03.json @@ -1,14 +1,15 @@ { "db_name": "PostgreSQL", - "query": "UPDATE workspace_settings SET openai_resource_path = NULL WHERE workspace_id = $1", + "query": "UPDATE workspace_settings SET openai_resource_path = NULL, code_completion_enabled = $1 WHERE workspace_id = $2", "describe": { "columns": [], "parameters": { "Left": [ + "Bool", "Text" ] }, "nullable": [] }, - "hash": "28eef409e9f25e4c037dd716d6515e96e8962acb59d5e64f9cc3227e0f5fd058" + "hash": "6268eabd561502a44e273d6391102278974623f7a7bcad6891d7abadf4d3ea03" } diff --git a/backend/.sqlx/query-65835f2e5ad38f7cc6b147dadfef6f580f15bca96d9746c9359e98ca793f8f1f.json b/backend/.sqlx/query-65835f2e5ad38f7cc6b147dadfef6f580f15bca96d9746c9359e98ca793f8f1f.json index bfe7c41f64..c52efca4c0 100644 --- a/backend/.sqlx/query-65835f2e5ad38f7cc6b147dadfef6f580f15bca96d9746c9359e98ca793f8f1f.json +++ b/backend/.sqlx/query-65835f2e5ad38f7cc6b147dadfef6f580f15bca96d9746c9359e98ca793f8f1f.json @@ -42,7 +42,6 @@ "bash", "postgresql", "nativets", - "Nativets", "bun", "mysql", "bigquery", diff --git a/backend/.sqlx/query-6b9ff3fbca9e825c95d14705082a10de88172c0c748a45aba4d2d03c3b58f54d.json b/backend/.sqlx/query-6b9ff3fbca9e825c95d14705082a10de88172c0c748a45aba4d2d03c3b58f54d.json index dabac76bfe..73e6e17c76 100644 --- a/backend/.sqlx/query-6b9ff3fbca9e825c95d14705082a10de88172c0c748a45aba4d2d03c3b58f54d.json +++ b/backend/.sqlx/query-6b9ff3fbca9e825c95d14705082a10de88172c0c748a45aba4d2d03c3b58f54d.json @@ -46,7 +46,6 @@ "bash", "postgresql", "nativets", - "Nativets", "bun", "mysql", "bigquery", diff --git a/backend/.sqlx/query-9e8c3ff3d6b31e366e15beda1e96e03e870ccc3b353401439bc0ed8ff219249b.json b/backend/.sqlx/query-9e8c3ff3d6b31e366e15beda1e96e03e870ccc3b353401439bc0ed8ff219249b.json index 6308bf3bb2..fead4ba250 100644 --- a/backend/.sqlx/query-9e8c3ff3d6b31e366e15beda1e96e03e870ccc3b353401439bc0ed8ff219249b.json +++ b/backend/.sqlx/query-9e8c3ff3d6b31e366e15beda1e96e03e870ccc3b353401439bc0ed8ff219249b.json @@ -60,7 +60,6 @@ "bash", "postgresql", "nativets", - "Nativets", "bun", "mysql", "bigquery", diff --git a/backend/.sqlx/query-b224cdd1221fc9e7227ef8e8c025eedc09bceb82bca349f3e31c8513ebbf0192.json b/backend/.sqlx/query-b224cdd1221fc9e7227ef8e8c025eedc09bceb82bca349f3e31c8513ebbf0192.json index 38f81da395..c90719118a 100644 --- a/backend/.sqlx/query-b224cdd1221fc9e7227ef8e8c025eedc09bceb82bca349f3e31c8513ebbf0192.json +++ b/backend/.sqlx/query-b224cdd1221fc9e7227ef8e8c025eedc09bceb82bca349f3e31c8513ebbf0192.json @@ -42,7 +42,6 @@ "bash", "postgresql", "nativets", - "Nativets", "bun", "mysql", "bigquery", diff --git a/backend/.sqlx/query-ceb97024ebf1a1c00ea1ed4952f66b229ca4622c537cc252d8ed52b4d24270ee.json b/backend/.sqlx/query-ceb97024ebf1a1c00ea1ed4952f66b229ca4622c537cc252d8ed52b4d24270ee.json new file mode 100644 index 0000000000..30b5230f96 --- /dev/null +++ b/backend/.sqlx/query-ceb97024ebf1a1c00ea1ed4952f66b229ca4622c537cc252d8ed52b4d24270ee.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT openai_resource_path, code_completion_enabled FROM workspace_settings WHERE workspace_id = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "openai_resource_path", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "code_completion_enabled", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + true, + false + ] + }, + "hash": "ceb97024ebf1a1c00ea1ed4952f66b229ca4622c537cc252d8ed52b4d24270ee" +} diff --git a/backend/migrations/20230929092213_copilot_code_completion.down.sql b/backend/migrations/20230929092213_copilot_code_completion.down.sql new file mode 100644 index 0000000000..b81f7a766c --- /dev/null +++ b/backend/migrations/20230929092213_copilot_code_completion.down.sql @@ -0,0 +1,2 @@ +-- Add down migration script here +ALTER TABLE workspace_settings DROP COLUMN code_completion_enabled; \ No newline at end of file diff --git a/backend/migrations/20230929092213_copilot_code_completion.up.sql b/backend/migrations/20230929092213_copilot_code_completion.up.sql new file mode 100644 index 0000000000..45941016b8 --- /dev/null +++ b/backend/migrations/20230929092213_copilot_code_completion.up.sql @@ -0,0 +1,2 @@ +-- Add up migration script here +ALTER TABLE workspace_settings ADD COLUMN code_completion_enabled BOOLEAN NOT NULL DEFAULT false; \ No newline at end of file diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index dd340ceb89..ef00ce42f0 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -1155,8 +1155,12 @@ paths: type: string openai_resource_path: type: string + code_completion_enabled: + type: boolean error_handler: type: string + required: + - code_completion_enabled /w/{workspace}/workspaces/get_deploy_to: get: @@ -1309,24 +1313,28 @@ paths: schema: type: string - /w/{workspace}/workspaces/edit_openai_resource_path: + /w/{workspace}/workspaces/edit_copilot_config: post: - summary: edit OpenAI resource path - operationId: editOpenaiResourcePath + summary: edit copilot config + operationId: editCopilotConfig tags: - workspace parameters: - $ref: "#/components/parameters/WorkspaceId" requestBody: - description: WorkspaceOpenaiResourcePath + description: WorkspaceCopilotConfig required: true content: application/json: schema: type: object + required: + - code_completion_enabled properties: openai_resource_path: type: string + code_completion_enabled: + type: boolean responses: "200": description: status @@ -1335,10 +1343,10 @@ paths: schema: type: string - /w/{workspace}/workspaces/exists_openai_resource_path: + /w/{workspace}/workspaces/get_copilot_info: get: - summary: OpenAI resource path exists - operationId: existsOpenaiResourcePath + summary: get copilot info + operationId: getCopilotInfo tags: - workspace parameters: @@ -1350,7 +1358,15 @@ paths: content: text/plain: schema: - type: boolean + type: object + properties: + exists_openai_resource_path: + type: boolean + code_completion_enabled: + type: boolean + required: + - exists_openai_resource_path + - code_completion_enabled /w/{workspace}/workspaces/edit_error_handler: post: @@ -6883,7 +6899,7 @@ components: - "workspaces.edit_deploy_to" - "workspaces.edit_auto_invite_domain" - "workspaces.edit_webhook" - - "workspaces.edit_openai_resource_path" + - "workspaces.edit_copilot_config" - "workspaces.edit_error_handler" - "workspaces.create" - "workspaces.update" diff --git a/backend/windmill-api/src/workspaces.rs b/backend/windmill-api/src/workspaces.rs index 5aeda3a456..7fa5a681d8 100644 --- a/backend/windmill-api/src/workspaces.rs +++ b/backend/windmill-api/src/workspaces.rs @@ -69,8 +69,8 @@ pub fn workspaced_service() -> Router { .route("/edit_deploy_to", post(edit_deploy_to)) .route("/tarball", get(tarball_workspace)) .route("/premium_info", get(premium_info)) - .route("/edit_openai_resource_path", post(edit_openai_resource_path)) - .route("/exists_openai_resource_path", get(exists_openai_resource_path) ) + .route("/edit_copilot_config", post(edit_copilot_config)) + .route("/get_copilot_info", get(get_copilot_info) ) .route("/edit_error_handler", post(edit_error_handler)); #[cfg(feature = "enterprise")] @@ -125,6 +125,7 @@ pub struct WorkspaceSettings { pub webhook: Option, pub deploy_to: Option, pub openai_resource_path: Option, + pub code_completion_enabled: bool, pub error_handler: Option, } @@ -166,8 +167,9 @@ struct EditWebhook { } #[derive(Deserialize)] -struct EditOpenaiResourcePath { +struct EditCopilotConfig { openai_resource_path: Option, + code_completion_enabled: bool, } #[derive(Deserialize)] @@ -670,12 +672,12 @@ async fn edit_webhook( Ok(format!("Edit webhook for workspace {}", &w_id)) } -async fn edit_openai_resource_path( +async fn edit_copilot_config( authed: ApiAuthed, Extension(db): Extension, Path(w_id): Path, ApiAuthed { is_admin, username, .. }: ApiAuthed, - Json(eo): Json, + Json(eo): Json, ) -> Result { require_admin(is_admin, &username)?; @@ -683,15 +685,17 @@ async fn edit_openai_resource_path( if let Some(openai_resource_path) = &eo.openai_resource_path { sqlx::query!( - "UPDATE workspace_settings SET openai_resource_path = $1 WHERE workspace_id = $2", + "UPDATE workspace_settings SET openai_resource_path = $1, code_completion_enabled = $2 WHERE workspace_id = $3", openai_resource_path, + eo.code_completion_enabled, &w_id ) .execute(&mut *tx) .await?; } else { sqlx::query!( - "UPDATE workspace_settings SET openai_resource_path = NULL WHERE workspace_id = $1", + "UPDATE workspace_settings SET openai_resource_path = NULL, code_completion_enabled = $1 WHERE workspace_id = $2", + eo.code_completion_enabled, &w_id, ) .execute(&mut *tx) @@ -700,37 +704,43 @@ async fn edit_openai_resource_path( audit_log( &mut *tx, &authed.username, - "workspaces.edit_openai_resource_path", + "workspaces.edit_copilot_config", ActionKind::Update, &w_id, Some(&authed.email), - Some([("openai_resource_path", &format!("{:?}", eo.openai_resource_path)[..])].into()), + Some([("openai_resource_path", &format!("{:?}", eo.openai_resource_path)[..]), ("code_completion_enabled", &format!("{:?}", eo.code_completion_enabled)[..])].into()), ) .await?; tx.commit().await?; - Ok(format!("Edit openai_resource_path for workspace {}", &w_id)) + Ok(format!("Edit copilot config for workspace {}", &w_id)) } - -async fn exists_openai_resource_path( +#[derive(Serialize)] +struct CopilotInfo { + pub exists_openai_resource_path: bool, + pub code_completion_enabled: bool, +} +async fn get_copilot_info( Extension(db): Extension, Path(w_id): Path, -) -> JsonResult { +) -> JsonResult { let mut tx = db.begin().await?; - let openai_resource_path = sqlx::query_scalar!( - "SELECT openai_resource_path FROM workspace_settings WHERE workspace_id = $1", + let record = sqlx::query!( + "SELECT openai_resource_path, code_completion_enabled FROM workspace_settings WHERE workspace_id = $1", &w_id ) .fetch_one(&mut *tx) .await - .map_err(|e| Error::InternalErr(format!("getting openai_resource_path: {e}")))?; + .map_err(|e| Error::InternalErr(format!("getting openai_resource_path and code_completion_enabled: {e}")))?; tx.commit().await?; - let exists = openai_resource_path.is_some(); - Ok(Json(exists)) + Ok(Json(CopilotInfo { + exists_openai_resource_path: record.openai_resource_path.is_some(), + code_completion_enabled: record.code_completion_enabled, + })) } diff --git a/frontend/src/lib/components/Editor.svelte b/frontend/src/lib/components/Editor.svelte index fac81b88f9..e4c11e1f2a 100644 --- a/frontend/src/lib/components/Editor.svelte +++ b/frontend/src/lib/components/Editor.svelte @@ -30,7 +30,7 @@ import { toSocket, WebSocketMessageReader, WebSocketMessageWriter } from 'vscode-ws-jsonrpc' import { CloseAction, ErrorAction, RequestType, NotificationType } from 'vscode-languageclient' import { MonacoBinding } from 'y-monaco' - import { dbSchemas, type DBSchema } from '$lib/stores' + import { dbSchemas, type DBSchema, copilotInfo } from '$lib/stores' import { createHash as randomHash, @@ -47,6 +47,8 @@ import type { Text } from 'yjs' import { initializeMode } from 'monaco-graphql/esm/initializeMode' import type { MonacoGraphQLAPI } from 'monaco-graphql/esm/api' + import { sleep } from '$lib/utils' + import { editorCodeCompletion } from './copilot/completion' let divEl: HTMLDivElement | null = null let editor: meditor.IStandaloneCodeEditor @@ -354,6 +356,78 @@ } } + let copilotCompletor: Disposable | undefined = undefined + let copilotTs = Date.now() + let abortController: AbortController | undefined = undefined + function addCopilotSuggestions() { + if (copilotCompletor) { + copilotCompletor.dispose() + } + copilotCompletor = languages.registerInlineCompletionsProvider( + { pattern: '**' }, + { + freeInlineCompletions(completions) {}, + async provideInlineCompletions(model, position, context, token) { + abortController?.abort() + const textUntilPosition = model.getValueInRange({ + startLineNumber: 1, + startColumn: 1, + endLineNumber: position.lineNumber, + endColumn: position.column + }) + + let items: languages.InlineCompletions['items'] = [] + + const lastChar = textUntilPosition[textUntilPosition.length - 1] + if (textUntilPosition.trim().length > 5 && lastChar.match(/[\(\{\s:=]/)) { + const textAfterPosition = model.getValueInRange({ + startLineNumber: position.lineNumber, + startColumn: position.column, + endLineNumber: model.getLineCount() + 1, + endColumn: 1 + }) + const thisTs = Date.now() + copilotTs = thisTs + await sleep(500) + if (copilotTs === thisTs) { + abortController?.abort() + abortController = new AbortController() + const insertText = await editorCodeCompletion( + textUntilPosition, + textAfterPosition, + lang, + abortController + ) + if (insertText) { + items = [ + { + insertText, + range: { + startLineNumber: position.lineNumber, + startColumn: position.column, + endLineNumber: position.lineNumber, + endColumn: position.column + }, + completeBracketPairs: false + } + ] + } + } + } + + return { + items, + commands: [] + } + } + } + ) + } + + $: $copilotInfo.exists_openai_resource_path && + $copilotInfo.code_completion_enabled && + addCopilotSuggestions() + const outputChannel = { name: 'Language Server Client', appendLine: (msg: string) => { @@ -922,6 +996,7 @@ disposeMethod && disposeMethod() websocketInterval && clearInterval(websocketInterval) sqlSchemaCompletor && sqlSchemaCompletor.dispose() + copilotCompletor && copilotCompletor.dispose() }) diff --git a/frontend/src/lib/components/FlowBuilder.svelte b/frontend/src/lib/components/FlowBuilder.svelte index 8387e59f3a..49105258f1 100644 --- a/frontend/src/lib/components/FlowBuilder.svelte +++ b/frontend/src/lib/components/FlowBuilder.svelte @@ -11,8 +11,8 @@ } from '$lib/gen' import { initHistory, push, redo, undo } from '$lib/history' import { + copilotInfo, enterpriseLicense, - existsOpenaiResourcePath, hubScripts, userStore, workspaceStore @@ -638,7 +638,11 @@ try { if (flowModule.value.type === 'rawscript') { const stepSchema: Schema = JSON.parse(JSON.stringify($flowStateStore[module.id].schema)) // deep copy - if (module.source === 'hub' && pastModule !== undefined && $existsOpenaiResourcePath) { + if ( + module.source === 'hub' && + pastModule !== undefined && + $copilotInfo.exists_openai_resource_path + ) { // ask AI to set step inputs abortController = new AbortController() const inputs = await glueCopilot( @@ -677,7 +681,11 @@ } }) } else { - if (module.source === 'hub' && pastModule !== undefined && !$existsOpenaiResourcePath) { + if ( + module.source === 'hub' && + pastModule !== undefined && + !$copilotInfo.exists_openai_resource_path + ) { sendUserToast( 'For better input generation, enable Windmill AI in the workspace settings', true diff --git a/frontend/src/lib/components/auditLogs/AuditLogsFilters.svelte b/frontend/src/lib/components/auditLogs/AuditLogsFilters.svelte index 4bdc44f3e6..dcc0ee1000 100644 --- a/frontend/src/lib/components/auditLogs/AuditLogsFilters.svelte +++ b/frontend/src/lib/components/auditLogs/AuditLogsFilters.svelte @@ -244,7 +244,7 @@ WORKSPACES_EDIT_DEPLOY_TO: 'workspaces.edit_deploy_to', WORKSPACES_EDIT_AUTO_INVITE_DOMAIN: 'workspaces.edit_auto_invite_domain', WORKSPACES_EDIT_WEBHOOK: 'workspaces.edit_webhook', - WORKSPACES_EDIT_OPENAI_RESOURCE_PATH: 'workspaces.edit_openai_resource_path', + WORKSPACES_EDIT_COPILOT_CONFIG: 'workspaces.edit_copilot_config', WORKSPACES_EDIT_ERROR_HANDLER: 'workspaces.edit_error_handler', WORKSPACES_CREATE: 'workspaces.create', WORKSPACES_UPDATE: 'workspaces.update', diff --git a/frontend/src/lib/components/copilot/FlowCopilotStatus.svelte b/frontend/src/lib/components/copilot/FlowCopilotStatus.svelte index ddff5df322..3845bc47dd 100644 --- a/frontend/src/lib/components/copilot/FlowCopilotStatus.svelte +++ b/frontend/src/lib/components/copilot/FlowCopilotStatus.svelte @@ -6,7 +6,7 @@ import type { FlowCopilotContext } from './flow' import { faMagicWandSparkles } from '@fortawesome/free-solid-svg-icons' import { charsToNumber } from '../flows/idUtils' - import { existsOpenaiResourcePath } from '$lib/stores' + import { copilotInfo } from '$lib/stores' import Popup from '../common/popup/Popup.svelte' import type { FlowModule } from '$lib/gen' import type { FlowEditorContext } from '../flows/types' @@ -30,7 +30,7 @@ $: copilotStatus && copilotPopover?.refresh() -{#if $existsOpenaiResourcePath} +{#if $copilotInfo.exists_openai_resource_path} - {#if !$existsOpenaiResourcePath} + {#if !$copilotInfo.exists_openai_resource_path}

Enable Windmill AI in the | undefined >(undefined) -export const existsOpenaiResourcePath = writable(false) +export const copilotInfo = writable<{ + exists_openai_resource_path: boolean + code_completion_enabled: boolean +}>({ + exists_openai_resource_path: false, + code_completion_enabled: false +}) type SQLBaseSchema = { [schemaKey: string]: { diff --git a/frontend/src/routes/(root)/(logged)/user/(user)/create_workspace/+page.svelte b/frontend/src/routes/(root)/(logged)/user/(user)/create_workspace/+page.svelte index ad21b05df5..7a67ffc462 100644 --- a/frontend/src/routes/(root)/(logged)/user/(user)/create_workspace/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/user/(user)/create_workspace/+page.svelte @@ -67,9 +67,9 @@ resource_type: 'openai' } }) - await WorkspaceService.editOpenaiResourcePath({ + await WorkspaceService.editCopilotConfig({ workspace: id, - requestBody: { openai_resource_path: path } + requestBody: { openai_resource_path: path, code_completion_enabled: false } }) } diff --git a/frontend/src/routes/(root)/(logged)/workspace_settings/+page.svelte b/frontend/src/routes/(root)/(logged)/workspace_settings/+page.svelte index 684528f07b..ae77285be0 100644 --- a/frontend/src/routes/(root)/(logged)/workspace_settings/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/workspace_settings/+page.svelte @@ -16,7 +16,7 @@ import { OauthService, Script, WorkspaceService } from '$lib/gen' import { enterpriseLicense, - existsOpenaiResourcePath, + copilotInfo, superadmin, userStore, usersWorkspaceStore, @@ -29,6 +29,7 @@ import { Slack } from 'lucide-svelte' import PremiumInfo from '$lib/components/settings/PremiumInfo.svelte' + import Toggle from '$lib/components/Toggle.svelte' let initialPath: string let scriptPath: string @@ -42,6 +43,7 @@ let errorHandlerScriptPath: string let errorHandlerItemKind: 'script' = 'script' let openaiResourceInitialPath: string | undefined = undefined + let codeCompletionEnabled: boolean = false let tab = ($page.url.searchParams.get('tab') as | 'users' @@ -111,24 +113,35 @@ } } - async function editOpenaiResourcePath(openaiResourcePath: string): Promise { + async function editCopilotConfig(openaiResourcePath: string): Promise { // in JS, an empty string is also falsy openaiResourceInitialPath = openaiResourcePath if (openaiResourcePath) { - await WorkspaceService.editOpenaiResourcePath({ + await WorkspaceService.editCopilotConfig({ workspace: $workspaceStore!, - requestBody: { openai_resource_path: openaiResourcePath } + requestBody: { + openai_resource_path: openaiResourcePath, + code_completion_enabled: codeCompletionEnabled + } + }) + copilotInfo.set({ + exists_openai_resource_path: true, + code_completion_enabled: codeCompletionEnabled }) - existsOpenaiResourcePath.set(true) - sendUserToast('OpenAI resource set') } else { - await WorkspaceService.editOpenaiResourcePath({ + await WorkspaceService.editCopilotConfig({ workspace: $workspaceStore!, - requestBody: { openai_resource_path: undefined } + requestBody: { + openai_resource_path: undefined, + code_completion_enabled: codeCompletionEnabled + } + }) + copilotInfo.set({ + exists_openai_resource_path: true, + code_completion_enabled: codeCompletionEnabled }) - existsOpenaiResourcePath.set(false) - sendUserToast(`OpenAI resource removed`) } + sendUserToast(`Copilot settings updated`) } async function loadSettings(): Promise { @@ -147,6 +160,7 @@ openaiResourceInitialPath = settings.openai_resource_path errorHandlerScriptPath = (settings.error_handler ?? '').split('/').slice(1).join('/') errorHandlerInitialPath = errorHandlerScriptPath + codeCompletionEnabled = settings.code_completion_enabled } $: { @@ -447,7 +461,8 @@

@@ -456,11 +471,21 @@ resourceType="openai" initialValue={openaiResourceInitialPath} on:change={(ev) => { - editOpenaiResourcePath(ev.detail) + editCopilotConfig(ev.detail) }} /> {/key}
+
+ { + editCopilotConfig(openaiResourceInitialPath || '') + }} + /> +
{/if} {:else}