Skip to content
41 changes: 34 additions & 7 deletions src/common/atlas/apiClientError.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,48 @@
export class ApiClientError extends Error {
response?: Response;
import { ApiError } from "./openapi.js";

constructor(message: string, response: Response | undefined = undefined) {
export class ApiClientError extends Error {
private constructor(
message: string,
public readonly response?: Response,
public readonly body?: ApiError
) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a benefit to us storing the body?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting the ApiError model gives us insight into backend error codes, some tools might require an if/else depending on the backend error code.

super(message);
this.name = "ApiClientError";
this.response = response;
}

static async fromResponse(
response: Response,
message: string = `error calling Atlas API`
): Promise<ApiClientError> {
const { errorMessage, body } = await this.extractErrorMessage(response);

return new ApiClientError(`${message}: ${errorMessage}`, response, body);
}

private static async extractErrorMessage(
response: Response
): Promise<{ errorMessage: string; body: ApiError | undefined }> {
let errorMessage: string = "";
let body: ApiError | undefined = undefined;
try {
const text = await response.text();
return new ApiClientError(`${message}: [${response.status} ${response.statusText}] ${text}`, response);
body = (await response.json()) as ApiError;
errorMessage = body.reason || "unknown error";
if (body.detail && body.detail.length > 0) {
errorMessage = `${errorMessage}; ${body.detail}`;
}
} catch {
return new ApiClientError(`${message}: ${response.status} ${response.statusText}`, response);
try {
errorMessage = await response.text();
} catch {
errorMessage = "unknown error";
}
}

errorMessage = `[${response.status} ${response.statusText}] ${errorMessage.trim()}`;

return {
errorMessage,
body,
};
}
}
2 changes: 1 addition & 1 deletion src/tools/tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,9 @@ export abstract class ToolBase {
{
type: "text",
text: `Error running ${this.name}: ${error instanceof Error ? error.message : String(error)}`,
isError: true,
},
],
isError: true,
};
}

Expand Down
Loading