mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-09 03:11:58 +00:00
Turns the existing 'all lints disabled' stance into 'exactly one lint
enabled' — PLW1514 (unspecified-encoding) catches bare open() /
read_text() / write_text() calls that default to locale encoding on
Windows (cp1252), silently corrupting non-ASCII content.
Changes:
1. pyproject.toml
- Migrate [tool.ruff] top-level select → [tool.ruff.lint].select
(deprecated config location, ruff was warning on every run)
- Add preview = true (PLW1514 is a preview rule in ruff 0.15.x)
- select = ['PLW1514'] (exactly one rule, deliberately minimal)
- per-file-ignores exempt tests/, plugins/, skills/, optional-skills/ —
those have their own conventions or intentionally exercise edge cases
2. website/scripts/extract-skills.py
- Fix 3 remaining bare opens (website/ was excluded from the main
sweep but needed for ruff check . to go green)
3. tests/test_lint_config.py (new, 5 tests)
- Guards against accidental rule removal. If someone deletes PLW1514
from the select list or disables preview mode, these tests fail
with a loud message explaining why the rule exists.
Paired with a companion commit (held locally for now, pending a token
with workflow scope) that adds a blocking ruff step to .github/workflows/
lint.yml. Without that companion commit, ruff is configured correctly
but nothing in CI enforces it yet — the advisory PR comment will still
surface new PLW1514 violations though, so authors see them.
Verified: ruff check . → exit 0, 0 violations across the repo.
Test suite: 90 passed, 14 skipped, 0 failed.
217 lines
8.2 KiB
TOML
217 lines
8.2 KiB
TOML
[build-system]
|
|
requires = ["setuptools>=61.0"]
|
|
build-backend = "setuptools.build_meta"
|
|
|
|
[project]
|
|
name = "hermes-agent"
|
|
version = "0.13.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 — pinned to known-good ranges to limit supply chain attack surface
|
|
"openai>=2.21.0,<3",
|
|
"anthropic>=0.39.0,<1",
|
|
"python-dotenv>=1.2.1,<2",
|
|
"fire>=0.7.1,<1",
|
|
"httpx[socks]>=0.28.1,<1",
|
|
"rich>=14.3.3,<15",
|
|
"tenacity>=9.1.4,<10",
|
|
"pyyaml>=6.0.2,<7",
|
|
"requests>=2.33.0,<3", # CVE-2026-25645
|
|
"jinja2>=3.1.5,<4",
|
|
"pydantic>=2.12.5,<3",
|
|
# Interactive CLI (prompt_toolkit is used directly by cli.py)
|
|
"prompt_toolkit>=3.0.52,<4",
|
|
# Tools
|
|
"exa-py>=2.9.0,<3",
|
|
"firecrawl-py>=4.16.0,<5",
|
|
"parallel-web>=0.4.2,<1",
|
|
"fal-client>=0.13.1,<1",
|
|
# Cron scheduler (built-in feature — scheduled cron/interval jobs use croniter).
|
|
"croniter>=6.0.0,<7",
|
|
# Text-to-speech (Edge TTS is free, no API key needed)
|
|
"edge-tts>=7.2.7,<8",
|
|
# Skills Hub (GitHub App JWT auth — optional, only needed for bot identity)
|
|
"PyJWT[crypto]>=2.12.0,<3", # CVE-2026-32597
|
|
# Windows has no IANA tzdata shipped with the OS, so Python's ``zoneinfo``
|
|
# (PEP 615) raises ``ZoneInfoNotFoundError`` for every non-UTC timezone
|
|
# out of the box. ``tzdata`` ships the Olson database as a data package
|
|
# Python resolves automatically. No-op on Linux/macOS (which have
|
|
# /usr/share/zoneinfo). Credits: PR #13182 (@sprmn24).
|
|
"tzdata>=2023.3; sys_platform == 'win32'",
|
|
]
|
|
|
|
[project.optional-dependencies]
|
|
modal = ["modal>=1.0.0,<2"]
|
|
daytona = ["daytona>=0.148.0,<1"]
|
|
vercel = ["vercel>=0.5.7,<0.6.0"]
|
|
dev = ["debugpy>=1.8.0,<2", "pytest>=9.0.2,<10", "pytest-asyncio>=1.3.0,<2", "pytest-xdist>=3.0,<4", "mcp>=1.2.0,<2", "ty>=0.0.1a29,<0.0.22", "ruff"]
|
|
messaging = ["python-telegram-bot[webhooks]>=22.6,<23", "discord.py[voice]>=2.7.1,<3", "aiohttp>=3.13.3,<4", "slack-bolt>=1.18.0,<2", "slack-sdk>=3.27.0,<4", "qrcode>=7.0,<8"]
|
|
cron = [] # croniter is now a core dependency; this extra kept for back-compat
|
|
slack = ["slack-bolt>=1.18.0,<2", "slack-sdk>=3.27.0,<4"]
|
|
matrix = ["mautrix[encryption]>=0.20,<1", "Markdown>=3.6,<4", "aiosqlite>=0.20", "asyncpg>=0.29", "aiohttp-socks>=0.10,<1"]
|
|
cli = ["simple-term-menu>=1.0,<2"]
|
|
tts-premium = ["elevenlabs>=1.0,<2"]
|
|
voice = [
|
|
# Local STT pulls in wheel-only transitive deps (ctranslate2, onnxruntime),
|
|
# so keep it out of the base install for source-build packagers like Homebrew.
|
|
"faster-whisper>=1.0.0,<2",
|
|
"sounddevice>=0.4.6,<1",
|
|
"numpy>=1.24.0,<3",
|
|
]
|
|
pty = [
|
|
"ptyprocess>=0.7.0,<1; sys_platform != 'win32'",
|
|
"pywinpty>=2.0.0,<3; sys_platform == 'win32'",
|
|
]
|
|
honcho = ["honcho-ai>=2.0.1,<3"]
|
|
mcp = ["mcp>=1.2.0,<2"]
|
|
homeassistant = ["aiohttp>=3.9.0,<4"]
|
|
sms = ["aiohttp>=3.9.0,<4"]
|
|
# Computer use — macOS background desktop control via cua-driver (MCP stdio).
|
|
# The cua-driver binary itself is installed via `hermes tools` post-setup
|
|
# (curl install script); this extra just pins the MCP client used to talk
|
|
# to it, which is already provided by the `mcp` extra.
|
|
computer-use = ["mcp>=1.2.0,<2"]
|
|
acp = ["agent-client-protocol>=0.9.0,<1.0"]
|
|
mistral = ["mistralai>=2.3.0,<3"]
|
|
bedrock = ["boto3>=1.35.0,<2"]
|
|
termux = [
|
|
# Baseline Android / Termux path for reliable fresh installs.
|
|
"python-telegram-bot[webhooks]>=22.6,<23",
|
|
"hermes-agent[cron]",
|
|
"hermes-agent[cli]",
|
|
"hermes-agent[pty]",
|
|
"hermes-agent[mcp]",
|
|
"hermes-agent[honcho]",
|
|
"hermes-agent[acp]",
|
|
]
|
|
termux-all = [
|
|
# Best-effort "install all" profile for Termux: include broad extras that
|
|
# are known to resolve on Android, while intentionally excluding extras that
|
|
# currently hard-fail from missing/broken Android wheels/toolchains.
|
|
#
|
|
# Excluded for now:
|
|
# - matrix (mautrix[encryption] -> python-olm build failures on Termux)
|
|
# - voice (faster-whisper chain requires ctranslate2/av builds not packaged)
|
|
"hermes-agent[termux]",
|
|
"hermes-agent[messaging]",
|
|
"hermes-agent[slack]",
|
|
"hermes-agent[tts-premium]",
|
|
"hermes-agent[dingtalk]",
|
|
"hermes-agent[feishu]",
|
|
"hermes-agent[google]",
|
|
"hermes-agent[mistral]",
|
|
"hermes-agent[bedrock]",
|
|
"hermes-agent[homeassistant]",
|
|
"hermes-agent[sms]",
|
|
"hermes-agent[web]",
|
|
]
|
|
dingtalk = ["dingtalk-stream>=0.20,<1", "alibabacloud-dingtalk>=2.0.0", "qrcode>=7.0,<8"]
|
|
feishu = ["lark-oapi>=1.5.3,<2", "qrcode>=7.0,<8"]
|
|
google = [
|
|
# Required by the google-workspace skill (Gmail, Calendar, Drive, Contacts,
|
|
# Sheets, Docs). Declared here so packagers (Nix, Homebrew) ship them with
|
|
# the [all] extra and users don't hit runtime `pip install` paths that fail
|
|
# in environments without pip (e.g. Nix-managed Python).
|
|
"google-api-python-client>=2.100,<3",
|
|
"google-auth-oauthlib>=1.0,<2",
|
|
"google-auth-httplib2>=0.2,<1",
|
|
]
|
|
# `hermes dashboard` (localhost SPA + API). Not in core to keep the default install lean.
|
|
web = ["fastapi>=0.104.0,<1", "uvicorn[standard]>=0.24.0,<1"]
|
|
rl = [
|
|
"atroposlib @ git+https://github.com/NousResearch/atropos.git@c20c85256e5a45ad31edf8b7276e9c5ee1995a30",
|
|
"tinker @ git+https://github.com/thinking-machines-lab/tinker.git@30517b667f18a3dfb7ef33fb56cf686d5820ba2b",
|
|
"fastapi>=0.104.0,<1",
|
|
"uvicorn[standard]>=0.24.0,<1",
|
|
"wandb>=0.15.0,<1",
|
|
]
|
|
yc-bench = ["yc-bench @ git+https://github.com/collinear-ai/yc-bench.git@bfb0c88062450f46341bd9a5298903fc2e952a5c ; python_version >= '3.12'"]
|
|
all = [
|
|
"hermes-agent[modal]",
|
|
"hermes-agent[daytona]",
|
|
"hermes-agent[vercel]",
|
|
"hermes-agent[messaging]",
|
|
# matrix: python-olm (required by matrix-nio[e2e]) is upstream-broken on
|
|
# modern macOS (archived libolm, C++ errors with Clang 21+). On Linux the
|
|
# [matrix] extra's own marker pulls in the [e2e] variant automatically.
|
|
"hermes-agent[matrix]; sys_platform == 'linux'",
|
|
"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]",
|
|
"hermes-agent[sms]",
|
|
"hermes-agent[acp]",
|
|
"hermes-agent[voice]",
|
|
"hermes-agent[dingtalk]",
|
|
"hermes-agent[feishu]",
|
|
"hermes-agent[google]",
|
|
"hermes-agent[mistral]",
|
|
"hermes-agent[bedrock]",
|
|
"hermes-agent[web]",
|
|
]
|
|
|
|
[project.scripts]
|
|
hermes = "hermes_cli.main:main"
|
|
hermes-agent = "run_agent:main"
|
|
hermes-acp = "acp_adapter.entry:main"
|
|
|
|
[tool.setuptools]
|
|
py-modules = ["run_agent", "model_tools", "toolsets", "batch_runner", "trajectory_compressor", "toolset_distributions", "cli", "hermes_bootstrap", "hermes_constants", "hermes_state", "hermes_time", "hermes_logging", "rl_cli", "utils"]
|
|
|
|
[tool.setuptools.package-data]
|
|
hermes_cli = ["web_dist/**/*"]
|
|
gateway = ["assets/**/*"]
|
|
|
|
[tool.setuptools.packages.find]
|
|
include = ["agent", "agent.*", "tools", "tools.*", "hermes_cli", "gateway", "gateway.*", "tui_gateway", "tui_gateway.*", "cron", "acp_adapter", "plugins", "plugins.*", "providers", "providers.*"]
|
|
|
|
[tool.pytest.ini_options]
|
|
testpaths = ["tests"]
|
|
markers = [
|
|
"integration: marks tests requiring external services (API keys, Modal, etc.)",
|
|
]
|
|
addopts = "-m 'not integration' -n auto"
|
|
|
|
[tool.ty.environment]
|
|
python-version = "3.13"
|
|
|
|
[tool.ty.rules]
|
|
unknown-argument = "warn"
|
|
redundant-cast = "ignore"
|
|
|
|
[tool.ty.src]
|
|
exclude = ["tinker-atropos"]
|
|
|
|
[tool.ruff]
|
|
exclude = ["tinker-atropos"]
|
|
preview = true # required for PLW1514 (unspecified-encoding) — preview rule
|
|
|
|
[tool.ruff.lint]
|
|
# All other lints are intentionally disabled (see comment history on this
|
|
# file) while we wrangle typechecks — but PLW1514 is too load-bearing to
|
|
# keep off. Bare open()/read_text()/write_text() in text mode defaults to
|
|
# the system locale encoding on Windows (cp1252 on US-locale installs),
|
|
# which silently corrupts any non-ASCII file content. We had three
|
|
# separate Windows sandbox regressions in one debug session before
|
|
# adding the explicit encoding. This rule keeps new code honest.
|
|
select = ["PLW1514"]
|
|
|
|
[tool.ruff.lint.per-file-ignores]
|
|
# Tests can intentionally exercise locale-encoding edge cases.
|
|
"tests/**" = ["PLW1514"]
|
|
# Skills and plugins are partially user-authored — their own conventions.
|
|
"skills/**" = ["PLW1514"]
|
|
"optional-skills/**" = ["PLW1514"]
|
|
"plugins/**" = ["PLW1514"]
|
|
|
|
[tool.uv]
|
|
exclude-newer = "7 days"
|