import { AxiosHeaders } from "axios"; import { Feedback, FeedbackResponse, GitHubAccessTokenResponse, GetConfigResponse, GetVSCodeUrlResponse, AuthenticateResponse, Conversation, ResultSet, GetTrajectoryResponse, GitChangeDiff, GitChange, } from "./open-hands.types"; import { openHands } from "./open-hands-axios"; import { ApiSettings, PostApiSettings, Provider } from "#/types/settings"; import { GitUser, GitRepository, Branch } from "#/types/git"; import { SuggestedTask } from "#/components/features/home/tasks/task.types"; class OpenHands { private static currentConversation: Conversation | null = null; /** * Get a current conversation * @return the current conversation */ static getCurrentConversation(): Conversation | null { return this.currentConversation; } /** * Set a current conversation * @param url Custom URL to use for conversation endpoints */ static setCurrentConversation( currentConversation: Conversation | null, ): void { this.currentConversation = currentConversation; } /** * Get the url for the conversation. If */ static getConversationUrl(conversationId: string): string { if (this.currentConversation?.conversation_id === conversationId) { if (this.currentConversation.url) { return this.currentConversation.url; } } return `/api/conversations/${conversationId}`; } /** * Retrieve the list of models available * @returns List of models available */ static async getModels(): Promise { const { data } = await openHands.get("/api/options/models"); return data; } /** * Retrieve the list of agents available * @returns List of agents available */ static async getAgents(): Promise { const { data } = await openHands.get("/api/options/agents"); return data; } /** * Retrieve the list of security analyzers available * @returns List of security analyzers available */ static async getSecurityAnalyzers(): Promise { const { data } = await openHands.get( "/api/options/security-analyzers", ); return data; } static async getConfig(): Promise { const { data } = await openHands.get( "/api/options/config", ); return data; } static getConversationHeaders(): AxiosHeaders { const headers = new AxiosHeaders(); const sessionApiKey = this.currentConversation?.session_api_key; if (sessionApiKey) { headers.set("X-Session-API-Key", sessionApiKey); } return headers; } /** * Send feedback to the server * @param data Feedback data * @returns The stored feedback data */ static async submitFeedback( conversationId: string, feedback: Feedback, ): Promise { const url = `/api/conversations/${conversationId}/submit-feedback`; const { data } = await openHands.post(url, feedback); return data; } /** * Authenticate with GitHub token * @returns Response with authentication status and user info if successful */ static async authenticate( appMode: GetConfigResponse["APP_MODE"], ): Promise { if (appMode === "oss") return true; // Just make the request, if it succeeds (no exception thrown), return true await openHands.post("/api/authenticate"); return true; } /** * Get the blob of the workspace zip * @returns Blob of the workspace zip */ static async getWorkspaceZip(conversationId: string): Promise { const url = `${this.getConversationUrl(conversationId)}/zip-directory`; const response = await openHands.get(url, { responseType: "blob", headers: this.getConversationHeaders(), }); return response.data; } /** * Get the web hosts * @returns Array of web hosts */ static async getWebHosts(conversationId: string): Promise { const url = `${this.getConversationUrl(conversationId)}/web-hosts`; const response = await openHands.get(url, { headers: this.getConversationHeaders(), }); return Object.keys(response.data.hosts); } /** * @param code Code provided by GitHub * @returns GitHub access token */ static async getGitHubAccessToken( code: string, ): Promise { const { data } = await openHands.post( "/api/keycloak/callback", { code, }, ); return data; } /** * Get the VSCode URL * @returns VSCode URL */ static async getVSCodeUrl( conversationId: string, ): Promise { const url = `${this.getConversationUrl(conversationId)}/vscode-url`; const { data } = await openHands.get(url, { headers: this.getConversationHeaders(), }); return data; } static async getRuntimeId( conversationId: string, ): Promise<{ runtime_id: string }> { const url = `${this.getConversationUrl(conversationId)}/config`; const { data } = await openHands.get<{ runtime_id: string }>(url, { headers: this.getConversationHeaders(), }); return data; } static async getUserConversations(): Promise { const { data } = await openHands.get>( "/api/conversations?limit=20", ); return data.results; } static async deleteUserConversation(conversationId: string): Promise { await openHands.delete(`/api/conversations/${conversationId}`); } static async createConversation( selectedRepository?: string, git_provider?: Provider, initialUserMsg?: string, imageUrls?: string[], replayJson?: string, suggested_task?: SuggestedTask, selected_branch?: string, ): Promise { const body = { repository: selectedRepository, git_provider, selected_branch, initial_user_msg: initialUserMsg, image_urls: imageUrls, replay_json: replayJson, suggested_task, }; const { data } = await openHands.post( "/api/conversations", body, ); return data; } static async getConversation( conversationId: string, ): Promise { const { data } = await openHands.get( `/api/conversations/${conversationId}`, ); return data; } static async startConversation( conversationId: string, ): Promise { const { data } = await openHands.post( `/api/conversations/${conversationId}/start`, ); return data; } static async stopConversation( conversationId: string, ): Promise { const { data } = await openHands.post( `/api/conversations/${conversationId}/stop`, ); return data; } /** * Get the settings from the server or use the default settings if not found */ static async getSettings(): Promise { const { data } = await openHands.get("/api/settings"); return data; } /** * Save the settings to the server. Only valid settings are saved. * @param settings - the settings to save */ static async saveSettings( settings: Partial, ): Promise { const data = await openHands.post("/api/settings", settings); return data.status === 200; } static async createCheckoutSession(amount: number): Promise { const { data } = await openHands.post( "/api/billing/create-checkout-session", { amount, }, ); return data.redirect_url; } static async createBillingSessionResponse(): Promise { const { data } = await openHands.post( "/api/billing/create-customer-setup-session", ); return data.redirect_url; } static async getBalance(): Promise { const { data } = await openHands.get<{ credits: string }>( "/api/billing/credits", ); return data.credits; } static async getGitUser(): Promise { const response = await openHands.get("/api/user/info"); const { data } = response; const user: GitUser = { id: data.id, login: data.login, avatar_url: data.avatar_url, company: data.company, name: data.name, email: data.email, }; return user; } static async searchGitRepositories( query: string, per_page = 5, ): Promise { const response = await openHands.get( "/api/user/search/repositories", { params: { query, per_page, }, }, ); return response.data; } static async getTrajectory( conversationId: string, ): Promise { const url = `${this.getConversationUrl(conversationId)}/trajectory`; const { data } = await openHands.get(url, { headers: this.getConversationHeaders(), }); return data; } static async logout(appMode: GetConfigResponse["APP_MODE"]): Promise { const endpoint = appMode === "saas" ? "/api/logout" : "/api/unset-provider-tokens"; await openHands.post(endpoint); } static async getGitChanges(conversationId: string): Promise { const url = `${this.getConversationUrl(conversationId)}/git/changes`; const { data } = await openHands.get(url, { headers: this.getConversationHeaders(), }); return data; } static async getGitChangeDiff( conversationId: string, path: string, ): Promise { const url = `${this.getConversationUrl(conversationId)}/git/diff`; const { data } = await openHands.get(url, { params: { path }, headers: this.getConversationHeaders(), }); return data; } /** * Given a PAT, retrieves the repositories of the user * @returns A list of repositories */ static async retrieveUserGitRepositories() { const { data } = await openHands.get( "/api/user/repositories", { params: { sort: "pushed", }, }, ); return data; } static async getRepositoryBranches(repository: string): Promise { const { data } = await openHands.get( `/api/user/repository/branches?repository=${encodeURIComponent(repository)}`, ); return data; } } export default OpenHands;