|
import {
|
|
SaveFileSuccessResponse,
|
|
FileUploadSuccessResponse,
|
|
Feedback,
|
|
FeedbackResponse,
|
|
GitHubAccessTokenResponse,
|
|
ErrorResponse,
|
|
GetConfigResponse,
|
|
GetVSCodeUrlResponse,
|
|
AuthenticateResponse,
|
|
Conversation,
|
|
ResultSet,
|
|
} from "./open-hands.types";
|
|
import { openHands } from "./open-hands-axios";
|
|
import { ApiSettings } from "#/services/settings";
|
|
|
|
class OpenHands {
|
|
|
|
|
|
|
|
|
|
static async getModels(): Promise<string[]> {
|
|
const { data } = await openHands.get<string[]>("/api/options/models");
|
|
return data;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static async getAgents(): Promise<string[]> {
|
|
const { data } = await openHands.get<string[]>("/api/options/agents");
|
|
return data;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static async getSecurityAnalyzers(): Promise<string[]> {
|
|
const { data } = await openHands.get<string[]>(
|
|
"/api/options/security-analyzers",
|
|
);
|
|
return data;
|
|
}
|
|
|
|
static async getConfig(): Promise<GetConfigResponse> {
|
|
const { data } = await openHands.get<GetConfigResponse>(
|
|
"/api/options/config",
|
|
);
|
|
return data;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static async getFiles(
|
|
conversationId: string,
|
|
path?: string,
|
|
): Promise<string[]> {
|
|
const url = `/api/conversations/${conversationId}/list-files`;
|
|
const { data } = await openHands.get<string[]>(url, {
|
|
params: { path },
|
|
});
|
|
return data;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static async getFile(conversationId: string, path: string): Promise<string> {
|
|
const url = `/api/conversations/${conversationId}/select-file`;
|
|
const { data } = await openHands.get<{ code: string }>(url, {
|
|
params: { file: path },
|
|
});
|
|
|
|
return data.code;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static async saveFile(
|
|
conversationId: string,
|
|
path: string,
|
|
content: string,
|
|
): Promise<SaveFileSuccessResponse> {
|
|
const url = `/api/conversations/${conversationId}/save-file`;
|
|
const { data } = await openHands.post<
|
|
SaveFileSuccessResponse | ErrorResponse
|
|
>(url, {
|
|
filePath: path,
|
|
content,
|
|
});
|
|
|
|
if ("error" in data) throw new Error(data.error);
|
|
return data;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static async uploadFiles(
|
|
conversationId: string,
|
|
files: File[],
|
|
): Promise<FileUploadSuccessResponse> {
|
|
const url = `/api/conversations/${conversationId}/upload-files`;
|
|
const formData = new FormData();
|
|
files.forEach((file) => formData.append("files", file));
|
|
|
|
const { data } = await openHands.post<
|
|
FileUploadSuccessResponse | ErrorResponse
|
|
>(url, formData);
|
|
|
|
if ("error" in data) throw new Error(data.error);
|
|
return data;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static async submitFeedback(
|
|
conversationId: string,
|
|
feedback: Feedback,
|
|
): Promise<FeedbackResponse> {
|
|
const url = `/api/conversations/${conversationId}/submit-feedback`;
|
|
const { data } = await openHands.post<FeedbackResponse>(url, feedback);
|
|
return data;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static async authenticate(
|
|
appMode: GetConfigResponse["APP_MODE"],
|
|
): Promise<boolean> {
|
|
if (appMode === "oss") return true;
|
|
|
|
const response =
|
|
await openHands.post<AuthenticateResponse>("/api/authenticate");
|
|
return response.status === 200;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static async refreshToken(
|
|
appMode: GetConfigResponse["APP_MODE"],
|
|
userId: string,
|
|
): Promise<string> {
|
|
if (appMode === "oss") return "";
|
|
|
|
const response = await openHands.post<GitHubAccessTokenResponse>(
|
|
"/api/refresh-token",
|
|
{
|
|
userId,
|
|
},
|
|
);
|
|
return response.data.access_token;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static async getWorkspaceZip(conversationId: string): Promise<Blob> {
|
|
const url = `/api/conversations/${conversationId}/zip-directory`;
|
|
const response = await openHands.get(url, {
|
|
responseType: "blob",
|
|
});
|
|
return response.data;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static async getGitHubAccessToken(
|
|
code: string,
|
|
): Promise<GitHubAccessTokenResponse> {
|
|
const { data } = await openHands.post<GitHubAccessTokenResponse>(
|
|
"/api/github/callback",
|
|
{
|
|
code,
|
|
},
|
|
);
|
|
return data;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static async getVSCodeUrl(
|
|
conversationId: string,
|
|
): Promise<GetVSCodeUrlResponse> {
|
|
const { data } = await openHands.get<GetVSCodeUrlResponse>(
|
|
`/api/conversations/${conversationId}/vscode-url`,
|
|
);
|
|
return data;
|
|
}
|
|
|
|
static async getRuntimeId(
|
|
conversationId: string,
|
|
): Promise<{ runtime_id: string }> {
|
|
const { data } = await openHands.get<{ runtime_id: string }>(
|
|
`/api/conversations/${conversationId}/config`,
|
|
);
|
|
return data;
|
|
}
|
|
|
|
static async getUserConversations(): Promise<Conversation[]> {
|
|
const { data } = await openHands.get<ResultSet<Conversation>>(
|
|
"/api/conversations?limit=9",
|
|
);
|
|
return data.results;
|
|
}
|
|
|
|
static async deleteUserConversation(conversationId: string): Promise<void> {
|
|
await openHands.delete(`/api/conversations/${conversationId}`);
|
|
}
|
|
|
|
static async updateUserConversation(
|
|
conversationId: string,
|
|
conversation: Partial<Omit<Conversation, "conversation_id">>,
|
|
): Promise<void> {
|
|
await openHands.patch(`/api/conversations/${conversationId}`, conversation);
|
|
}
|
|
|
|
static async createConversation(
|
|
githubToken?: string,
|
|
selectedRepository?: string,
|
|
): Promise<Conversation> {
|
|
const body = {
|
|
github_token: githubToken,
|
|
selected_repository: selectedRepository,
|
|
};
|
|
|
|
const { data } = await openHands.post<Conversation>(
|
|
"/api/conversations",
|
|
body,
|
|
);
|
|
|
|
|
|
localStorage.setItem("latest_conversation_id", data.conversation_id);
|
|
|
|
return data;
|
|
}
|
|
|
|
static async getConversation(
|
|
conversationId: string,
|
|
): Promise<Conversation | null> {
|
|
const { data } = await openHands.get<Conversation | null>(
|
|
`/api/conversations/${conversationId}`,
|
|
);
|
|
|
|
return data;
|
|
}
|
|
|
|
static async searchEvents(
|
|
conversationId: string,
|
|
params: {
|
|
query?: string;
|
|
startId?: number;
|
|
limit?: number;
|
|
eventType?: string;
|
|
source?: string;
|
|
startDate?: string;
|
|
endDate?: string;
|
|
},
|
|
): Promise<{ events: Record<string, unknown>[]; has_more: boolean }> {
|
|
const { data } = await openHands.get<{
|
|
events: Record<string, unknown>[];
|
|
has_more: boolean;
|
|
}>(`/api/conversations/${conversationId}/events/search`, {
|
|
params: {
|
|
query: params.query,
|
|
start_id: params.startId,
|
|
limit: params.limit,
|
|
event_type: params.eventType,
|
|
source: params.source,
|
|
start_date: params.startDate,
|
|
end_date: params.endDate,
|
|
},
|
|
});
|
|
return data;
|
|
}
|
|
|
|
|
|
|
|
|
|
static async getSettings(): Promise<ApiSettings> {
|
|
const { data } = await openHands.get<ApiSettings>("/api/settings");
|
|
return data;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static async saveSettings(settings: Partial<ApiSettings>): Promise<boolean> {
|
|
const data = await openHands.post("/api/settings", settings);
|
|
return data.status === 200;
|
|
}
|
|
|
|
static async getGitHubUser(): Promise<GitHubUser> {
|
|
const response = await openHands.get<GitHubUser>("/api/github/user");
|
|
|
|
const { data } = response;
|
|
|
|
const user: GitHubUser = {
|
|
id: data.id,
|
|
login: data.login,
|
|
avatar_url: data.avatar_url,
|
|
company: data.company,
|
|
name: data.name,
|
|
email: data.email,
|
|
};
|
|
|
|
return user;
|
|
}
|
|
|
|
static async getGitHubUserInstallationIds(): Promise<number[]> {
|
|
const response = await openHands.get<number[]>("/api/github/installations");
|
|
return response.data;
|
|
}
|
|
|
|
static async searchGitHubRepositories(
|
|
query: string,
|
|
per_page = 5,
|
|
): Promise<GitHubRepository[]> {
|
|
const response = await openHands.get<{ items: GitHubRepository[] }>(
|
|
"/api/github/search/repositories",
|
|
{
|
|
params: {
|
|
query,
|
|
per_page,
|
|
},
|
|
},
|
|
);
|
|
|
|
return response.data.items;
|
|
}
|
|
}
|
|
|
|
export default OpenHands;
|
|
|