feat(gui): route embedded TUI through dashboard gateway (#21979)
Inject HERMES_TUI_GATEWAY_URL into dashboard PTY sessions so embedded ui-tui instances attach to the in-process websocket gateway, with coverage for the new env wiring.
This commit is contained in:
@@ -3284,6 +3284,10 @@ def _resolve_chat_argv(
|
|||||||
Appending ``--resume <id>`` to argv doesn't work because ``ui-tui`` does
|
Appending ``--resume <id>`` to argv doesn't work because ``ui-tui`` does
|
||||||
not parse its argv.
|
not parse its argv.
|
||||||
|
|
||||||
|
``HERMES_TUI_GATEWAY_URL`` is injected so the PTY child can attach to
|
||||||
|
this process's in-memory ``tui_gateway`` instance instead of spawning
|
||||||
|
its own Python gateway subprocess.
|
||||||
|
|
||||||
`sidecar_url` (when set) is forwarded as ``HERMES_TUI_SIDECAR_URL`` so
|
`sidecar_url` (when set) is forwarded as ``HERMES_TUI_SIDECAR_URL`` so
|
||||||
the spawned ``tui_gateway.entry`` can mirror dispatcher emits to the
|
the spawned ``tui_gateway.entry`` can mirror dispatcher emits to the
|
||||||
dashboard's ``/api/pub`` endpoint (see :func:`pub_ws`).
|
dashboard's ``/api/pub`` endpoint (see :func:`pub_ws`).
|
||||||
@@ -3310,9 +3314,26 @@ def _resolve_chat_argv(
|
|||||||
if sidecar_url:
|
if sidecar_url:
|
||||||
env["HERMES_TUI_SIDECAR_URL"] = sidecar_url
|
env["HERMES_TUI_SIDECAR_URL"] = sidecar_url
|
||||||
|
|
||||||
|
if gateway_ws_url := _build_gateway_ws_url():
|
||||||
|
env["HERMES_TUI_GATEWAY_URL"] = gateway_ws_url
|
||||||
|
|
||||||
return list(argv), str(cwd) if cwd else None, env
|
return list(argv), str(cwd) if cwd else None, env
|
||||||
|
|
||||||
|
|
||||||
|
def _build_gateway_ws_url() -> Optional[str]:
|
||||||
|
"""ws:// URL the PTY child should attach to for JSON-RPC gateway traffic."""
|
||||||
|
host = getattr(app.state, "bound_host", None)
|
||||||
|
port = getattr(app.state, "bound_port", None)
|
||||||
|
|
||||||
|
if not host or not port:
|
||||||
|
return None
|
||||||
|
|
||||||
|
netloc = f"[{host}]:{port}" if ":" in host and not host.startswith("[") else f"{host}:{port}"
|
||||||
|
qs = urllib.parse.urlencode({"token": _SESSION_TOKEN})
|
||||||
|
|
||||||
|
return f"ws://{netloc}/api/ws?{qs}"
|
||||||
|
|
||||||
|
|
||||||
def _build_sidecar_url(channel: str) -> Optional[str]:
|
def _build_sidecar_url(channel: str) -> Optional[str]:
|
||||||
"""ws:// URL the PTY child should publish events to, or None when unbound."""
|
"""ws:// URL the PTY child should publish events to, or None when unbound."""
|
||||||
host = getattr(app.state, "bound_host", None)
|
host = getattr(app.state, "bound_host", None)
|
||||||
|
|||||||
@@ -2257,3 +2257,23 @@ class TestPtyWebSocket:
|
|||||||
):
|
):
|
||||||
pass
|
pass
|
||||||
assert exc.value.code == 4400
|
assert exc.value.code == 4400
|
||||||
|
|
||||||
|
|
||||||
|
def test_resolve_chat_argv_injects_gateway_ws_url(monkeypatch):
|
||||||
|
import hermes_cli.main as cli_main
|
||||||
|
import hermes_cli.web_server as ws
|
||||||
|
|
||||||
|
monkeypatch.setattr(
|
||||||
|
cli_main,
|
||||||
|
"_make_tui_argv",
|
||||||
|
lambda *_args, **_kwargs: (["node", "fake-tui.js"], Path("/tmp")),
|
||||||
|
)
|
||||||
|
monkeypatch.setattr(ws.app.state, "bound_host", "127.0.0.1", raising=False)
|
||||||
|
monkeypatch.setattr(ws.app.state, "bound_port", 9119, raising=False)
|
||||||
|
|
||||||
|
_argv, _cwd, env = ws._resolve_chat_argv()
|
||||||
|
|
||||||
|
assert env is not None
|
||||||
|
gateway_url = env.get("HERMES_TUI_GATEWAY_URL", "")
|
||||||
|
assert gateway_url.startswith("ws://127.0.0.1:9119/api/ws?")
|
||||||
|
assert "token=" in gateway_url
|
||||||
|
|||||||
Reference in New Issue
Block a user