From a010cf4f9164ea276b9de172d33e48e65d146747 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A9ri=20Le=20Bouder?= Date: Tue, 6 Aug 2024 14:04:15 -0400 Subject: [PATCH] lightspeed: move playbook exp/gen away from the LSP server It's tricky to get the LSP to send the requests through a HTTP server and we don't want to deal with to different network configuration/stack. In addition, we would like to migrate away from Axios and use Electron's `fetch` which is already configured to use the VS Code proxy configuration. --- .../ansible-language-server/package-lock.json | 21 --- packages/ansible-language-server/package.json | 1 - .../src/ansibleLanguageService.ts | 97 ------------- .../src/interfaces/lightspeedApi.ts | 24 ---- src/definitions/lightspeed.ts | 2 + src/features/lightspeed/api.ts | 127 +++++++++++++++--- .../lightspeed/contentMatchesWebview.ts | 2 +- .../src => src/features/lightspeed}/errors.ts | 2 +- .../features/lightspeed}/handleApiError.ts | 4 +- .../lightspeed/playbookExplanation.ts | 43 +++--- src/features/lightspeed/playbookGeneration.ts | 36 ++--- src/features/lightspeed/utils/errors.ts | 15 ++- .../lightspeed/utils/oneClickTrial.ts | 2 +- src/interfaces/lightspeed.ts | 25 ++++ test/ui-test/lightspeedUiTest.ts | 2 +- test/units/lightspeed/contentmatches.test.ts | 2 +- .../lightspeed}/utils/handleApiError.test.ts | 2 +- yarn.lock | 1 - 18 files changed, 183 insertions(+), 225 deletions(-) delete mode 100644 packages/ansible-language-server/src/interfaces/lightspeedApi.ts rename {packages/ansible-language-server/src => src/features/lightspeed}/errors.ts (99%) rename {packages/ansible-language-server/src/utils => src/features/lightspeed}/handleApiError.ts (94%) rename {packages/ansible-language-server/test => test/units/lightspeed}/utils/handleApiError.test.ts (99%) diff --git a/packages/ansible-language-server/package-lock.json b/packages/ansible-language-server/package-lock.json index 0d54eb8ed2..35394b533c 100644 --- a/packages/ansible-language-server/package-lock.json +++ b/packages/ansible-language-server/package-lock.json @@ -11,7 +11,6 @@ "dependencies": { "@flatten-js/interval-tree": "^1.1.3", "antsibull-docs": "^1.0.1", - "axios": "^1.7.2", "glob": "^10.4.2", "ini": "^4.1.3", "lodash": "^4.17.21", @@ -1426,16 +1425,6 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, - "node_modules/axios": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", - "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", - "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -7709,16 +7698,6 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, - "axios": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", - "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", - "requires": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", diff --git a/packages/ansible-language-server/package.json b/packages/ansible-language-server/package.json index 066738f086..9fb27f1cc2 100644 --- a/packages/ansible-language-server/package.json +++ b/packages/ansible-language-server/package.json @@ -47,7 +47,6 @@ "dependencies": { "@flatten-js/interval-tree": "^1.1.3", "antsibull-docs": "^1.0.2", - "axios": "^1.7.2", "glob": "^10.4.5", "ini": "^4.1.3", "lodash": "^4.17.21", diff --git a/packages/ansible-language-server/src/ansibleLanguageService.ts b/packages/ansible-language-server/src/ansibleLanguageService.ts index f5dbb59099..3df7afff2c 100644 --- a/packages/ansible-language-server/src/ansibleLanguageService.ts +++ b/packages/ansible-language-server/src/ansibleLanguageService.ts @@ -23,15 +23,6 @@ import { doValidate } from "./providers/validationProvider"; import { ValidationManager } from "./services/validationManager"; import { WorkspaceManager } from "./services/workspaceManager"; import { getAnsibleMetaData } from "./utils/getAnsibleMetaData"; -import axios from "axios"; -import { AxiosError } from "axios"; -import { getBaseUri } from "./utils/webUtils"; -import { - ExplanationResponse, - GenerationResponse, - IError, -} from "./interfaces/lightspeedApi"; -import { mapError } from "./utils/handleApiError"; /** * Initializes the connection and registers all lifecycle event handlers. @@ -360,94 +351,6 @@ export class AnsibleLanguageService { } }, ); - - this.connection.onRequest( - "playbook/explanation", - async (params): Promise => { - const accessToken: string = params["accessToken"]; - const URL: string = params["URL"]; - const content: string = params["content"]; - const explanationId: string = params["explanationId"]; - - const headers = { - "Content-Type": "application/json", - Authorization: `Bearer ${accessToken}`, - }; - - const axiosInstance = axios.create({ - baseURL: `${getBaseUri(URL)}/api/v0`, - headers: headers, - }); - - const result: ExplanationResponse = await axiosInstance - .post( - "/ai/explanations/", - { - content: content, - explanationId: explanationId, - }, - { signal: AbortSignal.timeout(28000) }, - ) - .then((response) => { - return response.data; - }) - .catch((error) => { - const err = error as AxiosError; - const mappedError: IError = mapError(err); - return mappedError; - }); - - console.log(result); - - return result; - }, - ); - - this.connection.onRequest( - "playbook/generation", - async (params): Promise => { - const accessToken: string = params["accessToken"]; - const URL: string = params["URL"]; - const text: string = params["text"]; - const createOutline: boolean = params["createOutline"]; - const outline: string | undefined = params["outline"]; - const generationId: string = params["generationId"]; - const wizardId: string | undefined = params["wizardId"]; - - const headers = { - "Content-Type": "application/json", - Authorization: `Bearer ${accessToken}`, - }; - - const axiosInstance = axios.create({ - baseURL: `${getBaseUri(URL)}/api/v0`, - headers: headers, - }); - - const result: GenerationResponse = await axiosInstance - .post( - "/ai/generations/", - { - text, - createOutline, - outline, - generationId, - wizardId, - }, - { signal: AbortSignal.timeout(28000) }, - ) - .then((response) => { - return response.data; - }) - .catch((error) => { - const err = error as AxiosError; - const mappedError: IError = mapError(err); - return mappedError; - }); - - return result; - }, - ); } private handleError(error: unknown, contextName: string) { diff --git a/packages/ansible-language-server/src/interfaces/lightspeedApi.ts b/packages/ansible-language-server/src/interfaces/lightspeedApi.ts deleted file mode 100644 index 528386ea11..0000000000 --- a/packages/ansible-language-server/src/interfaces/lightspeedApi.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Interface for Lightspeed playbook generation/explanation APIs - */ -export interface IError { - code: string; - message?: string; - detail?: unknown; -} - -export interface GenerationSuccessResponse { - playbook: string; - outline?: string; - generationId: string; -} - -export interface ExplanationSuccessResponse { - content: string; - format: string; - explanationId: string; -} - -export type GenerationResponse = GenerationSuccessResponse | IError; - -export type ExplanationResponse = ExplanationSuccessResponse | IError; diff --git a/src/definitions/lightspeed.ts b/src/definitions/lightspeed.ts index 1a001cf4a3..e315c7f49f 100644 --- a/src/definitions/lightspeed.ts +++ b/src/definitions/lightspeed.ts @@ -63,6 +63,8 @@ export namespace LightSpeedCommands { } export const LIGHTSPEED_API_VERSION = "v0"; +export const LIGHTSPEED_PLAYBOOK_EXPLANATION_URL = `${LIGHTSPEED_API_VERSION}/ai/explanations/`; +export const LIGHTSPEED_PLAYBOOK_GENERATION_URL = `${LIGHTSPEED_API_VERSION}/ai/generations/`; export const LIGHTSPEED_SUGGESTION_COMPLETION_URL = `${LIGHTSPEED_API_VERSION}/ai/completions/`; export const LIGHTSPEED_SUGGESTION_FEEDBACK_URL = `${LIGHTSPEED_API_VERSION}/ai/feedback/`; export const LIGHTSPEED_SUGGESTION_CONTENT_MATCHES_URL = `${LIGHTSPEED_API_VERSION}/ai/contentmatches/`; diff --git a/src/features/lightspeed/api.ts b/src/features/lightspeed/api.ts index d2bb6ef1ba..bbd9d58427 100644 --- a/src/features/lightspeed/api.ts +++ b/src/features/lightspeed/api.ts @@ -3,22 +3,28 @@ import axios, { AxiosInstance, AxiosError } from "axios"; import { SettingsManager } from "../../settings"; import { - CompletionResponseParams, CompletionRequestParams, - FeedbackRequestParams, - FeedbackResponseParams, + CompletionResponseParams, ContentMatchesRequestParams, ContentMatchesResponseParams, + ExplanationRequestParams, + ExplanationResponseParams, + FeedbackRequestParams, + FeedbackResponseParams, + GenerationRequestParams, + GenerationResponseParams, } from "../../interfaces/lightspeed"; import { - LIGHTSPEED_SUGGESTION_CONTENT_MATCHES_URL, + LIGHTSPEED_PLAYBOOK_EXPLANATION_URL, + LIGHTSPEED_PLAYBOOK_GENERATION_URL, LIGHTSPEED_SUGGESTION_COMPLETION_URL, + LIGHTSPEED_SUGGESTION_CONTENT_MATCHES_URL, LIGHTSPEED_SUGGESTION_FEEDBACK_URL, UserAction, } from "../../definitions/lightspeed"; import { getBaseUri } from "./utils/webUtils"; import { ANSIBLE_LIGHTSPEED_API_TIMEOUT } from "../../definitions/constants"; -import { IError } from "@ansible/ansible-language-server/src/interfaces/lightspeedApi"; +import { IError } from "./utils/errors"; import { lightSpeedManager } from "../../extension"; import { LightspeedUser } from "./lightspeedUser"; import { inlineSuggestionHideHandler } from "./inlineSuggestions"; @@ -26,25 +32,10 @@ import { getOneClickTrialProvider, OneClickTrialProvider, } from "./utils/oneClickTrial"; +import { mapError } from "./handleApiError"; const UNKNOWN_ERROR: string = "An unknown error occurred."; -// eslint-disable-next-line @typescript-eslint/no-explicit-any -let _handleApiError: any; - -export async function mapError(error: AxiosError): Promise { - if (!_handleApiError) { - try { - _handleApiError = - await require("@ansible/ansible-language-server/src/utils/handleApiError"); - } catch (e) { - _handleApiError = - await require(/* webpackIgnore: true */ "../../../../server/src/utils/handleApiError"); - } - } - return _handleApiError.mapError(error); -} - export class LightSpeedAPI { private axiosInstance: AxiosInstance | undefined; private settingsManager: SettingsManager; @@ -296,4 +287,98 @@ export class LightSpeedAPI { return mappedError; } } + + public async explanationRequest( + inputData: ExplanationRequestParams, + ): Promise { + // return early if the user is not authenticated + if (!(await this.lightspeedAuthenticatedUser.isAuthenticated())) { + vscode.window.showErrorMessage( + "User not authenticated to use Ansible Lightspeed.", + ); + return {} as ExplanationResponseParams; + } + + const axiosInstance = await this.getApiInstance(); + if (axiosInstance === undefined) { + console.error("Ansible Lightspeed instance is not initialized."); + return {} as ExplanationResponseParams; + } + try { + const requestData = { + ...inputData, + metadata: { ansibleExtensionVersion: this._extensionVersion }, + }; + console.log( + `[ansible-lightspeed] Explanation request sent to lightspeed: ${JSON.stringify( + requestData, + )}`, + ); + const response = await axiosInstance.post( + LIGHTSPEED_PLAYBOOK_EXPLANATION_URL, + //LIGHTSPEED_SUGGESTION_CONTENT_MATCHES_URL, + requestData, + { + timeout: ANSIBLE_LIGHTSPEED_API_TIMEOUT, + // This is coming from our former LSP implementation, it may be a good + // idea to generalize the use of a <28s timeout to be below CloudFront's 30s + signal: AbortSignal.timeout(28000), + }, + ); + return response.data; + } catch (error) { + const err = error as AxiosError; + const mappedError: IError = await mapError(err); + // Do not show trial popup for errors on content matches because either + // completions or generations API should have been called already. + return mappedError; + } + } + + public async generationRequest( + inputData: GenerationRequestParams, + ): Promise { + // return early if the user is not authenticated + if (!(await this.lightspeedAuthenticatedUser.isAuthenticated())) { + vscode.window.showErrorMessage( + "User not authenticated to use Ansible Lightspeed.", + ); + return {} as GenerationResponseParams; + } + + const axiosInstance = await this.getApiInstance(); + if (axiosInstance === undefined) { + console.error("Ansible Lightspeed instance is not initialized."); + return {} as GenerationResponseParams; + } + try { + const requestData = { + ...inputData, + metadata: { ansibleExtensionVersion: this._extensionVersion }, + }; + console.log( + `[ansible-lightspeed] Explanation request sent to lightspeed: ${JSON.stringify( + requestData, + )}`, + ); + const response = await axiosInstance.post( + LIGHTSPEED_PLAYBOOK_GENERATION_URL, + //LIGHTSPEED_SUGGESTION_CONTENT_MATCHES_URL, + requestData, + { + timeout: ANSIBLE_LIGHTSPEED_API_TIMEOUT, + // This is coming from our former LSP implementation, it may be a good + // idea to generalize the use of a <28s timeout to be below CloudFront's 30s + signal: AbortSignal.timeout(28000), + }, + ); + return response.data; + } catch (error) { + const err = error as AxiosError; + const mappedError: IError = await mapError(err); + // Do not show trial popup for errors on content matches because either + // completions or generations API should have been called already. + return mappedError; + } + } } diff --git a/src/features/lightspeed/contentMatchesWebview.ts b/src/features/lightspeed/contentMatchesWebview.ts index ab8b20a031..0f74367417 100644 --- a/src/features/lightspeed/contentMatchesWebview.ts +++ b/src/features/lightspeed/contentMatchesWebview.ts @@ -13,7 +13,7 @@ import { getCurrentUTCDateTime } from "../utils/dateTime"; import * as yaml from "yaml"; import { LightspeedUser } from "./lightspeedUser"; import { parsePlays } from "./utils/parsePlays"; -import { IError } from "@ansible/ansible-language-server/src/interfaces/lightspeedApi"; +import { IError } from "./utils/errors"; export class ContentMatchesWebview implements vscode.WebviewViewProvider { public static readonly viewType = "ansible.lightspeed.trainingMatchPanel"; diff --git a/packages/ansible-language-server/src/errors.ts b/src/features/lightspeed/errors.ts similarity index 99% rename from packages/ansible-language-server/src/errors.ts rename to src/features/lightspeed/errors.ts index a4d268316f..be73db07e8 100644 --- a/packages/ansible-language-server/src/errors.ts +++ b/src/features/lightspeed/errors.ts @@ -1,5 +1,5 @@ import { AxiosError } from "axios"; -import { IError } from "./interfaces/lightspeedApi"; +import { IError } from "./utils/errors"; class Error implements IError { readonly code: string; diff --git a/packages/ansible-language-server/src/utils/handleApiError.ts b/src/features/lightspeed/handleApiError.ts similarity index 94% rename from packages/ansible-language-server/src/utils/handleApiError.ts rename to src/features/lightspeed/handleApiError.ts index 0a94a894f2..4621137a75 100644 --- a/packages/ansible-language-server/src/utils/handleApiError.ts +++ b/src/features/lightspeed/handleApiError.ts @@ -10,8 +10,8 @@ import { ERRORS_CONNECTION_CANCELED_TIMEOUT, ERRORS_CONNECTION_TIMEOUT, ERRORS_NOT_FOUND, -} from "../errors"; -import { IError } from "../interfaces/lightspeedApi"; +} from "./errors"; +import { IError } from "./utils/errors"; export function mapError(err: AxiosError): IError { // Lookup _known_ errors diff --git a/src/features/lightspeed/playbookExplanation.ts b/src/features/lightspeed/playbookExplanation.ts index 61bfef338b..b73f795c7b 100644 --- a/src/features/lightspeed/playbookExplanation.ts +++ b/src/features/lightspeed/playbookExplanation.ts @@ -7,7 +7,10 @@ import * as marked from "marked"; import { SettingsManager } from "../../settings"; import { lightSpeedManager } from "../../extension"; import { LightspeedUser } from "./lightspeedUser"; -import { ExplanationResponse } from "@ansible/ansible-language-server/src/interfaces/lightspeedApi"; +import { IError } from "./utils/errors"; +import { ExplanationResponseParams } from "../../interfaces/lightspeed"; +import { LightSpeedAPI } from "./api"; + import { v4 as uuidv4 } from "uuid"; import * as yaml from "yaml"; import { getOneClickTrialProvider } from "./utils/oneClickTrial"; @@ -98,19 +101,19 @@ export const playbookExplanation = async ( lightSpeedManager.statusBarProvider.statusBar.text = `$(loading~spin) ${lightSpeedStatusbarText}`; try { generateExplanation( + lightSpeedManager.apiInstance, content, explanationId, - client, - lightspeedAuthenticatedUser, - settingsManager, - ).then(async (response: ExplanationResponse) => { + ).then(async (response: ExplanationResponseParams | IError) => { + console.log(response); if (isError(response)) { const oneClickTrialProvider = getOneClickTrialProvider(); - response = oneClickTrialProvider.mapError(response); - if (!(await oneClickTrialProvider.showPopup(response))) { - vscode.window.showErrorMessage(response.message ?? UNKNOWN_ERROR); + //response = oneClickTrialProvider.mapError(response); + const my_error = response as IError; + if (!(await oneClickTrialProvider.showPopup(my_error))) { + vscode.window.showErrorMessage(my_error.message ?? UNKNOWN_ERROR); currentPanel.setContent( - `

The operation has failed:

${response.message}

`, + `

The operation has failed:

${my_error.message}

`, ); } } else { @@ -133,25 +136,17 @@ export const playbookExplanation = async ( }; async function generateExplanation( + apiInstance: LightSpeedAPI, content: string, explanationId: string, - client: LanguageClient, - lightspeedAuthenticatedUser: LightspeedUser, - settingsManager: SettingsManager, -): Promise { - const accessToken = - await lightspeedAuthenticatedUser.getLightspeedUserAccessToken(); - - const explanation: ExplanationResponse = await client.sendRequest( - "playbook/explanation", - { - accessToken: accessToken, - URL: settingsManager.settings.lightSpeedService.URL, +): Promise { + const response: ExplanationResponseParams | IError = + await apiInstance.explanationRequest({ content: content, explanationId: explanationId, - }, - ); - return explanation; + }); + + return response; } export class PlaybookExplanationPanel { diff --git a/src/features/lightspeed/playbookGeneration.ts b/src/features/lightspeed/playbookGeneration.ts index 165a047499..ee7326ed43 100644 --- a/src/features/lightspeed/playbookGeneration.ts +++ b/src/features/lightspeed/playbookGeneration.ts @@ -7,13 +7,15 @@ import { getUri } from "../utils/getUri"; import { SettingsManager } from "../../settings"; import { isLightspeedEnabled, lightSpeedManager } from "../../extension"; import { LightspeedUser } from "./lightspeedUser"; -import { GenerationResponse } from "@ansible/ansible-language-server/src/interfaces/lightspeedApi"; +import { IError } from "./utils/errors"; +import { GenerationResponseParams } from "../../interfaces/lightspeed"; import { LightSpeedCommands, PlaybookGenerationActionType, } from "../../definitions/lightspeed"; import { isError, UNKNOWN_ERROR } from "./utils/errors"; import { getOneClickTrialProvider } from "./utils/oneClickTrial"; +import { LightSpeedAPI } from "./api"; let currentPanel: WebviewPanel | undefined; let wizardId: string | undefined; @@ -70,33 +72,25 @@ async function sendActionEvent( } async function generatePlaybook( + apiInstance: LightSpeedAPI, text: string, outline: string | undefined, generationId: string, - client: LanguageClient, - lightspeedAuthenticatedUser: LightspeedUser, - settingsManager: SettingsManager, panel: vscode.WebviewPanel, -): Promise { - const accessToken = - await lightspeedAuthenticatedUser.getLightspeedUserAccessToken(); - +): Promise { try { panel.webview.postMessage({ command: "startSpinner" }); const createOutline = outline === undefined; - const playbook: GenerationResponse = await client.sendRequest( - "playbook/generation", - { - accessToken, - URL: settingsManager.settings.lightSpeedService.URL, + + const response: GenerationResponseParams | IError = + await apiInstance.generationRequest({ text, outline, createOutline, generationId, wizardId, - }, - ); - return playbook; + }); + return response; } finally { panel.webview.postMessage({ command: "stopSpinner" }); } @@ -157,14 +151,12 @@ export async function showPlaybookGenerationPage( try { if (!message.outline) { generatePlaybook( + lightSpeedManager.apiInstance, message.text, undefined, message.generationId, - client, - lightspeedAuthenticatedUser, - settingsManager, panel, - ).then(async (response: GenerationResponse) => { + ).then(async (response: GenerationResponseParams | IError) => { if (isError(response)) { const oneClickTrialProvider = getOneClickTrialProvider(); response = oneClickTrialProvider.mapError(response); @@ -204,12 +196,10 @@ export async function showPlaybookGenerationPage( if (!playbook) { try { const response = await generatePlaybook( + lightSpeedManager.apiInstance, message.text, message.outline, message.generationId, - client, - lightspeedAuthenticatedUser, - settingsManager, panel, ); if (isError(response)) { diff --git a/src/features/lightspeed/utils/errors.ts b/src/features/lightspeed/utils/errors.ts index 22c3506cfa..ba7d61c2ea 100644 --- a/src/features/lightspeed/utils/errors.ts +++ b/src/features/lightspeed/utils/errors.ts @@ -1,13 +1,18 @@ import { - GenerationResponse, - ExplanationResponse, -} from "@ansible/ansible-language-server/src/interfaces/lightspeedApi"; -import { IError } from "@ansible/ansible-language-server/src/interfaces/lightspeedApi"; + GenerationResponseParams, + ExplanationResponseParams, +} from "../../../interfaces/lightspeed"; + +export interface IError { + code: string; + message?: string; + detail?: unknown; +} export const UNKNOWN_ERROR: string = "An unknown error occurred."; export function isError( - response: GenerationResponse | ExplanationResponse, + response: GenerationResponseParams | ExplanationResponseParams | IError, ): response is IError { return (response as IError).code !== undefined; } diff --git a/src/features/lightspeed/utils/oneClickTrial.ts b/src/features/lightspeed/utils/oneClickTrial.ts index 6514e31227..ead14e27a2 100644 --- a/src/features/lightspeed/utils/oneClickTrial.ts +++ b/src/features/lightspeed/utils/oneClickTrial.ts @@ -1,5 +1,5 @@ import * as vscode from "vscode"; -import { IError } from "@ansible/ansible-language-server/src/interfaces/lightspeedApi"; +import { IError } from "./errors"; import { lightSpeedManager } from "../../../extension"; import { LightSpeedCommands } from "../../../definitions/lightspeed"; diff --git a/src/interfaces/lightspeed.ts b/src/interfaces/lightspeed.ts index 58064255da..01e6b9cfac 100644 --- a/src/interfaces/lightspeed.ts +++ b/src/interfaces/lightspeed.ts @@ -140,6 +140,31 @@ export interface ISuggestionDetails { isPlaybook: boolean; } +export interface GenerationRequestParams { + text: string; + outline?: string; + generationId: string; + createOutline: boolean; + wizardId?: string; +} + +export interface GenerationResponseParams { + playbook: string; + outline?: string; + generationId: string; +} + +export interface ExplanationRequestParams { + content: string; + explanationId: string; +} + +export interface ExplanationResponseParams { + content: string; + format: string; + explanationId: string; +} + export type IAnsibleFileType = "playbook" | "tasks_in_role" | "tasks" | "other"; export type VarType = "defaults" | "vars"; diff --git a/test/ui-test/lightspeedUiTest.ts b/test/ui-test/lightspeedUiTest.ts index f53631e17b..470fb5700c 100644 --- a/test/ui-test/lightspeedUiTest.ts +++ b/test/ui-test/lightspeedUiTest.ts @@ -351,7 +351,7 @@ export function lightspeedUIAssetsTest(): void { await webView.switchBack(); await sleep(2000); - await expectNotification("Bad Request response. Please try again."); + await expectNotification("User not authenticated to use Ansible Lightspeed."); await webView.switchToFrame(5000); // Click reset button and make sure the string "(status=400)" is removed diff --git a/test/units/lightspeed/contentmatches.test.ts b/test/units/lightspeed/contentmatches.test.ts index 5054ff8084..937be73ed3 100644 --- a/test/units/lightspeed/contentmatches.test.ts +++ b/test/units/lightspeed/contentmatches.test.ts @@ -21,7 +21,7 @@ import { ISuggestionDetails, } from "../../../src/interfaces/lightspeed"; import { LightspeedUser } from "../../../src/features/lightspeed/lightspeedUser"; -import { IError } from "@ansible/ansible-language-server/src/interfaces/lightspeedApi"; +import { IError } from "../../../src/features/lightspeed/utils/errors"; function createMatchResponse(): ContentMatchesResponseParams { const contentMatchParams = { diff --git a/packages/ansible-language-server/test/utils/handleApiError.test.ts b/test/units/lightspeed/utils/handleApiError.test.ts similarity index 99% rename from packages/ansible-language-server/test/utils/handleApiError.test.ts rename to test/units/lightspeed/utils/handleApiError.test.ts index 801e97f5ec..5ad5fdc62e 100644 --- a/packages/ansible-language-server/test/utils/handleApiError.test.ts +++ b/test/units/lightspeed/utils/handleApiError.test.ts @@ -1,7 +1,7 @@ require("assert"); import { AxiosError, AxiosHeaders } from "axios"; -import { mapError } from "../../src/utils/handleApiError"; +import { mapError } from "../../../../src/features/lightspeed/handleApiError"; import assert from "assert"; function createError( diff --git a/yarn.lock b/yarn.lock index 6579801624..1a9e829202 100644 --- a/yarn.lock +++ b/yarn.lock @@ -36,7 +36,6 @@ __metadata: "@types/uuid": "npm:^10.0.0" "@types/vscode": "npm:^1.85.0" antsibull-docs: "npm:^1.0.2" - axios: "npm:^1.7.2" chai: "npm:^4.5.0" fuse.js: "npm:^7.0.0" glob: "npm:^10.4.5"