mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-08 13:12:08 +00:00
Move provider adapters (anthropic, bedrock, azure), platform adapters (telegram, slack, discord, feishu, dingtalk, matrix), and terminal backends (modal, daytona) out of core into plugins/ workspace members. Core references them via the plugin registries (get_provider_namespace / get_provider_service / get_tool_provider / get_credential_pool_hook) instead of direct imports. - Provider/platform/terminal adapters relocated under plugins/; pyproject extras reference workspace members; nix variants aggregate per-platform extras. - Anthropic credential discovery + OAuth-masquerade guard live in the plugin's credential_pool_hook; browser-open guarded by _can_open_graphical_browser. - Vercel AI Gateway + Vercel Sandbox removed (upstream deletion); get_bedrock_model_ids removed (replaced by bedrock_model_ids_or_none + discover_bedrock_models). - Terminal backends resolve ModalEnvironment / DaytonaEnvironment lazily from the plugin registry. - uv.lock regenerated against the pluginified workspace. Plugin test suites updated for the relocation: imports point at hermes_agent_<plat>.adapter, caplog logger-name filters and monkeypatch targets use the new module paths, and credential/rollback tests patch registries.get_provider_service rather than the removed agent.*_adapter modules. Verified: zero dead imports of relocated modules in core (import smoke test + rename-map grep); nix develop succeeds; targeted plugin suites green (bedrock, anthropic-auxiliary, matrix, dingtalk, feishu, credential_pool, switch_model_rollback). Remaining full-suite failures are pre-existing on the pre-merge tree (telegram setUpModule __code__) or environmental (voice/media/ PTY/network-dependent), not introduced here.
63 lines
2.7 KiB
Python
63 lines
2.7 KiB
Python
from pathlib import Path
|
|
import tomllib
|
|
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
|
|
def test_faster_whisper_is_not_a_base_dependency():
|
|
data = tomllib.loads((REPO_ROOT / "pyproject.toml").read_text(encoding="utf-8"))
|
|
deps = data["project"]["dependencies"]
|
|
|
|
assert not any(dep.startswith("faster-whisper") for dep in deps)
|
|
|
|
# faster-whisper now lives in the stt plugin, not the root voice extra
|
|
stt_plugin = tomllib.loads((REPO_ROOT / "plugins/stt/pyproject.toml").read_text(encoding="utf-8"))
|
|
stt_deps = stt_plugin["project"]["dependencies"]
|
|
assert any(dep.startswith("faster-whisper") for dep in stt_deps)
|
|
|
|
|
|
def test_manifest_includes_bundled_skills():
|
|
manifest = (REPO_ROOT / "MANIFEST.in").read_text(encoding="utf-8")
|
|
|
|
assert "graft skills" in manifest
|
|
assert "graft optional-skills" in manifest
|
|
|
|
|
|
def test_bundled_plugin_manifests_ship_in_both_wheel_and_sdist():
|
|
"""Regression test for #34034 / #28149.
|
|
|
|
Plugin discovery (hermes_cli/plugins.py) registers each bundled plugin by
|
|
reading its ``plugin.yaml`` / ``plugin.yml`` manifest. Those manifests are
|
|
data files, not Python modules, so they only reach installed packages when
|
|
declared explicitly:
|
|
|
|
- wheel -> ``[tool.setuptools.package-data]`` ``plugins`` glob
|
|
- sdist -> ``MANIFEST.in`` (Homebrew and other downstream packagers build
|
|
from the sdist)
|
|
|
|
v0.15.0 declared neither, so the wheel shipped every adapter's Python code
|
|
but none of its manifests, and *every* gateway platform failed with
|
|
"No adapter available for <platform>". Both channels must cover manifests.
|
|
"""
|
|
# There must actually be manifests on disk for the globs to match.
|
|
on_disk = list((REPO_ROOT / "plugins").rglob("plugin.yaml")) + list(
|
|
(REPO_ROOT / "plugins").rglob("plugin.yml")
|
|
)
|
|
assert on_disk, "expected bundled plugin manifests under plugins/"
|
|
|
|
# Wheel channel: package-data must declare a glob that matches plugin
|
|
# manifests anywhere under the plugins package.
|
|
data = tomllib.loads((REPO_ROOT / "pyproject.toml").read_text(encoding="utf-8"))
|
|
plugins_pkg_data = data["tool"]["setuptools"]["package-data"].get("plugins", [])
|
|
assert any(
|
|
g.endswith("plugin.yaml") or g.endswith("plugin.yml")
|
|
for g in plugins_pkg_data
|
|
), "pyproject package-data 'plugins' must ship plugin.yaml/plugin.yml (wheel)"
|
|
|
|
# Sdist channel: MANIFEST.in must recursively include the manifests so
|
|
# downstream packagers building from the sdist also get them.
|
|
manifest = (REPO_ROOT / "MANIFEST.in").read_text(encoding="utf-8")
|
|
assert "recursive-include plugins" in manifest and "plugin.yaml" in manifest, (
|
|
"MANIFEST.in must recursive-include plugins plugin.yaml/plugin.yml (sdist)"
|
|
)
|