Mirror the upstream Stage 1 slash-command preprocessor
(api_server_slash.py) as an aiohttp middleware installed by the
bootstrap patch. Intercepts gateway commands (/help, /commands,
/profile, /provider) and returns synthetic responses instead of
forwarding them to the LLM, which would hallucinate wrong replies.
Stateful commands (/model, /new, /retry, etc.) get a deterministic
decline notice. Feature-detects and skips when the upstream module
exists.
- /v1/chat/completions: synthetic SSE stream or JSON chat.completion
- /v1/runs: injects message.delta + run.completed into adapter queue
- Auth check runs before command logic (matches upstream order)
- Fail-open: any middleware error falls through to the original handler
- 31 new tests (unit + aiohttp integration)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Six files modified outside the voice-intents session — roadmap
updates, TODO adjustments, upstream contribution docs, decisions
doc corrections, and bootstrap handler/patch tweaks. Committing
to clean the working tree before the v0.4.0 merge to main.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Upstream commit 8d023e43 removed `skills_categories` from
`tools/skills_tool.py` as dead code. The bootstrap's `_resolve_upstream()`
imported it unconditionally, which raised ImportError and silently prevented
all injected /api/* routes from registering on post-sync vanilla upstream
(the try/except in _maybe_register_routes caught it, gateway started fine,
but sessions/memory/skills/config were all missing).
Fix: remove the import and the /api/skills/categories route entirely. The
app never calls this endpoint — skill browsing uses /api/skills?category=.
Upstream removed it as dead code; we don't re-introduce it.
Updated _INJECTED_PATHS in _patch.py and module docstring in _handlers.py
to document both deliberate omissions (chat/stream and skills/categories).
Updated docs/decisions.md and docs/HERMES-WEBAPI-REFERENCE.md to reflect
the upstream alignment rationale.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds hermes_relay_bootstrap/ — a Python package shipped via .pth in the
hermes-agent venv site-packages — that monkey-patches aiohttp.web.Application
at interpreter startup. When the gateway builds its app, the bootstrap
intercepts app["api_server_adapter"] = self and injects 14 management
handlers onto the same router: /api/sessions/* CRUD, /api/memory,
/api/skills, /api/config, /api/available-models. Feature-detects on route
path and no-ops cleanly when these routes are already present, so it's
safe to ship across all hermes-agent versions.
Chat streaming continues to use standard upstream /v1/runs (which already
emits structured tool events). The Android client gains a new
ServerCapabilities probe + streamingEndpoint = "auto" default that picks
the best chat path automatically based on what each server actually
exposes (Auto/Sessions/Runs).
Also adds canonical uninstall.sh — reverses every install.sh step in the
opposite order, idempotent, never touches state shared with other Hermes
tools (.env, sessions DB, hermes-agent venv core). Flags: --dry-run,
--keep-clone, --remove-secret. install.sh header + success summary +
README + user-docs/guide/getting-started.md + user-docs/reference/api.md
all updated to mention the uninstall path.
Verified end-to-end on the server: bootstrap loads via .pth, intercepts
aiohttp.web import, injects 11 unique paths onto a vanilla aiohttp app,
GET /api/sessions returns real production data via SessionDB, OPTIONS
probes return the expected 405/404 codes for capability detection, and
feature detection no-ops cleanly when routes already exist.
See docs/decisions.md ADR 16 for full rationale and DEVLOG.md
2026-04-12 entries for the work breakdown.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>