mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-14 14:12:44 +00:00
opentui(phase3): launcher integration — HERMES_TUI_ENGINE dual-engine
hermes --tui launches the native OpenTUI engine (Bun) when HERMES_TUI_ENGINE=opentui (env) or display.tui_engine=opentui (config); Ink stays the default and the shipping path is untouched. - _resolve_tui_engine() (env > config > ink); refuses opentui on Windows/Termux (no Bun) -> falls back to ink with a notice. - _make_opentui_argv() -> [bun, src/entry.real.tsx] (no build step). - _bun_bin() with HERMES_BUN override. - Branch at top of _make_tui_argv BEFORE _ensure_tui_node (Bun-only host must not bootstrap Node). - Gate _launch_tui NODE_OPTIONS/--max-old-space-size on engine==ink (Bun is JSC; the V8 flag errors/ignores). Verified end-to-end via tmux: real hermes --tui -> Bun -> OpenTUI -> real Python gateway streamed a real reply. No-flag default still ink.
This commit is contained in:
parent
24f74eb888
commit
2bd9c9b881
741 changed files with 17733 additions and 79889 deletions
|
|
@ -1,100 +0,0 @@
|
|||
"""Regression: the keyless Parallel web default must survive a failed sweep.
|
||||
|
||||
``web_search`` / ``web_extract`` are documented to work out of the box with
|
||||
zero setup via the bundled keyless Parallel free-MCP backend. That guarantee
|
||||
only holds if the bundled ``plugins/web/*`` providers are registered in
|
||||
``agent.web_search_registry``. The dispatch triggers the general plugin sweep
|
||||
(:func:`hermes_cli.plugins._ensure_plugins_discovered`) to do that — but the
|
||||
sweep can finish without registering them (its exception swallowed as a
|
||||
warning, a packaged layout where it ran before the bundled tree was
|
||||
importable, or a stale empty-discovery cache). When that happened, *both*
|
||||
tools dead-ended on "No web {search,extract} provider configured" even though
|
||||
no setup should be needed.
|
||||
|
||||
These tests pin the invariant that :func:`tools.web_tools._ensure_web_plugins_loaded`
|
||||
guarantees the keyless default is registered regardless of the sweep's outcome,
|
||||
and that the direct-registration fallback honors an explicit ``plugins.disabled``
|
||||
entry. Real imports from the bundled plugin modules — no provider mocking.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
import agent.web_search_registry as reg
|
||||
import hermes_cli.plugins as plugins
|
||||
from tools import web_tools
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _clean_registry():
|
||||
reg._reset_for_tests()
|
||||
yield
|
||||
reg._reset_for_tests()
|
||||
|
||||
|
||||
def _boom(*_a, **_k):
|
||||
raise RuntimeError("discovery boom")
|
||||
|
||||
|
||||
def test_keyless_default_registered_when_discovery_raises(monkeypatch):
|
||||
"""A swallowed discovery failure must not strand the keyless default."""
|
||||
monkeypatch.setattr(plugins, "_ensure_plugins_discovered", _boom)
|
||||
assert reg.get_provider("parallel") is None
|
||||
|
||||
web_tools._ensure_web_plugins_loaded()
|
||||
|
||||
parallel = reg.get_provider("parallel")
|
||||
assert parallel is not None, "keyless Parallel default not restored"
|
||||
# It is the universal keyless default precisely because it does both.
|
||||
assert parallel.supports_search()
|
||||
assert parallel.supports_extract()
|
||||
|
||||
|
||||
def test_fallback_registers_full_bundled_set(monkeypatch):
|
||||
"""The fix covers the whole bundled provider class, not just parallel."""
|
||||
monkeypatch.setattr(plugins, "_ensure_plugins_discovered", _boom)
|
||||
|
||||
web_tools._ensure_web_plugins_loaded()
|
||||
|
||||
names = {p.name for p in reg.list_providers()}
|
||||
# Every bundled backend a user might have configured should be reachable
|
||||
# again, so an explicit ``web.extract_backend: firecrawl`` etc. resolves.
|
||||
for expected in ("parallel", "firecrawl", "tavily", "exa"):
|
||||
assert expected in names, f"{expected} missing after fallback"
|
||||
|
||||
|
||||
def test_fallback_honors_explicit_disable(monkeypatch):
|
||||
"""A backend the user turned off via plugins.disabled stays off."""
|
||||
monkeypatch.setattr(plugins, "_get_disabled_plugins", lambda: {"web-parallel"})
|
||||
|
||||
web_tools._register_bundled_web_providers_directly()
|
||||
|
||||
names = {p.name for p in reg.list_providers()}
|
||||
assert "parallel" not in names, "explicit disable was ignored"
|
||||
# Other bundled backends are unaffected by the parallel disable.
|
||||
assert "tavily" in names
|
||||
|
||||
|
||||
def test_fallback_is_noop_when_discovery_already_registered(monkeypatch):
|
||||
"""Healthy path: don't pay for the direct sweep when parallel is present."""
|
||||
# Pretend the general sweep already registered the keyless default.
|
||||
import importlib
|
||||
|
||||
class _Ctx:
|
||||
def register_web_search_provider(self, provider):
|
||||
reg.register_provider(provider)
|
||||
|
||||
importlib.import_module("plugins.web.parallel").register(_Ctx())
|
||||
monkeypatch.setattr(plugins, "_ensure_plugins_discovered", lambda *a, **k: None)
|
||||
|
||||
calls = {"n": 0}
|
||||
real = web_tools._register_bundled_web_providers_directly
|
||||
|
||||
def _spy():
|
||||
calls["n"] += 1
|
||||
real()
|
||||
|
||||
monkeypatch.setattr(web_tools, "_register_bundled_web_providers_directly", _spy)
|
||||
web_tools._ensure_web_plugins_loaded()
|
||||
|
||||
assert calls["n"] == 0, "direct-registration ran on the healthy path"
|
||||
Loading…
Add table
Add a link
Reference in a new issue