* fix: Home Assistant event filtering now closed by default Previously, when no watch_domains or watch_entities were configured, ALL state_changed events passed through to the agent, causing users to be flooded with notifications for every HA entity change. Now events are dropped by default unless the user explicitly configures: - watch_domains: list of domains to monitor (e.g. climate, light) - watch_entities: list of specific entity IDs to monitor - watch_all: true (new option — opt-in to receive all events) A warning is logged at connect time if no filters are configured, guiding users to set up their HA platform config. All 49 gateway HA tests + 52 HA tool tests pass. * docs: update Home Assistant integration documentation - homeassistant.md: Fix event filtering docs to reflect closed-by-default behavior. Add watch_all option. Replace Python dict config example with YAML. Fix defaults table (was incorrectly showing 'all'). Add required configuration warning admonition. - environment-variables.md: Add HASS_TOKEN and HASS_URL to Messaging section. - messaging/index.md: Add Home Assistant to description, architecture diagram, platform toolsets table, and Next Steps links. * fix(terminal): strip provider env vars from background and PTY subprocesses Extends the env var blocklist from #1157 to also cover the two remaining leaky paths in process_registry.py: - spawn_local() PTY path (line 156) - spawn_local() background Popen path (line 197) Both were still using raw os.environ, leaking provider vars to background processes and interactive PTY sessions. Now uses the same dynamic _HERMES_PROVIDER_ENV_BLOCKLIST from local.py. Explicit env_vars passed to spawn_local() still override the blocklist, matching the existing behavior for callers that intentionally need these. Gap identified by PR #1004 (@PeterFile). * feat(delegate): add observability metadata to subagent results Enrich delegate_task results with metadata from the child AIAgent: - model: which model the child used - exit_reason: completed | interrupted | max_iterations - tokens.input / tokens.output: token counts - tool_trace: per-tool-call trace with byte sizes and ok/error status Tool trace uses tool_call_id matching to correctly pair parallel tool calls with their results, with a fallback for messages without IDs. Cherry-picked from PR #872 by @omerkaz, with fixes: - Fixed parallel tool call trace pairing (was always updating last entry) - Removed redundant 'iterations' field (identical to existing 'api_calls') - Added test for parallel tool call trace correctness Co-authored-by: omerkaz <omerkaz@users.noreply.github.com> * feat(stt): add free local whisper transcription via faster-whisper Replace OpenAI-only STT with a dual-provider system mirroring the TTS architecture (Edge TTS free / ElevenLabs paid): STT: faster-whisper local (free, default) / OpenAI Whisper API (paid) Changes: - tools/transcription_tools.py: Full rewrite with provider dispatch, config loading, local faster-whisper backend, and OpenAI API backend. Auto-downloads model (~150MB for 'base') on first voice message. Singleton model instance reused across calls. - pyproject.toml: Add faster-whisper>=1.0.0 as core dependency - hermes_cli/config.py: Expand stt config to match TTS pattern with provider selection and per-provider model settings - agent/context_compressor.py: Fix .strip() crash when LLM returns non-string content (dict from llama.cpp, None). Fixes #1100 partially. - tests/: 23 new tests for STT providers + 2 for compressor fix - docs/: Updated Voice & TTS page with STT provider table, model sizes, config examples, and fallback behavior Fallback behavior: - Local not installed → OpenAI API (if key set) - OpenAI key not set → local whisper (if installed) - Neither → graceful error message to user Co-authored-by: Jah-yee <Jah-yee@users.noreply.github.com> --------- Co-authored-by: omerkaz <omerkaz@users.noreply.github.com> Co-authored-by: Jah-yee <Jah-yee@users.noreply.github.com>
97 lines
2.8 KiB
TOML
97 lines
2.8 KiB
TOML
[build-system]
|
|
requires = ["setuptools>=61.0"]
|
|
build-backend = "setuptools.build_meta"
|
|
|
|
[project]
|
|
name = "hermes-agent"
|
|
version = "0.2.0"
|
|
description = "The self-improving AI agent — creates skills from experience, improves them during use, and runs anywhere"
|
|
readme = "README.md"
|
|
requires-python = ">=3.11"
|
|
authors = [{ name = "Nous Research" }]
|
|
license = { text = "MIT" }
|
|
dependencies = [
|
|
# Core
|
|
"openai",
|
|
"anthropic>=0.39.0",
|
|
"python-dotenv",
|
|
"fire",
|
|
"httpx",
|
|
"rich",
|
|
"tenacity",
|
|
"pyyaml",
|
|
"requests",
|
|
"jinja2",
|
|
"pydantic>=2.0",
|
|
# Interactive CLI (prompt_toolkit is used directly by cli.py)
|
|
"prompt_toolkit",
|
|
# Tools
|
|
"firecrawl-py",
|
|
"fal-client",
|
|
# Text-to-speech (Edge TTS is free, no API key needed)
|
|
"edge-tts",
|
|
"faster-whisper>=1.0.0",
|
|
# mini-swe-agent deps (terminal tool)
|
|
"litellm>=1.75.5",
|
|
"typer",
|
|
"platformdirs",
|
|
# Skills Hub (GitHub App JWT auth — optional, only needed for bot identity)
|
|
"PyJWT[crypto]",
|
|
]
|
|
|
|
[project.optional-dependencies]
|
|
modal = ["swe-rex[modal]>=1.4.0"]
|
|
daytona = ["daytona>=0.148.0"]
|
|
dev = ["pytest", "pytest-asyncio", "pytest-xdist", "mcp>=1.2.0"]
|
|
messaging = ["python-telegram-bot>=20.0", "discord.py>=2.0", "aiohttp>=3.9.0", "slack-bolt>=1.18.0", "slack-sdk>=3.27.0"]
|
|
cron = ["croniter"]
|
|
slack = ["slack-bolt>=1.18.0", "slack-sdk>=3.27.0"]
|
|
cli = ["simple-term-menu"]
|
|
tts-premium = ["elevenlabs"]
|
|
pty = [
|
|
"ptyprocess>=0.7.0; sys_platform != 'win32'",
|
|
"pywinpty>=2.0.0; sys_platform == 'win32'",
|
|
]
|
|
honcho = ["honcho-ai>=2.0.1"]
|
|
mcp = ["mcp>=1.2.0"]
|
|
homeassistant = ["aiohttp>=3.9.0"]
|
|
rl = [
|
|
"atroposlib @ git+https://github.com/NousResearch/atropos.git",
|
|
"tinker @ git+https://github.com/thinking-machines-lab/tinker.git",
|
|
"fastapi>=0.104.0",
|
|
"uvicorn[standard]>=0.24.0",
|
|
"wandb>=0.15.0",
|
|
]
|
|
yc-bench = ["yc-bench @ git+https://github.com/collinear-ai/yc-bench.git"]
|
|
all = [
|
|
"hermes-agent[modal]",
|
|
"hermes-agent[daytona]",
|
|
"hermes-agent[messaging]",
|
|
"hermes-agent[cron]",
|
|
"hermes-agent[cli]",
|
|
"hermes-agent[dev]",
|
|
"hermes-agent[tts-premium]",
|
|
"hermes-agent[slack]",
|
|
"hermes-agent[pty]",
|
|
"hermes-agent[honcho]",
|
|
"hermes-agent[mcp]",
|
|
"hermes-agent[homeassistant]",
|
|
]
|
|
|
|
[project.scripts]
|
|
hermes = "hermes_cli.main:main"
|
|
hermes-agent = "run_agent:main"
|
|
|
|
[tool.setuptools]
|
|
py-modules = ["run_agent", "model_tools", "toolsets", "batch_runner", "trajectory_compressor", "toolset_distributions", "cli", "hermes_constants", "hermes_state", "hermes_time", "mini_swe_runner", "rl_cli", "utils"]
|
|
|
|
[tool.setuptools.packages.find]
|
|
include = ["agent", "tools", "tools.*", "hermes_cli", "gateway", "gateway.*", "cron", "honcho_integration"]
|
|
|
|
[tool.pytest.ini_options]
|
|
testpaths = ["tests"]
|
|
markers = [
|
|
"integration: marks tests requiring external services (API keys, Modal, etc.)",
|
|
]
|
|
addopts = "-m 'not integration' -n auto"
|