Metadata-Version: 2.4
Name: avervox-hermes
Version: 0.2.0
Summary: AverVOX TTS/STT providers for Hermes Agent — local speech, no cloud API
Author: Carl E. Hartung
License: MIT
Project-URL: Homepage, https://github.com/avrvx/AverVOX-Integrations
Project-URL: Source, https://github.com/avrvx/AverVOX-Integrations/tree/main/hermes
Project-URL: Issues, https://github.com/avrvx/AverVOX-Integrations/issues
Project-URL: AverVOX OSS, https://github.com/avrvx/AverVOX-OSS
Keywords: hermes,hermes-agent,tts,stt,speech,avervox,offline
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Plugins
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# AverVOX ↔ Hermes Agent

Use AverVOX (OSS or Pro) as the local TTS/STT backend for
[Hermes Agent](https://github.com/nousresearch/hermes-agent).

Speech runs on the same machine as the agent: replies are never sent to a
speech vendor, microphone audio is never uploaded, there is no per-character
bill, and it all keeps working with the network down. With the warm bridge
running, Hermes hears the first audio of a reply in about 0.32 s — see
[Latency](#latency).

## Fastest path

Recent AverVOX builds write the config below and verify it for you:

```bash
avrvx --install-integration hermes
```

It synthesizes real audio afterwards and exits non-zero if anything is wrong,
and it never modifies an existing `~/.hermes/config.yaml` — if you already have
one, it writes the snippet alongside for you to merge.

## Recommended: command providers (no Python plugin required)

Requires AverVOX 0.5.0 or newer with `avrvx` on `PATH`:

```yaml
# ~/.hermes/config.yaml  (snippet — merge into your existing file)
tts:
  provider: avervox
  providers:
    avervox:
      type: command
      command: "avrvx --synthesize --text-file {input_path} --output {output_path}"
      output_format: wav
      voice_compatible: true
      timeout: 180

stt:
  provider: avervox
  providers:
    avervox:
      type: command
      command: "avrvx --transcribe {input_path} > {output_path}"
      format: txt
      timeout: 300
```

A copy of this snippet lives at
[`hermes.config.snippet.yaml`](https://github.com/avrvx/AverVOX-Integrations/blob/main/hermes/hermes.config.snippet.yaml).

Verify:

```bash
avrvx --capabilities
hermes tools   # pick AverVOX / avervox for TTS when using the Python plugin path
```

## Optional: Python plugin

This directory is a Hermes plugin that registers TTS (and STT) providers named
`avervox` via `register_tts_provider` / `register_transcription_provider`.
Prefer the YAML command providers above unless you need picker metadata or
streaming hooks.

The plugin pipes reply text to `avrvx` over stdin rather than passing it as an
argument, so conversation text never appears in the process list. It caches the
`--capabilities` probe (the picker reads `display_name` repeatedly) and runs
`avrvx` in its own process group so a timeout also kills Piper or Whisper.

### Install

```bash
pip install avervox-hermes
# then enable if required by your Hermes version
hermes plugins enable avervox
```

The package registers itself under the `hermes_agent.plugins` entry point
group, so Hermes discovers it without any path configuration.

To work on the plugin instead of just using it:

```bash
git clone https://github.com/avrvx/AverVOX-Integrations.git
pip install -e AverVOX-Integrations/hermes
```

Point Hermes at AverVOX:

```yaml
tts:
  provider: avervox
stt:
  provider: avervox
```

## AverVOX → Hermes (Converse)

In the AverVOX Dashboard (Pro) or Settings → LLM (OSS), add a profile:

| Field | Example |
|-------|---------|
| Label | `Hermes Agent` |
| API base | `http://127.0.0.1:<hermes-port>/v1` |
| Session header | `X-Hermes-Session-Id` |

## OSS vs Pro

One integration. Pro features (Kokoro, etc.) follow whatever AverVOX has
configured; `avrvx --capabilities` reports the edition.

## Latency

Measured through Hermes' own registries on a 2017 laptop with Piper
`en_US-lessac-high`. "First audio" is the wait before playback can start on a
three-sentence reply; "whole reply" is the wait for a finished WAV.

| | Spawn per call | Warm daemon |
|---|---|---|
| First audio (streaming) | 2.6 s | 0.32 s |
| Whole reply (file) | 3.3 s | 0.77 s |

Two independent wins. `avrvx --daemon` removes the Python start and model load
from every call; see [systemd/](https://github.com/avrvx/AverVOX-Integrations/tree/main/systemd)
for a user unit. Streaming then starts playback on the first sentence instead
of the last. Neither is required — without both, the first column applies and
everything still works.

## Tested against

| | Version |
|---|---|
| Hermes Agent | 0.19.0 (commit `1161cc0`) |
| AverVOX | OSS and Pro, 0.5.0 and newer |
| Python | 3.12 |

Verified by registering through Hermes' own `agent.tts_registry` and
`agent.transcription_registry` and then synthesizing from what came back out,
rather than by calling the provider classes directly. That distinction matters:
`PluginContext.register_tts_provider` `isinstance`-checks against
`agent.tts_provider.TTSProvider` and only logs a warning when the check fails,
so a provider that does not inherit the ABC is dropped without raising. The
streamer is resolved through `tools.tts_streaming.resolve_streaming_provider`
for the same reason.
