Skip to content

Commit

Permalink
fix: Add proper type hints to routes directory
Browse files Browse the repository at this point in the history
  • Loading branch information
openhands-agent committed Feb 23, 2025
1 parent 70b21d1 commit d17df96
Show file tree
Hide file tree
Showing 6 changed files with 275 additions and 43 deletions.
2 changes: 1 addition & 1 deletion openhands/server/routes/feedback.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@


@app.post('/submit-feedback')
async def submit_feedback(request: Request, conversation_id: str):
async def submit_feedback(request: Request, conversation_id: str) -> JSONResponse:
"""Submit user feedback.
This function stores the provided feedback data.
Expand Down
10 changes: 6 additions & 4 deletions openhands/server/routes/github.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Union

from fastapi import APIRouter, Depends, status
from fastapi.responses import JSONResponse
from pydantic import SecretStr
Expand All @@ -22,7 +24,7 @@ async def get_github_repositories(
installation_id: int | None = None,
github_user_id: str | None = Depends(get_user_id),
github_user_token: SecretStr | None = Depends(get_github_token),
):
) -> Union[list[GitHubRepository], JSONResponse]:
client = GithubServiceImpl(user_id=github_user_id, token=github_user_token)
try:
repos: list[GitHubRepository] = await client.get_repositories(
Expand All @@ -47,7 +49,7 @@ async def get_github_repositories(
async def get_github_user(
github_user_id: str | None = Depends(get_user_id),
github_user_token: SecretStr | None = Depends(get_github_token),
):
) -> Union[GitHubUser, JSONResponse]:
client = GithubServiceImpl(user_id=github_user_id, token=github_user_token)
try:
user: GitHubUser = await client.get_user()
Expand All @@ -70,7 +72,7 @@ async def get_github_user(
async def get_github_installation_ids(
github_user_id: str | None = Depends(get_user_id),
github_user_token: SecretStr | None = Depends(get_github_token),
):
) -> Union[list[int], JSONResponse]:
client = GithubServiceImpl(user_id=github_user_id, token=github_user_token)
try:
installations_ids: list[int] = await client.get_installation_ids()
Expand All @@ -97,7 +99,7 @@ async def search_github_repositories(
order: str = 'desc',
github_user_id: str | None = Depends(get_user_id),
github_user_token: SecretStr | None = Depends(get_github_token),
):
) -> Union[list[GitHubRepository], JSONResponse]:
client = GithubServiceImpl(user_id=github_user_id, token=github_user_token)
try:
repos: list[GitHubRepository] = await client.search_repositories(
Expand Down
168 changes: 144 additions & 24 deletions openhands/server/routes/public.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import warnings
from typing import Annotated, Any, cast

import requests
from fastapi import APIRouter, Depends, Response
from fastapi.responses import JSONResponse
from fastapi.routing import APIRoute

from openhands.security.options import SecurityAnalyzers

with warnings.catch_warnings():
warnings.simplefilter('ignore')
import litellm

from fastapi import (
APIRouter,
)

from openhands.controller.agent import Agent
from openhands.core.config import LLMConfig
from openhands.core.logger import openhands_logger as logger
Expand All @@ -21,20 +21,14 @@
app = APIRouter(prefix='/api/options')


@app.get('/models')
async def get_litellm_models() -> list[str]:
async def get_litellm_models_list() -> list[str]:
"""Get all models supported by LiteLLM.
This function combines models from litellm and Bedrock, removing any
error-prone Bedrock models.
To get the models:
```sh
curl http://localhost:3000/api/litellm-models
```
Returns:
list: A sorted list of unique model names.
list[str]: A sorted list of unique model names.
"""
litellm_model_list = litellm.model_list + list(litellm.model_cost.keys())
litellm_model_list_without_bedrock = bedrock.remove_error_modelId(
Expand Down Expand Up @@ -74,41 +68,167 @@ async def get_litellm_models() -> list[str]:
return list(sorted(set(model_list)))


@app.get('/agents')
async def get_agents():
def get_models_route() -> APIRoute:
"""Get the route for getting models.
Returns:
APIRoute: The route for getting models.
"""
return cast(
APIRoute,
app.get('/models', response_model=list[str]),
)


async def get_litellm_models(
models: Annotated[list[str], Depends(get_litellm_models_list)],
) -> list[str]:
"""Get all models supported by LiteLLM.
To get the models:
```sh
curl http://localhost:3000/api/litellm-models
```
Args:
models (list[str]): The list of models from get_litellm_models_list.
Returns:
list[str]: A sorted list of unique model names.
"""
return models


models_route = get_models_route()
models_route.endpoint = get_litellm_models


async def get_agents_list() -> list[str]:
"""Get all agents supported by LiteLLM.
Returns:
list[str]: A sorted list of agent names.
"""
return sorted(Agent.list_agents())


def get_agents_route() -> APIRoute:
"""Get the route for getting agents.
Returns:
APIRoute: The route for getting agents.
"""
return cast(
APIRoute,
app.get('/agents', response_model=list[str]),
)


async def get_agents(
agents: Annotated[list[str], Depends(get_agents_list)],
) -> list[str]:
"""Get all agents supported by LiteLLM.
To get the agents:
```sh
curl http://localhost:3000/api/agents
```
Args:
agents (list[str]): The list of agents from get_agents_list.
Returns:
list: A sorted list of agent names.
list[str]: A sorted list of agent names.
"""
agents = sorted(Agent.list_agents())
return agents


@app.get('/security-analyzers')
async def get_security_analyzers():
agents_route = get_agents_route()
agents_route.endpoint = get_agents


async def get_security_analyzers_list() -> list[str]:
"""Get all supported security analyzers.
Returns:
list[str]: A sorted list of security analyzer names.
"""
return sorted(SecurityAnalyzers.keys())


def get_analyzers_route() -> APIRoute:
"""Get the route for getting security analyzers.
Returns:
APIRoute: The route for getting security analyzers.
"""
return cast(
APIRoute,
app.get('/security-analyzers', response_model=list[str]),
)


async def get_security_analyzers(
analyzers: Annotated[list[str], Depends(get_security_analyzers_list)],
) -> list[str]:
"""Get all supported security analyzers.
To get the security analyzers:
```sh
curl http://localhost:3000/api/security-analyzers
```
Args:
analyzers (list[str]): The list of analyzers from get_security_analyzers_list.
Returns:
list: A sorted list of security analyzer names.
list[str]: A sorted list of security analyzer names.
"""
return sorted(SecurityAnalyzers.keys())
return analyzers


analyzers_route = get_analyzers_route()
analyzers_route.endpoint = get_security_analyzers


async def get_server_config() -> Response:
"""Get current config.
Returns:
Response: The current server configuration.
"""
config_data = server_config.get_config()
return JSONResponse(
status_code=200,
content=config_data,
)


@app.get('/config')
async def get_config():
def get_config_route() -> APIRoute:
"""Get the route for getting config.
Returns:
APIRoute: The route for getting config.
"""
Get current config
return cast(
APIRoute,
app.get('/config', response_model=dict[str, Any]),
)


async def get_config(
response: Annotated[Response, Depends(get_server_config)],
) -> Response:
"""Get current config.
Args:
response (Response): The response from get_server_config.
Returns:
Response: The current server configuration.
"""
return response


return server_config.get_config()
config_route = get_config_route()
config_route.endpoint = get_config
48 changes: 42 additions & 6 deletions openhands/server/routes/security.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
from typing import Annotated, cast

from fastapi import (
APIRouter,
Depends,
HTTPException,
Request,
Response,
status,
)
from fastapi.routing import APIRoute

app = APIRouter(prefix='/api/conversations/{conversation_id}')


@app.route('/security/{path:path}', methods=['GET', 'POST', 'PUT', 'DELETE'])
async def security_api(request: Request):
"""Catch-all route for security analyzer API requests.
Each request is handled directly to the security analyzer.
async def get_response(request: Request) -> Response:
"""Get response from security analyzer.
Args:
request (Request): The incoming FastAPI request object.
Returns:
Any: The response from the security analyzer.
Response: The response from the security analyzer.
Raises:
HTTPException: If the security analyzer is not initialized.
Expand All @@ -32,3 +34,37 @@ async def security_api(request: Request):
return await request.state.conversation.security_analyzer.handle_api_request(
request
)


def get_route() -> APIRoute:
"""Get the route for the security API.
Returns:
APIRoute: The route for the security API.
"""
return cast(
APIRoute,
app.api_route(
'/security/{path:path}',
methods=['GET', 'POST', 'PUT', 'DELETE'],
response_model=None,
),
)


async def security_api(
response: Annotated[Response, Depends(get_response)],
) -> Response:
"""Catch-all route for security analyzer API requests.
Args:
response (Response): The response from the security analyzer.
Returns:
Response: The response from the security analyzer.
"""
return response


route = get_route()
route.endpoint = security_api
Loading

0 comments on commit d17df96

Please sign in to comment.