Spaces:
Build error
Build error
| 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<string[]> { | |
| const { data } = await openHands.get<string[]>("/api/options/models"); | |
| return data; | |
| } | |
| /** | |
| * Retrieve the list of agents available | |
| * @returns List of agents available | |
| */ | |
| static async getAgents(): Promise<string[]> { | |
| const { data } = await openHands.get<string[]>("/api/options/agents"); | |
| return data; | |
| } | |
| /** | |
| * Retrieve the list of security analyzers available | |
| * @returns List of security analyzers available | |
| */ | |
| 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 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<FeedbackResponse> { | |
| const url = `/api/conversations/${conversationId}/submit-feedback`; | |
| const { data } = await openHands.post<FeedbackResponse>(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<boolean> { | |
| if (appMode === "oss") return true; | |
| // Just make the request, if it succeeds (no exception thrown), return true | |
| await openHands.post<AuthenticateResponse>("/api/authenticate"); | |
| return true; | |
| } | |
| /** | |
| * Get the blob of the workspace zip | |
| * @returns Blob of the workspace zip | |
| */ | |
| static async getWorkspaceZip(conversationId: string): Promise<Blob> { | |
| 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<string[]> { | |
| 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<GitHubAccessTokenResponse> { | |
| const { data } = await openHands.post<GitHubAccessTokenResponse>( | |
| "/api/keycloak/callback", | |
| { | |
| code, | |
| }, | |
| ); | |
| return data; | |
| } | |
| /** | |
| * Get the VSCode URL | |
| * @returns VSCode URL | |
| */ | |
| static async getVSCodeUrl( | |
| conversationId: string, | |
| ): Promise<GetVSCodeUrlResponse> { | |
| const url = `${this.getConversationUrl(conversationId)}/vscode-url`; | |
| const { data } = await openHands.get<GetVSCodeUrlResponse>(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<Conversation[]> { | |
| const { data } = await openHands.get<ResultSet<Conversation>>( | |
| "/api/conversations?limit=20", | |
| ); | |
| return data.results; | |
| } | |
| static async deleteUserConversation(conversationId: string): Promise<void> { | |
| 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<Conversation> { | |
| 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<Conversation>( | |
| "/api/conversations", | |
| body, | |
| ); | |
| return data; | |
| } | |
| static async getConversation( | |
| conversationId: string, | |
| ): Promise<Conversation | null> { | |
| const { data } = await openHands.get<Conversation | null>( | |
| `/api/conversations/${conversationId}`, | |
| ); | |
| return data; | |
| } | |
| static async startConversation( | |
| conversationId: string, | |
| ): Promise<Conversation | null> { | |
| const { data } = await openHands.post<Conversation | null>( | |
| `/api/conversations/${conversationId}/start`, | |
| ); | |
| return data; | |
| } | |
| static async stopConversation( | |
| conversationId: string, | |
| ): Promise<Conversation | null> { | |
| const { data } = await openHands.post<Conversation | null>( | |
| `/api/conversations/${conversationId}/stop`, | |
| ); | |
| return data; | |
| } | |
| /** | |
| * Get the settings from the server or use the default settings if not found | |
| */ | |
| static async getSettings(): Promise<ApiSettings> { | |
| const { data } = await openHands.get<ApiSettings>("/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<PostApiSettings>, | |
| ): Promise<boolean> { | |
| const data = await openHands.post("/api/settings", settings); | |
| return data.status === 200; | |
| } | |
| static async createCheckoutSession(amount: number): Promise<string> { | |
| const { data } = await openHands.post( | |
| "/api/billing/create-checkout-session", | |
| { | |
| amount, | |
| }, | |
| ); | |
| return data.redirect_url; | |
| } | |
| static async createBillingSessionResponse(): Promise<string> { | |
| const { data } = await openHands.post( | |
| "/api/billing/create-customer-setup-session", | |
| ); | |
| return data.redirect_url; | |
| } | |
| static async getBalance(): Promise<string> { | |
| const { data } = await openHands.get<{ credits: string }>( | |
| "/api/billing/credits", | |
| ); | |
| return data.credits; | |
| } | |
| static async getGitUser(): Promise<GitUser> { | |
| const response = await openHands.get<GitUser>("/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<GitRepository[]> { | |
| const response = await openHands.get<GitRepository[]>( | |
| "/api/user/search/repositories", | |
| { | |
| params: { | |
| query, | |
| per_page, | |
| }, | |
| }, | |
| ); | |
| return response.data; | |
| } | |
| static async getTrajectory( | |
| conversationId: string, | |
| ): Promise<GetTrajectoryResponse> { | |
| const url = `${this.getConversationUrl(conversationId)}/trajectory`; | |
| const { data } = await openHands.get<GetTrajectoryResponse>(url, { | |
| headers: this.getConversationHeaders(), | |
| }); | |
| return data; | |
| } | |
| static async logout(appMode: GetConfigResponse["APP_MODE"]): Promise<void> { | |
| const endpoint = | |
| appMode === "saas" ? "/api/logout" : "/api/unset-provider-tokens"; | |
| await openHands.post(endpoint); | |
| } | |
| static async getGitChanges(conversationId: string): Promise<GitChange[]> { | |
| const url = `${this.getConversationUrl(conversationId)}/git/changes`; | |
| const { data } = await openHands.get<GitChange[]>(url, { | |
| headers: this.getConversationHeaders(), | |
| }); | |
| return data; | |
| } | |
| static async getGitChangeDiff( | |
| conversationId: string, | |
| path: string, | |
| ): Promise<GitChangeDiff> { | |
| const url = `${this.getConversationUrl(conversationId)}/git/diff`; | |
| const { data } = await openHands.get<GitChangeDiff>(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<GitRepository[]>( | |
| "/api/user/repositories", | |
| { | |
| params: { | |
| sort: "pushed", | |
| }, | |
| }, | |
| ); | |
| return data; | |
| } | |
| static async getRepositoryBranches(repository: string): Promise<Branch[]> { | |
| const { data } = await openHands.get<Branch[]>( | |
| `/api/user/repository/branches?repository=${encodeURIComponent(repository)}`, | |
| ); | |
| return data; | |
| } | |
| } | |
| export default OpenHands; | |