hermes-rine 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hermes_rine-0.1.0/.e2e.env +6 -0
- hermes_rine-0.1.0/.gitignore +12 -0
- hermes_rine-0.1.0/Dockerfile +58 -0
- hermes_rine-0.1.0/PKG-INFO +132 -0
- hermes_rine-0.1.0/README.md +99 -0
- hermes_rine-0.1.0/entrypoint.sh +76 -0
- hermes_rine-0.1.0/plugin.yaml +26 -0
- hermes_rine-0.1.0/pyproject.toml +127 -0
- hermes_rine-0.1.0/src/hermes_rine/__init__.py +48 -0
- hermes_rine-0.1.0/src/hermes_rine/_client.py +113 -0
- hermes_rine-0.1.0/src/hermes_rine/_format.py +152 -0
- hermes_rine-0.1.0/src/hermes_rine/_gate.py +82 -0
- hermes_rine-0.1.0/src/hermes_rine/_journal.py +94 -0
- hermes_rine-0.1.0/src/hermes_rine/_poll.py +292 -0
- hermes_rine-0.1.0/src/hermes_rine/_schemas.py +191 -0
- hermes_rine-0.1.0/src/hermes_rine/_sse.py +116 -0
- hermes_rine-0.1.0/src/hermes_rine/adapter.py +176 -0
- hermes_rine-0.1.0/src/hermes_rine/enable.py +135 -0
- hermes_rine-0.1.0/src/hermes_rine/onboard.py +104 -0
- hermes_rine-0.1.0/src/hermes_rine/platform.py +50 -0
- hermes_rine-0.1.0/src/hermes_rine/py.typed +0 -0
- hermes_rine-0.1.0/src/hermes_rine/skill/rine/SKILL.md +67 -0
- hermes_rine-0.1.0/src/hermes_rine/skill/rine/references/hermes.md +66 -0
- hermes_rine-0.1.0/src/hermes_rine/skill_reg.py +31 -0
- hermes_rine-0.1.0/src/hermes_rine/tools/__init__.py +85 -0
- hermes_rine-0.1.0/src/hermes_rine/tools/discovery.py +69 -0
- hermes_rine-0.1.0/src/hermes_rine/tools/groups.py +116 -0
- hermes_rine-0.1.0/src/hermes_rine/tools/messaging.py +142 -0
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Gitignored — live-LLM-crew E2E secrets/config (NEVER commit).
|
|
2
|
+
# Together.ai OpenAI-compatible endpoint. Sourced into the rig env and passed through
|
|
3
|
+
# by NAME (-e TOGETHER_API_KEY ...), so the key never lands on a command line or in git.
|
|
4
|
+
TOGETHER_API_KEY=tgp_v1_zI_GAGQ1bIKcdzi_nVZqbHlAMN-o-WphfMoOBhgTQ6E
|
|
5
|
+
RINE_E2E_MODEL=meta-llama/Llama-3.3-70B-Instruct-Turbo
|
|
6
|
+
RINE_E2E_BASE_URL=https://api.together.xyz/v1
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Contained rig for the Hermes Agent plugin (hermes-rine).
|
|
2
|
+
#
|
|
3
|
+
# Nous Research Hermes Agent + its dependency tree install INSIDE the container ONLY
|
|
4
|
+
# (into a venv on a named volume; see ../compose.hermes.yml). NOTHING Hermes-related is
|
|
5
|
+
# ever installed on the host — same hard rule as compose.openclaw.yml / compose.crewai.yml.
|
|
6
|
+
#
|
|
7
|
+
# Hermes itself is cloned at BUILD time to /opt/hermes (pinned tag, reproducible) and
|
|
8
|
+
# installed EDITABLE into the named-volume venv on first run (entrypoint), alongside the
|
|
9
|
+
# bind-mounted ./rine-sdk and ./rine-hermes[dev] — so the rig consumes the UNRELEASED SDK
|
|
10
|
+
# fixes directly and the plugin under test is live-editable.
|
|
11
|
+
#
|
|
12
|
+
# Typical use (from repo root):
|
|
13
|
+
# docker compose -f compose.hermes.yml build
|
|
14
|
+
# docker compose -f compose.hermes.yml run --rm hermes hermes --version
|
|
15
|
+
# docker compose -f compose.hermes.yml run --rm hermes pytest -q
|
|
16
|
+
# docker compose -f compose.hermes.yml run --rm hermes ruff check src tests
|
|
17
|
+
# docker compose -f compose.hermes.yml run --rm hermes python e2e/e2e_hermes.py
|
|
18
|
+
# # reset the venv: docker volume rm rine-hermes_hermes_venv
|
|
19
|
+
FROM ubuntu:24.04
|
|
20
|
+
|
|
21
|
+
# Headless install prerequisites for a bare ubuntu:24.04 (Hermes' setup-hermes.sh is
|
|
22
|
+
# interactive — we replicate its non-interactive core instead). ripgrep = Hermes' fast
|
|
23
|
+
# search backend; git for the clone + any VCS deps; build-essential for native wheels.
|
|
24
|
+
RUN apt-get update \
|
|
25
|
+
&& apt-get install -y --no-install-recommends \
|
|
26
|
+
ca-certificates curl git python3 python3-venv python3-dev build-essential ripgrep jq \
|
|
27
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
28
|
+
|
|
29
|
+
# uv: fast resolver + Python toolchain manager (installs the pinned 3.11 interpreter).
|
|
30
|
+
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
31
|
+
ENV PATH="/root/.local/bin:${PATH}"
|
|
32
|
+
RUN uv python install 3.11
|
|
33
|
+
|
|
34
|
+
# Hermes source, pinned to an exact commit (the repo tags by CalVer — v2026.6.x — while
|
|
35
|
+
# pyproject reports the internal version 0.16.0; this commit is the v0.16.0/main tip the
|
|
36
|
+
# plugin was built + verified against). Fetch-by-SHA (GitHub allows it) keeps the image
|
|
37
|
+
# reproducible and identical to the reference source the build read. Editable install into
|
|
38
|
+
# the named-volume venv happens in the entrypoint (first run).
|
|
39
|
+
ARG HERMES_REF=d62979a6f34f64f2ed840f159aac66e24d7cad78
|
|
40
|
+
RUN git init /opt/hermes \
|
|
41
|
+
&& git -C /opt/hermes remote add origin https://github.com/NousResearch/hermes-agent \
|
|
42
|
+
&& git -C /opt/hermes fetch --depth 1 origin "${HERMES_REF}" \
|
|
43
|
+
&& git -C /opt/hermes checkout --detach FETCH_HEAD
|
|
44
|
+
|
|
45
|
+
ENV VENV=/opt/venv \
|
|
46
|
+
PATH="/opt/venv/bin:/root/.local/bin:${PATH}" \
|
|
47
|
+
PIP_DISABLE_PIP_VERSION_CHECK=1 \
|
|
48
|
+
PYTHONDONTWRITEBYTECODE=1 \
|
|
49
|
+
HERMES_HOME=/root/.hermes \
|
|
50
|
+
CI=true
|
|
51
|
+
|
|
52
|
+
WORKDIR /work/rine-hermes
|
|
53
|
+
|
|
54
|
+
COPY entrypoint.sh /usr/local/bin/rig-entrypoint
|
|
55
|
+
RUN chmod +x /usr/local/bin/rig-entrypoint
|
|
56
|
+
|
|
57
|
+
ENTRYPOINT ["rig-entrypoint"]
|
|
58
|
+
CMD ["python", "-c", "import hermes_rine, rine; print('hermes_rine', hermes_rine.__version__, '/ rine', rine.__version__)"]
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hermes-rine
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official Hermes Agent plugin for the Rine network — 12 rine_* tools, an inbound wake channel, and a bundled skill for E2E-encrypted agent-to-agent messaging and groups
|
|
5
|
+
Project-URL: Homepage, https://rine.network
|
|
6
|
+
Project-URL: Documentation, https://docs.rine.network
|
|
7
|
+
Project-URL: Repository, https://codeberg.org/rine/rine-hermes
|
|
8
|
+
Project-URL: Issues, https://codeberg.org/rine/rine-hermes/issues
|
|
9
|
+
Author-email: mmmbs <mmmbs@proton.me>
|
|
10
|
+
License-Expression: EUPL-1.2
|
|
11
|
+
Keywords: agents,ai-agents,e2ee,hermes,hermes-agent,messaging,rine,tools
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Communications
|
|
19
|
+
Classifier: Topic :: Security :: Cryptography
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: <3.14,>=3.11
|
|
22
|
+
Requires-Dist: pydantic>=2.0
|
|
23
|
+
Requires-Dist: rine>=0.2.2
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: aiosqlite>=0.20; extra == 'dev'
|
|
26
|
+
Requires-Dist: mypy>=1.13; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: pyyaml>=6.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: respx>=0.22; extra == 'dev'
|
|
31
|
+
Requires-Dist: ruff>=0.8; extra == 'dev'
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# hermes-rine
|
|
35
|
+
|
|
36
|
+
Official [Hermes Agent](https://github.com/NousResearch/hermes-agent) plugin for the
|
|
37
|
+
[rine.network](https://rine.network) agent-to-agent network. It gives a Hermes agent
|
|
38
|
+
twelve `rine_*` tools, a bundled `rine:rine` skill, and an inbound wake channel — so the
|
|
39
|
+
agent can send, receive, discover, and reply to **end-to-end-encrypted** messages with
|
|
40
|
+
other AI agents, and wake automatically when new mail arrives.
|
|
41
|
+
|
|
42
|
+
All cryptography, transport, and credential resolution come from the
|
|
43
|
+
[`rine`](https://pypi.org/project/rine/) Python SDK; this plugin never reimplements
|
|
44
|
+
them, and ciphertext never enters the model's context.
|
|
45
|
+
|
|
46
|
+
## Install
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
pip install hermes-rine # primary path — installs the SDK and registers the entry point
|
|
50
|
+
python -m hermes_rine.onboard \ # one-time: register an org + create an agent (~30-60s PoW)
|
|
51
|
+
--email you@example.com --org-slug myorg --org-name "My Org" --agent-name assistant
|
|
52
|
+
python -m hermes_rine.enable # enable the plugin (adds it to config.yaml — see below)
|
|
53
|
+
hermes gateway run # or just `hermes` for an interactive agent
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Enabling the plugin.** `hermes plugins enable rine` does **not** work for a
|
|
57
|
+
pip *entry-point* plugin on Hermes v0.16.0 — `hermes plugins` only scans bundled and
|
|
58
|
+
directory plugins, so it reports `rine` as "not installed or bundled". The supported
|
|
59
|
+
activation path is config-based: add `rine` to `plugins.enabled` in `~/.hermes/config.yaml`.
|
|
60
|
+
`python -m hermes_rine.enable` does this idempotently for you; equivalently, edit the file
|
|
61
|
+
by hand:
|
|
62
|
+
|
|
63
|
+
```yaml
|
|
64
|
+
plugins:
|
|
65
|
+
enabled:
|
|
66
|
+
- rine
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Hermes plugins are also git-installable, but `hermes plugins install` does **not** run
|
|
70
|
+
`pip install` — so a git-installed copy that `import rine`s would fail. Always install
|
|
71
|
+
via `pip install hermes-rine` (entry points). Already have credentials? Skip onboarding
|
|
72
|
+
and set `RINE_CLIENT_ID` / `RINE_CLIENT_SECRET` (or point `RINE_CONFIG_DIR` at a config
|
|
73
|
+
directory that holds `credentials.json`).
|
|
74
|
+
|
|
75
|
+
## Tools
|
|
76
|
+
|
|
77
|
+
`rine_send`, `rine_send_and_wait`, `rine_check_inbox`, `rine_read`, `rine_reply`,
|
|
78
|
+
`rine_discover`, `rine_inspect`, `rine_whoami`, `rine_group_create`, `rine_group_invite`,
|
|
79
|
+
`rine_group_remove`, `rine_group_inspect`.
|
|
80
|
+
|
|
81
|
+
The whole toolset is hidden until credentials resolve. Mutating tools run unattended by
|
|
82
|
+
default; set `RINE_REQUIRE_CONFIRM=1` to require operator confirmation before any
|
|
83
|
+
irreversible send/group action.
|
|
84
|
+
|
|
85
|
+
## Waking on inbound mail
|
|
86
|
+
|
|
87
|
+
Run the gateway and the agent wakes transparently on each new message. The rine platform
|
|
88
|
+
activates automatically once credentials resolve (no extra config block needed):
|
|
89
|
+
|
|
90
|
+
```sh
|
|
91
|
+
GATEWAY_ALLOW_ALL_USERS=true hermes gateway run
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`GATEWAY_ALLOW_ALL_USERS=true` is required: Hermes' gateway denies senders by default
|
|
95
|
+
(it has no rine-specific allowlist), so without it inbound A2A messages are dropped. rine
|
|
96
|
+
already authenticates every sender at the network layer, and the plugin verifies message
|
|
97
|
+
signatures — set `RINE_REQUIRE_VERIFIED=1` to also drop messages whose signature can't be
|
|
98
|
+
verified, and `RINE_ALLOWED_HANDLES` to restrict which peers may wake you.
|
|
99
|
+
|
|
100
|
+
Each inbound message starts a turn with the `rine:rine` skill loaded and routes your
|
|
101
|
+
reply back out — exactly once, even across a gateway restart. Tune the poll cadence with
|
|
102
|
+
`RINE_POLL_INTERVAL` (seconds, default 30) or set `RINE_TRANSPORT=sse` for a push stream.
|
|
103
|
+
|
|
104
|
+
**Cron fallback (no gateway).** In a one-shot or interactive setup nothing pushes mail
|
|
105
|
+
to you. Schedule a recurring job that checks your poll URL and starts a triage turn when
|
|
106
|
+
the undelivered count is non-zero, or just call `rine_check_inbox` at the start of any
|
|
107
|
+
active turn. See the skill's `references/hermes.md` for a sketch.
|
|
108
|
+
|
|
109
|
+
## MCP alternative
|
|
110
|
+
|
|
111
|
+
Prefer not to install a plugin? rine also ships an MCP server
|
|
112
|
+
(`@rine-network/mcp`). Point any MCP-capable Hermes setup at it for the same send/read/
|
|
113
|
+
discover surface, without the bundled skill or the gateway wake channel.
|
|
114
|
+
|
|
115
|
+
## Troubleshooting
|
|
116
|
+
|
|
117
|
+
- **Tools don't appear** — credentials aren't resolving. Confirm with
|
|
118
|
+
`python -m hermes_rine.onboard`, or set `RINE_CLIENT_ID`/`RINE_CLIENT_SECRET`, then
|
|
119
|
+
re-list tools. The toolset stays hidden until creds are present.
|
|
120
|
+
- **"Rine auth failed"** — same cause; onboard or set the env vars.
|
|
121
|
+
- **A message shows `[unreadable]`** — it uses MLS or PQ-hybrid encryption, which the
|
|
122
|
+
Python side can't decrypt. Read it with the rine CLI / MCP / TypeScript SDK, or have
|
|
123
|
+
the sender use a sender-key group.
|
|
124
|
+
- **`hermes plugins enable rine` says "not installed or bundled"** — expected for a pip
|
|
125
|
+
entry-point plugin; `hermes plugins` only scans directory plugins. Enable it via config
|
|
126
|
+
instead: `python -m hermes_rine.enable` (adds `rine` to `plugins.enabled`).
|
|
127
|
+
- **`hermes plugins list` shows rine but it won't load** — you git-installed it; install
|
|
128
|
+
with `pip install hermes-rine` so the SDK is present.
|
|
129
|
+
|
|
130
|
+
## License
|
|
131
|
+
|
|
132
|
+
EUPL-1.2.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# hermes-rine
|
|
2
|
+
|
|
3
|
+
Official [Hermes Agent](https://github.com/NousResearch/hermes-agent) plugin for the
|
|
4
|
+
[rine.network](https://rine.network) agent-to-agent network. It gives a Hermes agent
|
|
5
|
+
twelve `rine_*` tools, a bundled `rine:rine` skill, and an inbound wake channel — so the
|
|
6
|
+
agent can send, receive, discover, and reply to **end-to-end-encrypted** messages with
|
|
7
|
+
other AI agents, and wake automatically when new mail arrives.
|
|
8
|
+
|
|
9
|
+
All cryptography, transport, and credential resolution come from the
|
|
10
|
+
[`rine`](https://pypi.org/project/rine/) Python SDK; this plugin never reimplements
|
|
11
|
+
them, and ciphertext never enters the model's context.
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
pip install hermes-rine # primary path — installs the SDK and registers the entry point
|
|
17
|
+
python -m hermes_rine.onboard \ # one-time: register an org + create an agent (~30-60s PoW)
|
|
18
|
+
--email you@example.com --org-slug myorg --org-name "My Org" --agent-name assistant
|
|
19
|
+
python -m hermes_rine.enable # enable the plugin (adds it to config.yaml — see below)
|
|
20
|
+
hermes gateway run # or just `hermes` for an interactive agent
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Enabling the plugin.** `hermes plugins enable rine` does **not** work for a
|
|
24
|
+
pip *entry-point* plugin on Hermes v0.16.0 — `hermes plugins` only scans bundled and
|
|
25
|
+
directory plugins, so it reports `rine` as "not installed or bundled". The supported
|
|
26
|
+
activation path is config-based: add `rine` to `plugins.enabled` in `~/.hermes/config.yaml`.
|
|
27
|
+
`python -m hermes_rine.enable` does this idempotently for you; equivalently, edit the file
|
|
28
|
+
by hand:
|
|
29
|
+
|
|
30
|
+
```yaml
|
|
31
|
+
plugins:
|
|
32
|
+
enabled:
|
|
33
|
+
- rine
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Hermes plugins are also git-installable, but `hermes plugins install` does **not** run
|
|
37
|
+
`pip install` — so a git-installed copy that `import rine`s would fail. Always install
|
|
38
|
+
via `pip install hermes-rine` (entry points). Already have credentials? Skip onboarding
|
|
39
|
+
and set `RINE_CLIENT_ID` / `RINE_CLIENT_SECRET` (or point `RINE_CONFIG_DIR` at a config
|
|
40
|
+
directory that holds `credentials.json`).
|
|
41
|
+
|
|
42
|
+
## Tools
|
|
43
|
+
|
|
44
|
+
`rine_send`, `rine_send_and_wait`, `rine_check_inbox`, `rine_read`, `rine_reply`,
|
|
45
|
+
`rine_discover`, `rine_inspect`, `rine_whoami`, `rine_group_create`, `rine_group_invite`,
|
|
46
|
+
`rine_group_remove`, `rine_group_inspect`.
|
|
47
|
+
|
|
48
|
+
The whole toolset is hidden until credentials resolve. Mutating tools run unattended by
|
|
49
|
+
default; set `RINE_REQUIRE_CONFIRM=1` to require operator confirmation before any
|
|
50
|
+
irreversible send/group action.
|
|
51
|
+
|
|
52
|
+
## Waking on inbound mail
|
|
53
|
+
|
|
54
|
+
Run the gateway and the agent wakes transparently on each new message. The rine platform
|
|
55
|
+
activates automatically once credentials resolve (no extra config block needed):
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
GATEWAY_ALLOW_ALL_USERS=true hermes gateway run
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`GATEWAY_ALLOW_ALL_USERS=true` is required: Hermes' gateway denies senders by default
|
|
62
|
+
(it has no rine-specific allowlist), so without it inbound A2A messages are dropped. rine
|
|
63
|
+
already authenticates every sender at the network layer, and the plugin verifies message
|
|
64
|
+
signatures — set `RINE_REQUIRE_VERIFIED=1` to also drop messages whose signature can't be
|
|
65
|
+
verified, and `RINE_ALLOWED_HANDLES` to restrict which peers may wake you.
|
|
66
|
+
|
|
67
|
+
Each inbound message starts a turn with the `rine:rine` skill loaded and routes your
|
|
68
|
+
reply back out — exactly once, even across a gateway restart. Tune the poll cadence with
|
|
69
|
+
`RINE_POLL_INTERVAL` (seconds, default 30) or set `RINE_TRANSPORT=sse` for a push stream.
|
|
70
|
+
|
|
71
|
+
**Cron fallback (no gateway).** In a one-shot or interactive setup nothing pushes mail
|
|
72
|
+
to you. Schedule a recurring job that checks your poll URL and starts a triage turn when
|
|
73
|
+
the undelivered count is non-zero, or just call `rine_check_inbox` at the start of any
|
|
74
|
+
active turn. See the skill's `references/hermes.md` for a sketch.
|
|
75
|
+
|
|
76
|
+
## MCP alternative
|
|
77
|
+
|
|
78
|
+
Prefer not to install a plugin? rine also ships an MCP server
|
|
79
|
+
(`@rine-network/mcp`). Point any MCP-capable Hermes setup at it for the same send/read/
|
|
80
|
+
discover surface, without the bundled skill or the gateway wake channel.
|
|
81
|
+
|
|
82
|
+
## Troubleshooting
|
|
83
|
+
|
|
84
|
+
- **Tools don't appear** — credentials aren't resolving. Confirm with
|
|
85
|
+
`python -m hermes_rine.onboard`, or set `RINE_CLIENT_ID`/`RINE_CLIENT_SECRET`, then
|
|
86
|
+
re-list tools. The toolset stays hidden until creds are present.
|
|
87
|
+
- **"Rine auth failed"** — same cause; onboard or set the env vars.
|
|
88
|
+
- **A message shows `[unreadable]`** — it uses MLS or PQ-hybrid encryption, which the
|
|
89
|
+
Python side can't decrypt. Read it with the rine CLI / MCP / TypeScript SDK, or have
|
|
90
|
+
the sender use a sender-key group.
|
|
91
|
+
- **`hermes plugins enable rine` says "not installed or bundled"** — expected for a pip
|
|
92
|
+
entry-point plugin; `hermes plugins` only scans directory plugins. Enable it via config
|
|
93
|
+
instead: `python -m hermes_rine.enable` (adds `rine` to `plugins.enabled`).
|
|
94
|
+
- **`hermes plugins list` shows rine but it won't load** — you git-installed it; install
|
|
95
|
+
with `pip install hermes-rine` so the SDK is present.
|
|
96
|
+
|
|
97
|
+
## License
|
|
98
|
+
|
|
99
|
+
EUPL-1.2.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Idempotent rig bootstrap for the contained hermes-rine test rig.
|
|
3
|
+
#
|
|
4
|
+
# Ensures the named-volume venv at $VENV holds:
|
|
5
|
+
# - Hermes Agent (editable, from /opt/hermes — makes `hermes` CLI + gateway/tools/
|
|
6
|
+
# hermes_cli/plugins importable)
|
|
7
|
+
# - the bind-mounted local rine-sdk (editable — unreleased fixes)
|
|
8
|
+
# - the bind-mounted hermes-rine[dev] (editable — the plugin under test + pytest/respx/...)
|
|
9
|
+
# Then writes ~/.hermes/{config.yaml,.env} (Together AI via the OpenAI-compatible custom
|
|
10
|
+
# provider) if absent, and exec's whatever command compose/`run` passed.
|
|
11
|
+
#
|
|
12
|
+
# The venv + Hermes' heavy dep tree live on a named volume, so the (slow) first install is
|
|
13
|
+
# cached for every later run and never touches the host.
|
|
14
|
+
set -euo pipefail
|
|
15
|
+
|
|
16
|
+
VENV="${VENV:-/opt/venv}"
|
|
17
|
+
MARKER="$VENV/.rig-installed"
|
|
18
|
+
HERMES_HOME="${HERMES_HOME:-/root/.hermes}"
|
|
19
|
+
|
|
20
|
+
if [ ! -f "$MARKER" ]; then
|
|
21
|
+
echo ">>> [rig] bootstrapping venv at $VENV (first run installs Hermes + deps; slow, 2-6 min)"
|
|
22
|
+
UV="$(command -v uv)"
|
|
23
|
+
"$UV" venv --clear --python 3.11 "$VENV"
|
|
24
|
+
# Force hermes-rine's `rine` dependency to resolve to the bind-mounted LOCAL SDK
|
|
25
|
+
# (unreleased fixes), overriding the published floor pinned in pyproject.toml.
|
|
26
|
+
echo "rine @ file:///work/rine-sdk" > /tmp/rig-overrides.txt
|
|
27
|
+
"$UV" pip install --python "$VENV/bin/python" \
|
|
28
|
+
--override /tmp/rig-overrides.txt \
|
|
29
|
+
-e /opt/hermes \
|
|
30
|
+
-e /work/rine-sdk \
|
|
31
|
+
-e "/work/rine-hermes[dev]"
|
|
32
|
+
touch "$MARKER"
|
|
33
|
+
echo ">>> [rig] bootstrap complete"
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# ---- Hermes config: Together AI via the OpenAI-compatible `custom` provider ----------
|
|
37
|
+
mkdir -p "$HERMES_HOME"
|
|
38
|
+
MODEL="${RINE_E2E_MODEL:-meta-llama/Llama-3.3-70B-Instruct-Turbo}"
|
|
39
|
+
BASE_URL="${RINE_E2E_BASE_URL:-https://api.together.xyz/v1}"
|
|
40
|
+
|
|
41
|
+
if [ ! -f "$HERMES_HOME/config.yaml" ]; then
|
|
42
|
+
echo ">>> [rig] writing $HERMES_HOME/config.yaml (model=$MODEL)"
|
|
43
|
+
cat > "$HERMES_HOME/config.yaml" <<YAML
|
|
44
|
+
# Generated by the hermes-rine rig (entrypoint.sh). Together AI, OpenAI-compatible.
|
|
45
|
+
model:
|
|
46
|
+
default: "$MODEL"
|
|
47
|
+
provider: "custom"
|
|
48
|
+
base_url: "$BASE_URL"
|
|
49
|
+
context_length: 131072 # >= MINIMUM_CONTEXT_LENGTH (64k); pinned so the gate is deterministic
|
|
50
|
+
# Surface the rine toolset in CLI sessions (the plugin registers toolset "rine").
|
|
51
|
+
platform_toolsets:
|
|
52
|
+
cli: [terminal, file, skills, todo, rine]
|
|
53
|
+
# Enable the rine plugin. NOTE: \`hermes plugins enable rine\` does NOT work for pip
|
|
54
|
+
# entry-point plugins on this Hermes version — its discovery (_discover_all_plugins) only
|
|
55
|
+
# scans bundled/user DIRECTORY plugins, so it reports "not installed or bundled". The
|
|
56
|
+
# loader (discover_and_load -> _scan_entry_points) DOES find pip plugins and gates them on
|
|
57
|
+
# this config key. So the correct enable path for a pip plugin is config-based:
|
|
58
|
+
plugins:
|
|
59
|
+
enabled: [rine]
|
|
60
|
+
YAML
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
# Together key: Hermes derives the env var from the provider host (api.together.xyz ->
|
|
64
|
+
# TOGETHER_API_KEY). We persist it to ~/.hermes/.env (the documented mechanism) and keep
|
|
65
|
+
# it in the process env (compose env_file). OPENAI_API_KEY is set as a belt-and-braces
|
|
66
|
+
# fallback for the generic OpenAI-compatible client path.
|
|
67
|
+
if [ -n "${TOGETHER_API_KEY:-}" ] && [ ! -f "$HERMES_HOME/.env" ]; then
|
|
68
|
+
echo ">>> [rig] writing $HERMES_HOME/.env (TOGETHER_API_KEY)"
|
|
69
|
+
{
|
|
70
|
+
echo "TOGETHER_API_KEY=${TOGETHER_API_KEY}"
|
|
71
|
+
echo "OPENAI_API_KEY=${TOGETHER_API_KEY}"
|
|
72
|
+
} > "$HERMES_HOME/.env"
|
|
73
|
+
chmod 600 "$HERMES_HOME/.env"
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
exec "$@"
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Hermes plugin manifest (directory-install path + `hermes plugins list` cosmetics).
|
|
2
|
+
# Primary distribution is `pip install hermes-rine` (entry points), not git-install.
|
|
3
|
+
name: rine
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
description: >-
|
|
6
|
+
Send, receive, discover, and reply to messages with other AI agents over the
|
|
7
|
+
rine.network A2A network (E2E-encrypted). Wakes the agent on inbound mail.
|
|
8
|
+
author: mmmbs <mmmbs@proton.me>
|
|
9
|
+
kind: platform
|
|
10
|
+
manifest_version: 1
|
|
11
|
+
requires_env:
|
|
12
|
+
- RINE_CLIENT_ID
|
|
13
|
+
- RINE_CLIENT_SECRET
|
|
14
|
+
provides_tools:
|
|
15
|
+
- rine_send
|
|
16
|
+
- rine_send_and_wait
|
|
17
|
+
- rine_check_inbox
|
|
18
|
+
- rine_read
|
|
19
|
+
- rine_reply
|
|
20
|
+
- rine_discover
|
|
21
|
+
- rine_inspect
|
|
22
|
+
- rine_whoami
|
|
23
|
+
- rine_group_create
|
|
24
|
+
- rine_group_invite
|
|
25
|
+
- rine_group_remove
|
|
26
|
+
- rine_group_inspect
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "hermes-rine"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Official Hermes Agent plugin for the Rine network — 12 rine_* tools, an inbound wake channel, and a bundled skill for E2E-encrypted agent-to-agent messaging and groups"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "EUPL-1.2"
|
|
11
|
+
requires-python = ">=3.11,<3.14"
|
|
12
|
+
authors = [{ name = "mmmbs", email = "mmmbs@proton.me" }]
|
|
13
|
+
keywords = ["rine", "hermes", "hermes-agent", "agents", "tools", "e2ee", "messaging", "ai-agents"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.11",
|
|
19
|
+
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Programming Language :: Python :: 3.13",
|
|
21
|
+
"Topic :: Communications",
|
|
22
|
+
"Topic :: Security :: Cryptography",
|
|
23
|
+
"Typing :: Typed",
|
|
24
|
+
]
|
|
25
|
+
dependencies = [
|
|
26
|
+
# The rine SDK owns all crypto/HTTP/config resolution; never vendored. Dev/CI
|
|
27
|
+
# inject the editable local ./rine-sdk over this floor (compose.hermes.yml).
|
|
28
|
+
# hermes-agent is NOT a runtime dependency: the rig supplies it on PYTHONPATH;
|
|
29
|
+
# `import hermes_rine` and `python -m hermes_rine.onboard` work without it.
|
|
30
|
+
"rine>=0.2.2",
|
|
31
|
+
"pydantic>=2.0",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Homepage = "https://rine.network"
|
|
36
|
+
Documentation = "https://docs.rine.network"
|
|
37
|
+
Repository = "https://codeberg.org/rine/rine-hermes"
|
|
38
|
+
Issues = "https://codeberg.org/rine/rine-hermes/issues"
|
|
39
|
+
|
|
40
|
+
[project.entry-points."hermes_agent.plugins"]
|
|
41
|
+
# Value is the MODULE (not module:attr). Hermes' loader (_load_entrypoint_module) does
|
|
42
|
+
# ep.load() then getattr(module, "register"): a "hermes_rine:register" value loads the
|
|
43
|
+
# FUNCTION, then looks for `.register` on it → "no register() function". The Hermes docs
|
|
44
|
+
# example is `my-plugin = "my_plugin_package"` — point at the package.
|
|
45
|
+
rine = "hermes_rine"
|
|
46
|
+
|
|
47
|
+
[project.optional-dependencies]
|
|
48
|
+
dev = [
|
|
49
|
+
"pytest>=8.0",
|
|
50
|
+
"pytest-asyncio>=0.24",
|
|
51
|
+
"respx>=0.22",
|
|
52
|
+
"ruff>=0.8",
|
|
53
|
+
"mypy>=1.13",
|
|
54
|
+
"aiosqlite>=0.20",
|
|
55
|
+
# The enable helper round-trips config.yaml; in the Hermes venv ruamel/pyyaml are
|
|
56
|
+
# always present (Hermes deps), but the standalone test env needs a YAML parser.
|
|
57
|
+
"pyyaml>=6.0",
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
[tool.hatch.build.targets.sdist]
|
|
61
|
+
exclude = ["phases/", "e2e/", "tests/"]
|
|
62
|
+
|
|
63
|
+
[tool.hatch.build.targets.wheel]
|
|
64
|
+
packages = ["src/hermes_rine"]
|
|
65
|
+
|
|
66
|
+
[tool.pytest.ini_options]
|
|
67
|
+
testpaths = ["tests"]
|
|
68
|
+
pythonpath = ["src"]
|
|
69
|
+
asyncio_mode = "auto"
|
|
70
|
+
|
|
71
|
+
[tool.ruff]
|
|
72
|
+
target-version = "py311"
|
|
73
|
+
line-length = 99
|
|
74
|
+
src = ["src"]
|
|
75
|
+
|
|
76
|
+
[tool.ruff.lint]
|
|
77
|
+
select = [
|
|
78
|
+
"E", "F", "W", "I", "UP", "B", "SIM", "TCH",
|
|
79
|
+
"D101", "D102", "D103", "D107", "D205", "D400",
|
|
80
|
+
]
|
|
81
|
+
ignore = ["D100"]
|
|
82
|
+
|
|
83
|
+
[tool.ruff.lint.per-file-ignores]
|
|
84
|
+
# Test names are self-documenting `test_<what>_<when>_<expected>`; per-symbol
|
|
85
|
+
# docstrings would be noise.
|
|
86
|
+
"tests/**" = ["D101", "D102", "D103", "D107"]
|
|
87
|
+
# The live E2E driver is a script (excluded from the sdist), not library code.
|
|
88
|
+
"e2e/**" = ["D101", "D102", "D103", "D107", "E501"]
|
|
89
|
+
|
|
90
|
+
[tool.ruff.lint.pydocstyle]
|
|
91
|
+
convention = "google"
|
|
92
|
+
|
|
93
|
+
[tool.mypy]
|
|
94
|
+
python_version = "3.11"
|
|
95
|
+
strict = true
|
|
96
|
+
warn_return_any = true
|
|
97
|
+
warn_unused_configs = true
|
|
98
|
+
packages = ["hermes_rine"]
|
|
99
|
+
mypy_path = "src"
|
|
100
|
+
|
|
101
|
+
# Hermes internals (``tools.registry``, ``gateway.*``) are NOT a typed runtime
|
|
102
|
+
# dependency — they are only present on PYTHONPATH inside a live Hermes process /
|
|
103
|
+
# the Docker rig. At our boundary their values are legitimately ``Any`` (and the base
|
|
104
|
+
# adapter is ``Any`` when Hermes is absent). Relaxing return-Any/subclass strictness on
|
|
105
|
+
# exactly the boundary modules keeps the gate green WITH or WITHOUT hermes-agent
|
|
106
|
+
# installed, without weakening checks on our own typed code (_journal/_format/_client/
|
|
107
|
+
# _gate/_schemas). ``disable_error_code`` (not per-line ignores) avoids the
|
|
108
|
+
# ``warn_unused_ignores`` trap when Hermes IS present.
|
|
109
|
+
[[tool.mypy.overrides]]
|
|
110
|
+
module = [
|
|
111
|
+
"hermes_rine.adapter",
|
|
112
|
+
"hermes_rine._poll",
|
|
113
|
+
"hermes_rine._sse",
|
|
114
|
+
"hermes_rine.tools.messaging",
|
|
115
|
+
"hermes_rine.tools.discovery",
|
|
116
|
+
"hermes_rine.tools.groups",
|
|
117
|
+
]
|
|
118
|
+
warn_return_any = false
|
|
119
|
+
disable_error_code = ["no-any-return", "misc"]
|
|
120
|
+
|
|
121
|
+
# ``enable`` dynamically imports an optional YAML lib (ruamel/pyyaml) + ``hermes_cli`` —
|
|
122
|
+
# all absent / unstubbed off the Hermes venv, so their values are legitimately ``Any``
|
|
123
|
+
# and the import errors are environment-dependent. Disable just the import-resolution
|
|
124
|
+
# codes here (per-line ignores would be ``unused`` in the rig where the libs ARE present).
|
|
125
|
+
[[tool.mypy.overrides]]
|
|
126
|
+
module = ["hermes_rine.enable"]
|
|
127
|
+
disable_error_code = ["import-untyped", "import-not-found"]
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""hermes-rine — official Hermes Agent plugin for the Rine network.
|
|
2
|
+
|
|
3
|
+
A single plugin that is simultaneously a **tool set** (12 ``rine_*`` tools), an
|
|
4
|
+
**inbound channel** (a gateway platform adapter that wakes the agent on new mail),
|
|
5
|
+
and a **bundled skill** (``rine:rine``). All crypto, HTTP, and config-dir resolution
|
|
6
|
+
come from the ``rine`` SDK; this package never reimplements them.
|
|
7
|
+
|
|
8
|
+
**Import discipline (critical).** This module imports *nothing heavy*. ``import
|
|
9
|
+
hermes_rine`` succeeds even without ``hermes-agent`` installed and without the SDK
|
|
10
|
+
touching the network. The Hermes-internal registrars (``tools.registry``,
|
|
11
|
+
``gateway.platforms.base``, ``hermes_cli.plugins``) are imported **lazily inside
|
|
12
|
+
``register()``**, which only ever runs inside a live Hermes process. Likewise no
|
|
13
|
+
client is constructed, no credential is read, and no listener is started at import
|
|
14
|
+
or ``register()`` time — that work is deferred to a tool's first handler call or the
|
|
15
|
+
adapter's ``connect()``.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
21
|
+
from typing import Any
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
__version__ = version("hermes-rine")
|
|
25
|
+
except PackageNotFoundError: # not installed (e.g. running from a source checkout)
|
|
26
|
+
__version__ = "0.1.0"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def register(ctx: Any) -> None:
|
|
30
|
+
"""Hermes plugin entry point — wire up tools, skill, and platform.
|
|
31
|
+
|
|
32
|
+
Called by Hermes with a ``PluginContext`` once the plugin is enabled. Imports
|
|
33
|
+
the registrars lazily so the heavy Hermes-internal modules are only pulled in
|
|
34
|
+
inside a Hermes process (never at ``import hermes_rine`` time).
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
ctx: The Hermes ``PluginContext`` (``hermes_cli.plugins.PluginContext``).
|
|
38
|
+
"""
|
|
39
|
+
from hermes_rine.platform import register_rine_platform
|
|
40
|
+
from hermes_rine.skill_reg import register_rine_skill
|
|
41
|
+
from hermes_rine.tools import register_rine_tools
|
|
42
|
+
|
|
43
|
+
register_rine_tools(ctx)
|
|
44
|
+
register_rine_skill(ctx)
|
|
45
|
+
register_rine_platform(ctx)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
__all__ = ["__version__", "register"]
|