(Backend) New Config Endpoint (#12460)

This commit is contained in:
Tim O'Farrell
2026-01-15 22:06:39 -07:00
committed by GitHub
parent 102715a3c9
commit c8594a2eaa
8 changed files with 111 additions and 2 deletions

View File

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

View File

@@ -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:

View File

@@ -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)

View File

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

View File

@@ -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."""

View 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

View 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

View File

@@ -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.
"""