From e5f98c7ff01b1315ab5ead5b586e0ae244b6edf9 Mon Sep 17 00:00:00 2001 From: Graham Neubig Date: Tue, 6 May 2025 14:03:06 -0400 Subject: [PATCH] Fix typing in routes directory (#8293) Co-authored-by: openhands Co-authored-by: Rohit Malhotra --- openhands/server/routes/conversation.py | 6 ++-- openhands/server/routes/files.py | 29 ++++++++++++------- openhands/server/routes/git.py | 10 +++---- .../server/routes/manage_conversations.py | 7 +++-- 4 files changed, 31 insertions(+), 21 deletions(-) diff --git a/openhands/server/routes/conversation.py b/openhands/server/routes/conversation.py index b52eb0b53e..ff9dcf86dd 100644 --- a/openhands/server/routes/conversation.py +++ b/openhands/server/routes/conversation.py @@ -8,7 +8,7 @@ app = APIRouter(prefix='/api/conversations/{conversation_id}') @app.get('/config') -async def get_remote_runtime_config(request: Request): +async def get_remote_runtime_config(request: Request) -> JSONResponse: """Retrieve the runtime configuration. Currently, this is the session ID and runtime ID (if available). @@ -25,7 +25,7 @@ async def get_remote_runtime_config(request: Request): @app.get('/vscode-url') -async def get_vscode_url(request: Request): +async def get_vscode_url(request: Request) -> JSONResponse: """Get the VSCode URL. This endpoint allows getting the VSCode URL. @@ -55,7 +55,7 @@ async def get_vscode_url(request: Request): @app.get('/web-hosts') -async def get_hosts(request: Request): +async def get_hosts(request: Request) -> JSONResponse: """Get the hosts used by the runtime. This endpoint allows getting the hosts used by the runtime. diff --git a/openhands/server/routes/files.py b/openhands/server/routes/files.py index 62f27b154a..bf0e5ec324 100644 --- a/openhands/server/routes/files.py +++ b/openhands/server/routes/files.py @@ -1,4 +1,5 @@ import os +from typing import Any from fastapi import ( APIRouter, @@ -42,7 +43,7 @@ app = APIRouter(prefix='/api/conversations/{conversation_id}') @app.get('/list-files') -async def list_files(request: Request, path: str | None = None): +async def list_files(request: Request, path: str | None = None) -> dict[str, str]: """List files in the specified path. This function retrieves a list of files from the agent's runtime file store, @@ -83,7 +84,9 @@ async def list_files(request: Request, path: str | None = None): file_list = [f for f in file_list if f not in FILES_TO_IGNORE] - async def filter_for_gitignore(file_list, base_path): + async def filter_for_gitignore( + file_list: list[dict[str, Any]], base_path: str + ) -> list[dict[str, str]]: gitignore_path = os.path.join(base_path, '.gitignore') try: read_action = FileReadAction(gitignore_path) @@ -109,8 +112,8 @@ async def list_files(request: Request, path: str | None = None): return file_list -@app.get('/select-file') -async def select_file(file: str, request: Request): +@app.get('/select-file', response_model=None) +async def select_file(file: str, request: Request) -> FileResponse | JSONResponse: """Retrieve the content of a specified file. To select a file: @@ -144,7 +147,7 @@ async def select_file(file: str, request: Request): if isinstance(observation, FileReadObservation): content = observation.content - return {'code': content} + return JSONResponse(content={'code': content}) elif isinstance(observation, ErrorObservation): logger.error(f'Error opening file {file}: {observation}') @@ -158,10 +161,16 @@ async def select_file(file: str, request: Request): status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content={'error': f'Error opening file: {observation}'}, ) + else: + # Handle unexpected observation types + return JSONResponse( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + content={'error': f'Unexpected observation type: {type(observation)}'}, + ) @app.get('/zip-directory') -def zip_current_workspace(request: Request): +def zip_current_workspace(request: Request) -> FileResponse: try: logger.debug('Zipping workspace') runtime: Runtime = request.state.conversation.runtime @@ -193,7 +202,7 @@ async def git_changes( request: Request, conversation_id: str, user_id: str = Depends(get_user_id), -): +) -> dict[str, Any]: runtime: Runtime = request.state.conversation.runtime conversation_store = await ConversationStoreImpl.get_instance( config, @@ -234,8 +243,8 @@ async def git_diff( request: Request, path: str, conversation_id: str, - conversation_store=Depends(get_conversation_store), -): + conversation_store: Any = Depends(get_conversation_store), +) -> dict[str, Any]: runtime: Runtime = request.state.conversation.runtime cwd = await get_cwd( @@ -259,7 +268,7 @@ async def get_cwd( conversation_store: ConversationStore, conversation_id: str, workspace_mount_path_in_sandbox: str, -): +) -> str: metadata = await conversation_store.get_metadata(conversation_id) is_running = await conversation_manager.is_agent_loop_running(conversation_id) conversation_info = await _get_conversation_info(metadata, is_running) diff --git a/openhands/server/routes/git.py b/openhands/server/routes/git.py index f134acd399..ba53ac822f 100644 --- a/openhands/server/routes/git.py +++ b/openhands/server/routes/git.py @@ -30,7 +30,7 @@ async def get_user_repositories( provider_tokens: PROVIDER_TOKEN_TYPE | None = Depends(get_provider_tokens), access_token: SecretStr | None = Depends(get_access_token), user_id: str | None = Depends(get_user_id), -): +) -> list[Repository] | JSONResponse: if provider_tokens: client = ProviderHandler( provider_tokens=provider_tokens, @@ -66,7 +66,7 @@ async def get_user_repositories( async def get_user( provider_tokens: PROVIDER_TOKEN_TYPE | None = Depends(get_provider_tokens), access_token: SecretStr | None = Depends(get_access_token), -): +) -> User | JSONResponse: if provider_tokens: client = ProviderHandler( provider_tokens=provider_tokens, external_auth_token=access_token @@ -102,7 +102,7 @@ async def search_repositories( order: str = 'desc', provider_tokens: PROVIDER_TOKEN_TYPE | None = Depends(get_provider_tokens), access_token: SecretStr | None = Depends(get_access_token), -): +) -> list[Repository] | JSONResponse: if provider_tokens: client = ProviderHandler( provider_tokens=provider_tokens, external_auth_token=access_token @@ -135,7 +135,7 @@ async def search_repositories( async def get_suggested_tasks( provider_tokens: PROVIDER_TOKEN_TYPE | None = Depends(get_provider_tokens), access_token: SecretStr | None = Depends(get_access_token), -): +) -> list[SuggestedTask] | JSONResponse: """Get suggested tasks for the authenticated user across their most recently pushed repositories. Returns: @@ -173,7 +173,7 @@ async def get_repository_branches( repository: str, provider_tokens: PROVIDER_TOKEN_TYPE | None = Depends(get_provider_tokens), access_token: SecretStr | None = Depends(get_access_token), -): +) -> list[Branch] | JSONResponse: """Get branches for a repository. Args: diff --git a/openhands/server/routes/manage_conversations.py b/openhands/server/routes/manage_conversations.py index cf9a996d98..bd68ff97c3 100644 --- a/openhands/server/routes/manage_conversations.py +++ b/openhands/server/routes/manage_conversations.py @@ -1,5 +1,6 @@ import uuid from datetime import datetime, timezone +from typing import Any from fastapi import APIRouter, Body, Depends, status from fastapi.responses import JSONResponse @@ -75,7 +76,7 @@ async def _create_new_conversation( replay_json: str | None, conversation_trigger: ConversationTrigger = ConversationTrigger.GUI, attach_convo_id: bool = False, -): +) -> str: logger.info( 'Creating conversation', extra={ @@ -89,7 +90,7 @@ async def _create_new_conversation( settings = await settings_store.load() logger.info('Settings loaded') - session_init_args: dict = {} + session_init_args: dict[str, Any] = {} if settings: session_init_args = {**settings.__dict__, **session_init_args} # We could use litellm.check_valid_key for a more accurate check, @@ -172,7 +173,7 @@ async def new_conversation( user_id: str = Depends(get_user_id), provider_tokens: PROVIDER_TOKEN_TYPE = Depends(get_provider_tokens), auth_type: AuthType | None = Depends(get_auth_type), -): +) -> JSONResponse: """Initialize a new session or join an existing one. After successful initialization, the client should connect to the WebSocket