diff --git a/reme/application.py b/reme/application.py index aeccc5b4..a0e763f5 100644 --- a/reme/application.py +++ b/reme/application.py @@ -26,18 +26,17 @@ class Application(BaseComponent): self._started_components: list[BaseComponent] = [] self._setup_workspace_directories() - - if self.config.enable_logo: - print_logo(self.config) logger = get_logger( log_to_console=self.config.log_to_console, log_to_file=self.config.log_to_file, force_init=True, ) - logger.info(f"Initializing {self.config.app_name} Application v{__version__}") super().__init__() - self._init_service() + + if self.config.enable_logo: + print_logo(self.config, self.context.service) + logger.info(f"Initializing {self.config.app_name} Application v{__version__}") self._init_components() self._init_jobs() diff --git a/reme/utils/logo_utils.py b/reme/utils/logo_utils.py index b4795330..ef016aba 100644 --- a/reme/utils/logo_utils.py +++ b/reme/utils/logo_utils.py @@ -10,7 +10,10 @@ from rich.panel import Panel from rich.table import Table from rich.text import Text +from ..constants import REME_DEFAULT_HOST, REME_DEFAULT_PORT + if TYPE_CHECKING: + from ..components.service import BaseService from ..schema import ApplicationConfig @@ -28,7 +31,7 @@ def _hsv_rgb(h: float, s: float = 0.85, v: float = 0.98) -> tuple[int, int, int] return int(r * 255), int(g * 255), int(b * 255) -def print_logo(app_config: "ApplicationConfig"): +def print_logo(app_config: "ApplicationConfig", runtime_service: "BaseService | None" = None): """Print rainbow ASCII logo and runtime config (backend, URL, versions). Color: each startup picks a random hue rotation; both horizontal @@ -73,16 +76,16 @@ def print_logo(app_config: "ApplicationConfig"): match backend: case "http": - host = extra.get("host", "localhost") - port = extra.get("port", 8000) + host = getattr(runtime_service, "host", extra.get("host", REME_DEFAULT_HOST)) + port = getattr(runtime_service, "port", extra.get("port", REME_DEFAULT_PORT)) info_table.add_row("🔗", "URL:", f"http://{host}:{port}") info_table.add_row("📚", "FastAPI:", Text(get_version("fastapi"), style="dim")) case "mcp": - transport = extra.get("transport", "stdio") + transport = getattr(runtime_service, "transport", extra.get("transport", "sse")) info_table.add_row("🚌", "Transport:", transport) if transport != "stdio": - host = extra.get("host", "localhost") - port = extra.get("port", 8000) + host = getattr(runtime_service, "host", extra.get("host", REME_DEFAULT_HOST)) + port = getattr(runtime_service, "port", extra.get("port", REME_DEFAULT_PORT)) url = f"http://{host}:{port}" if transport == "sse": url += "/sse" diff --git a/tests/unit/test_logo_utils.py b/tests/unit/test_logo_utils.py new file mode 100644 index 00000000..23757ee5 --- /dev/null +++ b/tests/unit/test_logo_utils.py @@ -0,0 +1,86 @@ +"""Startup logo metadata tests.""" + +from io import StringIO +from types import SimpleNamespace + +from rich.console import Console + +from reme import application as application_module +from reme.application import Application +from reme.constants import REME_DEFAULT_HOST, REME_DEFAULT_PORT +from reme.schema import ApplicationConfig, ComponentConfig +from reme.utils import logo_utils + + +def _render_logo(monkeypatch, config: ApplicationConfig, runtime_service=None) -> str: + output = StringIO() + console = Console(file=output, force_terminal=False, width=120) + monkeypatch.setattr(logo_utils, "Console", lambda: console) + + logo_utils.print_logo(config, runtime_service) + + return output.getvalue() + + +def test_logo_uses_runtime_http_address(monkeypatch) -> None: + """Display the address resolved by the instantiated service.""" + config = ApplicationConfig(service=ComponentConfig(backend="http")) + runtime_service = SimpleNamespace(host="0.0.0.0", port=8123) + + output = _render_logo(monkeypatch, config, runtime_service) + + assert "http://0.0.0.0:8123" in output + + +def test_logo_fallback_matches_service_defaults(monkeypatch) -> None: + """Keep direct print_logo callers aligned with service defaults.""" + config = ApplicationConfig(service=ComponentConfig(backend="http")) + + output = _render_logo(monkeypatch, config) + + assert f"http://{REME_DEFAULT_HOST}:{REME_DEFAULT_PORT}" in output + + +def test_logo_uses_runtime_mcp_transport_and_address(monkeypatch) -> None: + """Display the transport resolved by the instantiated MCP service.""" + config = ApplicationConfig(service=ComponentConfig(backend="mcp")) + runtime_service = SimpleNamespace(transport="sse", host="0.0.0.0", port=8123) + + output = _render_logo(monkeypatch, config, runtime_service) + + assert "Transport: sse" in output + assert "http://0.0.0.0:8123/sse" in output + + +def test_logo_mcp_fallback_matches_service_defaults(monkeypatch) -> None: + """Keep direct print_logo callers aligned with MCP service defaults.""" + config = ApplicationConfig(service=ComponentConfig(backend="mcp")) + + output = _render_logo(monkeypatch, config) + + assert "Transport: sse" in output + assert f"http://{REME_DEFAULT_HOST}:{REME_DEFAULT_PORT}/sse" in output + + +def test_application_passes_instantiated_service_to_logo(monkeypatch, tmp_path) -> None: + """Render the service address after backend defaults and overrides resolve.""" + captured = {} + monkeypatch.setattr(Application, "_init_components", lambda self: None) + monkeypatch.setattr(Application, "_init_jobs", lambda self: None) + monkeypatch.setattr( + application_module, + "print_logo", + lambda config, runtime_service: captured.update( + host=runtime_service.host, + port=runtime_service.port, + ), + ) + + Application( + workspace_dir=str(tmp_path), + service={"backend": "http", "host": "0.0.0.0", "port": 8123}, + log_to_console=False, + log_to_file=False, + ) + + assert captured == {"host": "0.0.0.0", "port": 8123} diff --git a/website/README.md b/website/README.md index b680d7f4..28f52f9d 100644 --- a/website/README.md +++ b/website/README.md @@ -6,7 +6,7 @@ ReMe Studio is the local web workspace for ReMe. It lets you browse and edit use links, and chat with the ReMe Agent without moving durable memory into a separate application database. Search indexes, graphs, and other derived metadata remain rebuildable from the source files. -![ReMe Studio workspace](./public/og.png) +![ReMe Studio workspace](./public/og.jpg) ## Features diff --git a/website/README_ZH.md b/website/README_ZH.md index 27493578..75ec6054 100644 --- a/website/README_ZH.md +++ b/website/README_ZH.md @@ -5,7 +5,7 @@ ReMe Studio 是 ReMe 的本地 Web 工作区。你可以在这里浏览和编辑自己拥有的工作区文件、探索记忆之间的联系,并与 ReMe Agent 对话,而无需将持久记忆迁移到独立的应用数据库中。搜索索引、图谱和其他派生元数据均可根据源文件重建。 -![ReMe Studio 工作区](./public/og.png) +![ReMe Studio 工作区](./public/og.jpg) ## 功能 diff --git a/website/app/layout.tsx b/website/app/layout.tsx index 0d17ed64..705de075 100644 --- a/website/app/layout.tsx +++ b/website/app/layout.tsx @@ -31,9 +31,9 @@ export async function generateMetadata(): Promise { description: "本地优先的 Agent 记忆工作区", images: [ { - url: "/og.png", - width: 1731, - height: 909, + url: "/og.jpg", + width: 1200, + height: 626, alt: "ReMe Studio memory workspace", }, ], @@ -42,7 +42,7 @@ export async function generateMetadata(): Promise { card: "summary_large_image", title: "ReMe Studio", description: "本地优先的 Agent 记忆工作区", - images: ["/og.png"], + images: ["/og.jpg"], }, }; } diff --git a/website/public/og.jpg b/website/public/og.jpg new file mode 100644 index 00000000..786cd0ac Binary files /dev/null and b/website/public/og.jpg differ diff --git a/website/public/og.png b/website/public/og.png deleted file mode 100644 index 455bc0dc..00000000 Binary files a/website/public/og.png and /dev/null differ