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"