Skip to content
Merged
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
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ up: validate-image $(EXAMPLE)/.env ## Run the example in engine mode: API on htt
$(COMPOSE) --profile engine up -d
@echo "engine: http://localhost:8090/health"

up-ui: validate-image $(EXAMPLE)/.env ## Run the example in manager mode: chat UI on http://localhost:8100/demo
up-ui: validate-image $(EXAMPLE)/.env ## Run the example in manager mode: playground on http://localhost:8100/playground
$(COMPOSE) --profile ui up -d
@echo "chat UI: http://localhost:8100/demo"
@echo "playground: http://localhost:8100/playground"

down: ## Stop the example stack.
$(COMPOSE) --profile engine --profile ui down
Expand Down
4 changes: 2 additions & 2 deletions src/agent_manager/api/web.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ def mount_web(app: FastAPI, settings: Settings) -> None:
def widget_js() -> FileResponse:
return FileResponse(STATIC_DIR / "widget.js", media_type="application/javascript")

@app.get("/demo")
def demo() -> FileResponse:
@app.get("/playground")
def playground() -> FileResponse:
return FileResponse(STATIC_DIR / "demo.html", media_type="text/html")

@app.get("/widget-demo.html")
Expand Down
15 changes: 14 additions & 1 deletion src/agent_manager/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@
from dotenv import load_dotenv


def _playground_url(host: str, port: int) -> str:
if host in {"0.0.0.0", "::"}:
display_host = "localhost"
elif ":" in host and not host.startswith("["):
display_host = f"[{host}]"
else:
display_host = host
return f"http://{display_host}:{port}/playground"


@click.command()
@click.option("--config", required=True, help="Path to agents.yml")
@click.option("--host", default=None, help="Host to bind to (overrides settings)")
Expand All @@ -35,7 +45,10 @@ def main(config: str, host: str | None, port: int | None, env: str | None, migra
upgrade_database()

app = create_app(config, settings)
uvicorn.run(app, host=host or settings.host, port=port or settings.port)
bind_host = host or settings.host
bind_port = port or settings.port
click.echo(f"Playground: {_playground_url(bind_host, bind_port)}")
uvicorn.run(app, host=bind_host, port=bind_port)


if __name__ == "__main__":
Expand Down
77 changes: 77 additions & 0 deletions tests/agent_manager/test_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"""Tests for the ``agent-manager`` startup message and bind options."""

from __future__ import annotations

from types import SimpleNamespace

import pytest
from click.testing import CliRunner

from agent_manager.cli import main


@pytest.fixture
def captured_run(monkeypatch: pytest.MonkeyPatch) -> dict[str, object]:
import uvicorn

captured: dict[str, object] = {}

def fake_create_app(config: str, settings: object) -> object:
captured["config"] = config
captured["settings"] = settings
return object()

def fake_run(app: object, host: str, port: int) -> None:
captured["app"] = app
captured["host"] = host
captured["port"] = port

monkeypatch.setattr("agent_manager.cli.load_dotenv", lambda path, override: None)
monkeypatch.setattr("agent_manager.api.create_app", fake_create_app)
monkeypatch.setattr(
"agent_manager.config.Settings",
lambda: SimpleNamespace(host="0.0.0.0", port=8100),
)
monkeypatch.setattr(uvicorn, "run", fake_run)
return captured


def test_startup_prints_clickable_playground_url(captured_run: dict[str, object]) -> None:
result = CliRunner().invoke(main, ["--config", "agents.yml", "--no-migrate"])

assert result.exit_code == 0, result.output
assert "Playground: http://localhost:8100/playground" in result.output
assert captured_run["host"] == "0.0.0.0"
assert captured_run["port"] == 8100


def test_startup_url_uses_host_and_port_overrides(captured_run: dict[str, object]) -> None:
result = CliRunner().invoke(
main,
[
"--config",
"agents.yml",
"--host",
"127.0.0.1",
"--port",
"8200",
"--no-migrate",
],
)

assert result.exit_code == 0, result.output
assert "Playground: http://127.0.0.1:8200/playground" in result.output
assert captured_run["host"] == "127.0.0.1"
assert captured_run["port"] == 8200


def test_startup_url_formats_ipv6_host(captured_run: dict[str, object]) -> None:
result = CliRunner().invoke(
main,
["--config", "agents.yml", "--host", "::1", "--no-migrate"],
)

assert result.exit_code == 0, result.output
assert "Playground: http://[::1]:8100/playground" in result.output
assert captured_run["host"] == "::1"
assert captured_run["port"] == 8100
8 changes: 6 additions & 2 deletions tests/agent_manager/test_web.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,17 @@ def test_widget_js_served_as_javascript(client: TestClient) -> None:
assert "agent-chat" in r.text


def test_demo_page_served_as_html(client: TestClient) -> None:
r = client.get("/demo")
def test_playground_page_served_as_html(client: TestClient) -> None:
r = client.get("/playground")
assert r.status_code == 200
assert "text/html" in r.headers["content-type"]
assert "<agent-chat" in r.text


def test_old_demo_route_is_not_served(client: TestClient) -> None:
assert client.get("/demo").status_code == 404


@pytest.mark.parametrize(
"path",
[
Expand Down
Loading