Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion openhands-agent-server/openhands/agent_server/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from openhands.agent_server.env_parser import from_env
from openhands.sdk.utils.cipher import Cipher
from openhands.sdk.utils.deprecation import warn_deprecated


# Environment variable constants
Expand Down Expand Up @@ -47,6 +48,24 @@ def _default_secret_key() -> SecretStr | None:
return None


def _default_web_url() -> str | None:
web_url = os.getenv("OH_WEB_URL")
if web_url:
return web_url

legacy_web_url = os.getenv(V0_RUNTIME_URL)
if not legacy_web_url:
return None

warn_deprecated(
"RUNTIME_URL environment variable",
deprecated_in="1.14.0",
removed_in="1.19.0",
details="Use OH_WEB_URL instead.",
)
return legacy_web_url


class WebhookSpec(BaseModel):
"""Spec to create a webhook. All webhook requests use POST method."""

Expand Down Expand Up @@ -165,7 +184,7 @@ class Config(BaseModel):
),
)
web_url: str | None = Field(
default_factory=lambda: os.getenv(V0_RUNTIME_URL),
default_factory=_default_web_url,
description=(
"The URL where this agent server instance is available externally"
),
Expand Down
56 changes: 49 additions & 7 deletions tests/agent_server/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,24 @@

import asyncio
import tempfile
import warnings
from pathlib import Path
from unittest.mock import AsyncMock, patch

import pytest
from deprecation import DeprecatedWarning
from fastapi.testclient import TestClient

from openhands.agent_server.api import _get_root_path, api_lifespan, create_app
from openhands.agent_server.config import Config


@pytest.fixture(autouse=True)
def clear_web_url_env(monkeypatch):
monkeypatch.delenv("OH_WEB_URL", raising=False)
monkeypatch.delenv("RUNTIME_URL", raising=False)


class TestStaticFilesServing:
"""Test static files serving functionality."""

Expand Down Expand Up @@ -403,21 +411,55 @@ class TestConfigWebUrl:
"""Tests for web_url configuration field."""

def test_web_url_default_is_none_when_env_not_set(self):
"""Test that web_url defaults to None when RUNTIME_URL is not set."""
# Ensure the env var is not set
"""Test that web_url defaults to None when no env vars are set."""
with patch.dict("os.environ", {}, clear=True):
config = Config()
assert config.web_url is None

def test_web_url_reads_from_runtime_url_env(self):
"""Test that web_url reads from RUNTIME_URL environment variable."""
with patch.dict("os.environ", {"RUNTIME_URL": "https://test.example.com/path"}):
def test_web_url_reads_from_oh_web_url_env(self):
"""Test that web_url reads from the canonical OH_WEB_URL env var."""
with patch.dict("os.environ", {"OH_WEB_URL": "https://test.example.com/path"}):
config = Config()
assert config.web_url == "https://test.example.com/path"

def test_web_url_reads_from_runtime_url_env_with_warning(self):
"""Test that legacy RUNTIME_URL still works but emits a deprecation warning."""
with patch.dict("os.environ", {"RUNTIME_URL": "https://test.example.com/path"}):
with pytest.warns(DeprecatedWarning) as caught:
config = Config()

assert config.web_url == "https://test.example.com/path"
assert "RUNTIME_URL environment variable is deprecated" in str(
caught[0].message
)
assert "OH_WEB_URL" in str(caught[0].message)
assert "removed in 1.19.0" in str(caught[0].message)

def test_web_url_prefers_oh_web_url_over_runtime_url(self):
"""Test that the canonical env var wins without warnings."""
with patch.dict(
"os.environ",
{
"OH_WEB_URL": "https://preferred.example.com/path",
"RUNTIME_URL": "https://legacy.example.com/path",
},
):
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always")
config = Config()

assert config.web_url == "https://preferred.example.com/path"
assert caught == []

def test_web_url_can_be_set_explicitly(self):
"""Test that web_url can be set explicitly, overriding env var."""
with patch.dict("os.environ", {"RUNTIME_URL": "https://env.example.com"}):
"""Test that web_url can be set explicitly, overriding env vars."""
with patch.dict(
"os.environ",
{
"OH_WEB_URL": "https://env.example.com/oh",
"RUNTIME_URL": "https://env.example.com/runtime",
},
):
config = Config(web_url="https://explicit.example.com/custom")
assert config.web_url == "https://explicit.example.com/custom"

Expand Down
Loading