mirror of
https://github.com/OpenHands/OpenHands.git
synced 2026-03-22 13:47:19 +08:00
(Backend) New Config Endpoint (#12460)
This commit is contained in:
@@ -162,6 +162,7 @@ class SetAuthCookieMiddleware:
|
||||
'/api/email/resend',
|
||||
'/oauth/device/authorize',
|
||||
'/oauth/device/token',
|
||||
'/api/v1/web-client/config',
|
||||
)
|
||||
if path in ignore_paths:
|
||||
return False
|
||||
|
||||
@@ -48,7 +48,14 @@ from openhands.app_server.services.httpx_client_injector import HttpxClientInjec
|
||||
from openhands.app_server.services.injector import InjectorState
|
||||
from openhands.app_server.services.jwt_service import JwtService, JwtServiceInjector
|
||||
from openhands.app_server.user.user_context import UserContext, UserContextInjector
|
||||
from openhands.app_server.web_client.default_web_client_config_injector import (
|
||||
DefaultWebClientConfigInjector,
|
||||
)
|
||||
from openhands.app_server.web_client.web_client_config_injector import (
|
||||
WebClientConfigInjector,
|
||||
)
|
||||
from openhands.sdk.utils.models import OpenHandsModel
|
||||
from openhands.server.types import AppMode
|
||||
|
||||
|
||||
def get_default_persistence_dir() -> Path:
|
||||
@@ -114,9 +121,12 @@ class AppServerConfig(OpenHandsModel):
|
||||
persistence_dir=get_default_persistence_dir()
|
||||
)
|
||||
)
|
||||
|
||||
# Services
|
||||
lifespan: AppLifespanService | None = Field(default_factory=_get_default_lifespan)
|
||||
app_mode: AppMode = AppMode.OPENHANDS
|
||||
web_client: WebClientConfigInjector = Field(
|
||||
default_factory=DefaultWebClientConfigInjector
|
||||
)
|
||||
|
||||
|
||||
def config_from_env() -> AppServerConfig:
|
||||
|
||||
@@ -7,6 +7,7 @@ from openhands.app_server.event_callback import (
|
||||
)
|
||||
from openhands.app_server.sandbox import sandbox_router, sandbox_spec_router
|
||||
from openhands.app_server.user import user_router
|
||||
from openhands.app_server.web_client import web_client_router
|
||||
|
||||
# Include routers
|
||||
router = APIRouter(prefix='/api/v1')
|
||||
@@ -16,3 +17,4 @@ router.include_router(sandbox_router.router)
|
||||
router.include_router(sandbox_spec_router.router)
|
||||
router.include_router(user_router.router)
|
||||
router.include_router(webhook_router.router)
|
||||
router.include_router(web_client_router.router)
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import Field
|
||||
|
||||
from openhands.app_server.web_client.web_client_config_injector import (
|
||||
WebClientConfigInjector,
|
||||
)
|
||||
from openhands.app_server.web_client.web_client_models import (
|
||||
WebClientConfig,
|
||||
WebClientFeatureFlags,
|
||||
)
|
||||
from openhands.integrations.service_types import ProviderType
|
||||
|
||||
|
||||
class DefaultWebClientConfigInjector(WebClientConfigInjector):
|
||||
posthog_client_key: str | None = 'phc_3ESMmY9SgqEAGBB6sMGK5ayYHkeUuknH2vP6FmWH9RA'
|
||||
feature_flags: WebClientFeatureFlags = Field(default_factory=WebClientFeatureFlags)
|
||||
providers_configured: list[ProviderType] = Field(default_factory=list)
|
||||
maintenance_start_time: datetime | None = None
|
||||
auth_url: str | None = None
|
||||
recaptcha_site_key: str | None = None
|
||||
faulty_models: list[str] = Field(default_factory=list)
|
||||
error_message: str | None = None
|
||||
|
||||
async def get_web_client_config(self) -> WebClientConfig:
|
||||
from openhands.app_server.config import get_global_config
|
||||
|
||||
config = get_global_config()
|
||||
result = WebClientConfig(
|
||||
app_mode=config.app_mode,
|
||||
posthog_client_key=self.posthog_client_key,
|
||||
feature_flags=self.feature_flags,
|
||||
providers_configured=self.providers_configured,
|
||||
maintenance_start_time=self.maintenance_start_time,
|
||||
auth_url=self.auth_url,
|
||||
recaptcha_site_key=self.recaptcha_site_key,
|
||||
faulty_models=self.faulty_models,
|
||||
error_message=self.error_message,
|
||||
)
|
||||
return result
|
||||
@@ -0,0 +1,10 @@
|
||||
from abc import abstractmethod
|
||||
|
||||
from openhands.agent_server.env_parser import ABC, DiscriminatedUnionMixin
|
||||
from openhands.app_server.web_client.web_client_models import WebClientConfig
|
||||
|
||||
|
||||
class WebClientConfigInjector(DiscriminatedUnionMixin, ABC):
|
||||
@abstractmethod
|
||||
async def get_web_client_config(self) -> WebClientConfig:
|
||||
"""Get the current web client configuration."""
|
||||
27
openhands/app_server/web_client/web_client_models.py
Normal file
27
openhands/app_server/web_client/web_client_models.py
Normal file
@@ -0,0 +1,27 @@
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from openhands.agent_server.env_parser import DiscriminatedUnionMixin
|
||||
from openhands.integrations.service_types import ProviderType
|
||||
from openhands.server.types import AppMode
|
||||
|
||||
|
||||
class WebClientFeatureFlags(BaseModel):
|
||||
enable_billing: bool = False
|
||||
hide_llm_settings: bool = False
|
||||
enable_jira: bool = False
|
||||
enable_jira_dc: bool = False
|
||||
enable_linear: bool = False
|
||||
|
||||
|
||||
class WebClientConfig(DiscriminatedUnionMixin):
|
||||
app_mode: AppMode
|
||||
posthog_client_key: str | None
|
||||
feature_flags: WebClientFeatureFlags
|
||||
providers_configured: list[ProviderType]
|
||||
maintenance_start_time: datetime | None
|
||||
auth_url: str | None
|
||||
recaptcha_site_key: str | None
|
||||
faulty_models: list[str]
|
||||
error_message: str | None
|
||||
16
openhands/app_server/web_client/web_client_router.py
Normal file
16
openhands/app_server/web_client/web_client_router.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from fastapi import APIRouter
|
||||
|
||||
from openhands.app_server.config import get_global_config
|
||||
from openhands.app_server.web_client.web_client_models import WebClientConfig
|
||||
|
||||
router = APIRouter(prefix='/web-client', tags=['Config'])
|
||||
|
||||
|
||||
@router.get('/config')
|
||||
async def get_web_client_config() -> WebClientConfig:
|
||||
"""Get the configuration of the web client. This endpoint is typically one of the first
|
||||
invoked, and does not require authentication. It provides general settings for the
|
||||
web client independent of users."""
|
||||
config = get_global_config()
|
||||
result = await config.web_client.get_web_client_config()
|
||||
return result
|
||||
@@ -67,10 +67,13 @@ async def get_security_analyzers() -> list[str]:
|
||||
return sorted(SecurityAnalyzers.keys())
|
||||
|
||||
|
||||
@app.get('/config', response_model=dict[str, Any])
|
||||
@app.get('/config', response_model=dict[str, Any], deprecated=True)
|
||||
async def get_config() -> dict[str, Any]:
|
||||
"""Get current config.
|
||||
|
||||
This method has been replaced with the /v1/web-client/config endpoint,
|
||||
and will be removed as part of the V0 cleanup on 2026-04-01
|
||||
|
||||
Returns:
|
||||
dict[str, Any]: The current server configuration.
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user