Spaces:
				
			
			
	
			
			
		Build error
		
	
	
	
			
			
	
	
	
	
		
		
		Build error
		
	| from fastapi import APIRouter, Depends, HTTPException, Request, status | |
| from fastapi.responses import JSONResponse | |
| from openhands.core.logger import openhands_logger as logger | |
| from openhands.events.event_filter import EventFilter | |
| from openhands.events.serialization.event import event_to_dict | |
| from openhands.runtime.base import Runtime | |
| from openhands.server.dependencies import get_dependencies | |
| from openhands.server.session.conversation import ServerConversation | |
| from openhands.server.shared import conversation_manager | |
| from openhands.server.utils import get_conversation | |
| app = APIRouter(prefix='/api/conversations/{conversation_id}', dependencies=get_dependencies()) | |
| async def get_remote_runtime_config(conversation: ServerConversation = Depends(get_conversation)) -> JSONResponse: | |
| """Retrieve the runtime configuration. | |
| Currently, this is the session ID and runtime ID (if available). | |
| """ | |
| runtime = conversation.runtime | |
| runtime_id = runtime.runtime_id if hasattr(runtime, 'runtime_id') else None | |
| session_id = runtime.sid if hasattr(runtime, 'sid') else None | |
| return JSONResponse( | |
| content={ | |
| 'runtime_id': runtime_id, | |
| 'session_id': session_id, | |
| } | |
| ) | |
| async def get_vscode_url(conversation: ServerConversation = Depends(get_conversation)) -> JSONResponse: | |
| """Get the VSCode URL. | |
| This endpoint allows getting the VSCode URL. | |
| Args: | |
| request (Request): The incoming FastAPI request object. | |
| Returns: | |
| JSONResponse: A JSON response indicating the success of the operation. | |
| """ | |
| try: | |
| runtime: Runtime = conversation.runtime | |
| logger.debug(f'Runtime type: {type(runtime)}') | |
| logger.debug(f'Runtime VSCode URL: {runtime.vscode_url}') | |
| return JSONResponse( | |
| status_code=status.HTTP_200_OK, content={'vscode_url': runtime.vscode_url} | |
| ) | |
| except Exception as e: | |
| logger.error(f'Error getting VSCode URL: {e}') | |
| return JSONResponse( | |
| status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, | |
| content={ | |
| 'vscode_url': None, | |
| 'error': f'Error getting VSCode URL: {e}', | |
| }, | |
| ) | |
| async def get_hosts(conversation: ServerConversation = Depends(get_conversation)) -> JSONResponse: | |
| """Get the hosts used by the runtime. | |
| This endpoint allows getting the hosts used by the runtime. | |
| Args: | |
| request (Request): The incoming FastAPI request object. | |
| Returns: | |
| JSONResponse: A JSON response indicating the success of the operation. | |
| """ | |
| try: | |
| runtime: Runtime = conversation.runtime | |
| logger.debug(f'Runtime type: {type(runtime)}') | |
| logger.debug(f'Runtime hosts: {runtime.web_hosts}') | |
| return JSONResponse(status_code=200, content={'hosts': runtime.web_hosts}) | |
| except Exception as e: | |
| logger.error(f'Error getting runtime hosts: {e}') | |
| return JSONResponse( | |
| status_code=500, | |
| content={ | |
| 'hosts': None, | |
| 'error': f'Error getting runtime hosts: {e}', | |
| }, | |
| ) | |
| async def search_events( | |
| start_id: int = 0, | |
| end_id: int | None = None, | |
| reverse: bool = False, | |
| filter: EventFilter | None = None, | |
| limit: int = 20, | |
| conversation: ServerConversation = Depends(get_conversation), | |
| ): | |
| """Search through the event stream with filtering and pagination. | |
| Args: | |
| request: The incoming request object | |
| start_id: Starting ID in the event stream. Defaults to 0 | |
| end_id: Ending ID in the event stream | |
| reverse: Whether to retrieve events in reverse order. Defaults to False. | |
| filter: Filter for events | |
| limit: Maximum number of events to return. Must be between 1 and 100. Defaults to 20 | |
| Returns: | |
| dict: Dictionary containing: | |
| - events: List of matching events | |
| - has_more: Whether there are more matching events after this batch | |
| Raises: | |
| HTTPException: If conversation is not found | |
| ValueError: If limit is less than 1 or greater than 100 | |
| """ | |
| if limit < 0 or limit > 100: | |
| raise HTTPException( | |
| status_code=status.HTTP_400_BAD_REQUEST, detail='Invalid limit' | |
| ) | |
| # Get matching events from the stream | |
| event_stream = conversation.event_stream | |
| events = list( | |
| event_stream.search_events( | |
| start_id=start_id, | |
| end_id=end_id, | |
| reverse=reverse, | |
| filter=filter, | |
| limit=limit + 1, | |
| ) | |
| ) | |
| # Check if there are more events | |
| has_more = len(events) > limit | |
| if has_more: | |
| events = events[:limit] # Remove the extra event | |
| events_json = [event_to_dict(event) for event in events] | |
| return { | |
| 'events': events_json, | |
| 'has_more': has_more, | |
| } | |
| async def add_event(request: Request, conversation: ServerConversation = Depends(get_conversation)): | |
| data = request.json() | |
| await conversation_manager.send_to_event_stream(conversation.sid, data) | |
| return JSONResponse({'success': True}) | |