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; | |