borgee-hermes-plugin 0.1.3__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.
Files changed (25) hide show
  1. borgee_hermes_plugin-0.1.3/LICENSE +21 -0
  2. borgee_hermes_plugin-0.1.3/MANIFEST.in +1 -0
  3. borgee_hermes_plugin-0.1.3/PKG-INFO +210 -0
  4. borgee_hermes_plugin-0.1.3/README.md +184 -0
  5. borgee_hermes_plugin-0.1.3/plugin.yaml +10 -0
  6. borgee_hermes_plugin-0.1.3/pyproject.toml +78 -0
  7. borgee_hermes_plugin-0.1.3/setup.cfg +4 -0
  8. borgee_hermes_plugin-0.1.3/src/borgee_hermes/__init__.py +44 -0
  9. borgee_hermes_plugin-0.1.3/src/borgee_hermes/adapter.py +1140 -0
  10. borgee_hermes_plugin-0.1.3/src/borgee_hermes/bridge.py +113 -0
  11. borgee_hermes_plugin-0.1.3/src/borgee_hermes/cli.py +114 -0
  12. borgee_hermes_plugin-0.1.3/src/borgee_hermes/config.py +120 -0
  13. borgee_hermes_plugin-0.1.3/src/borgee_hermes/inbox.py +1078 -0
  14. borgee_hermes_plugin-0.1.3/src/borgee_hermes/locks.py +115 -0
  15. borgee_hermes_plugin-0.1.3/src/borgee_hermes/py.typed +1 -0
  16. borgee_hermes_plugin-0.1.3/src/borgee_hermes/tools.py +640 -0
  17. borgee_hermes_plugin-0.1.3/src/borgee_hermes_plugin.egg-info/PKG-INFO +210 -0
  18. borgee_hermes_plugin-0.1.3/src/borgee_hermes_plugin.egg-info/SOURCES.txt +23 -0
  19. borgee_hermes_plugin-0.1.3/src/borgee_hermes_plugin.egg-info/dependency_links.txt +1 -0
  20. borgee_hermes_plugin-0.1.3/src/borgee_hermes_plugin.egg-info/entry_points.txt +5 -0
  21. borgee_hermes_plugin-0.1.3/src/borgee_hermes_plugin.egg-info/requires.txt +12 -0
  22. borgee_hermes_plugin-0.1.3/src/borgee_hermes_plugin.egg-info/top_level.txt +1 -0
  23. borgee_hermes_plugin-0.1.3/tests/test_adapter.py +1145 -0
  24. borgee_hermes_plugin-0.1.3/tests/test_config_and_locks.py +408 -0
  25. borgee_hermes_plugin-0.1.3/tests/test_inbox.py +444 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Borgee contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ include plugin.yaml
@@ -0,0 +1,210 @@
1
+ Metadata-Version: 2.4
2
+ Name: borgee-hermes-plugin
3
+ Version: 0.1.3
4
+ Summary: Borgee messaging platform adapter for Hermes Agent
5
+ License-Expression: MIT
6
+ Classifier: Development Status :: 3 - Alpha
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Programming Language :: Python :: 3.11
9
+ Classifier: Programming Language :: Python :: 3.12
10
+ Classifier: Programming Language :: Python :: 3.13
11
+ Requires-Python: <3.14,>=3.11
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: borgee-plugin-sdk==0.1.2
15
+ Requires-Dist: hermes-agent==0.18.2
16
+ Requires-Dist: pyyaml>=6.0
17
+ Provides-Extra: test
18
+ Requires-Dist: build==1.2.2.post1; extra == "test"
19
+ Requires-Dist: mypy==1.17.0; extra == "test"
20
+ Requires-Dist: pytest==9.0.3; extra == "test"
21
+ Requires-Dist: pytest-asyncio==1.3.0; extra == "test"
22
+ Requires-Dist: pytest-timeout==2.4.0; extra == "test"
23
+ Requires-Dist: ruff==0.12.4; extra == "test"
24
+ Requires-Dist: twine==6.1.0; extra == "test"
25
+ Dynamic: license-file
26
+
27
+ # Borgee platform for Hermes Agent
28
+
29
+ `borgee-hermes-plugin` connects one Hermes Agent 0.18.2 gateway profile to one Borgee agent over BPP. It depends on `borgee-plugin-sdk==0.1.2`; for local builds, install the SDK wheel before the plugin.
30
+
31
+ ## Compatibility
32
+
33
+ | Component | Supported version |
34
+ | --- | --- |
35
+ | Python | 3.11, 3.12, or 3.13 |
36
+ | Hermes distribution | `hermes-agent==0.18.2` |
37
+ | Hermes release source | `9de9c25f620ff7f1ce0fd5457d596052d5159596` |
38
+ | Borgee Python SDK | `borgee-plugin-sdk==0.1.2` |
39
+
40
+ This package and the SDK are licensed under the MIT License. The repository provides a manual workflow for publishing them to TestPyPI and PyPI; this documentation does not imply that a registry release has occurred.
41
+
42
+ ## Install
43
+
44
+ Build and install the local SDK first:
45
+
46
+ ```bash
47
+ python -m build --wheel packages/sdk/plugin-py
48
+ python -m pip install packages/sdk/plugin-py/dist/borgee_plugin_sdk-0.1.2-*.whl
49
+ python -m pip install packages/plugins/hermes
50
+ ```
51
+
52
+ Enable the entry-point plugin and configure the platform in the active Hermes
53
+ profile's `config.yaml`:
54
+
55
+ ```yaml
56
+ plugins:
57
+ enabled:
58
+ - borgee
59
+
60
+ group_sessions_per_user: false
61
+
62
+ display:
63
+ busy_input_mode: queue
64
+
65
+ streaming:
66
+ enabled: true
67
+
68
+ borgee:
69
+ enabled: true
70
+ base_url: https://chat.example.com
71
+ # Set true only for an explicit http://127.0.0.1 or http://localhost server.
72
+ allow_insecure_loopback: false
73
+ max_concurrent_dispatches: 4
74
+ drain_timeout_seconds: 30
75
+ ```
76
+
77
+ `streaming.enabled` is a global Hermes setting — it applies to every
78
+ connected platform by default. To disable streaming for a specific platform,
79
+ set `platforms.<name>.display.streaming.enabled: false` in that platform's
80
+ config block.
81
+
82
+ Put the agent API key in the active profile's `.env`:
83
+
84
+ ```dotenv
85
+ BORGEE_API_KEY=bgr_replace_with_the_agent_key
86
+ ```
87
+
88
+ `base_url` is non-secret and belongs in `config.yaml`. The API key is accepted
89
+ only through `BORGEE_API_KEY`; values in `config.yaml` are rejected. Hermes
90
+ loads each profile's own `.env`, so the same variable name remains
91
+ profile-isolated without inventing profile-suffixed secret names.
92
+
93
+ Run one Hermes process and one Borgee socket per `HERMES_HOME`. Leave
94
+ `gateway.multiplex_profiles` disabled. The adapter takes two Hermes scoped
95
+ interprocess locks in a fixed order: a canonical real-`HERMES_HOME` hash, then
96
+ the Borgee origin plus credential fingerprint. It releases credential then
97
+ profile. An owner-token registry applies the same exclusions within one process
98
+ where Hermes locks are PID-reentrant.
99
+
100
+ ## Delivery and session behavior
101
+
102
+ Borgee authenticates the BPP socket as one agent and applies channel membership
103
+ and require-mention policy before sending an event. The adapter therefore sets
104
+ Hermes `authorization_is_upstream=True`; it does not maintain a second local
105
+ allowlist.
106
+
107
+ Hermes DMs use `agent:main:borgee:dm:<channel-id>`. Channel conversations use
108
+ `agent:main:borgee:channel:<channel-id>`. The required top-level
109
+ `group_sessions_per_user: false` makes two authors in one channel share that
110
+ channel session while preserving their names on each inbound event.
111
+
112
+ The plugin checkpoints BPP only after it commits the complete receipt to
113
+ `$HERMES_HOME/plugins/borgee/inbox.sqlite3`. The SDK cursor advances after that
114
+ commit, while pending work remains in the durable inbox. A scheduler claims a
115
+ receipt in SQLite before calling Hermes, preserves FIFO within each ordinary
116
+ session, and permits bounded concurrency across sessions. Ingress stores an
117
+ `ordinary`, `control`, or `urgent_stop` dispatch class using Hermes' real
118
+ command, plugin-command, and clarify state before the receipt commit. If that
119
+ classification fails, the delivery is failed without a checkpoint.
120
+
121
+ SQLite open, close, and every submitted actor operation settle before
122
+ cancellation is rethrown. Cancelling open automatically closes any connection
123
+ created in the worker, shuts down that executor, and makes the actor
124
+ non-reusable. Close is idempotent and always finishes both connection and worker
125
+ shutdown, including when concurrent lifecycle callers are cancelled.
126
+
127
+ Hermes slash commands and pending clarify answers bypass an active ordinary
128
+ turn. `/queue <payload>` and `/q <payload>` are different: the adapter removes
129
+ the prefix in the receipt transaction and keeps the payload as a durable
130
+ ordinary turn until the session becomes idle. A bare `/queue` follows Hermes'
131
+ normal inline usage response.
132
+
133
+ The scheduler can find a persisted control past an arbitrarily deep ordinary
134
+ backlog, then rechecks the live Hermes bypass state before dispatch. If the
135
+ session became idle during that check, the receipt must wait for the ordinary
136
+ FIFO head. Ordinary and control work have independent bounded lanes, and
137
+ `/stop` has a separately reserved urgent slot. A timed-out control or urgent
138
+ execution releases its lane slot, suspends the matching Hermes session when it
139
+ exists, and quarantines the claimed receipt for explicit remediation.
140
+
141
+ ## Crash recovery
142
+
143
+ A receipt moves through this state machine:
144
+
145
+ ```text
146
+ pending -> processing -> completed | failed
147
+ \-> in_doubt -> quarantined
148
+ ```
149
+
150
+ The `pending -> processing` claim and its unique token commit before Hermes
151
+ runs. A crash after the claim may have performed tools or sent side effects, so
152
+ restart never replays that receipt automatically. Startup marks leftover
153
+ `processing` rows `in_doubt`, suspends every matching Hermes session before the
154
+ BPP SDK connects, and quarantines the rows. A missing Hermes session needs no
155
+ suspension because the next turn cannot continue its old tool tail, but its
156
+ receipt is still quarantined.
157
+
158
+ The host can expose the adapter's remediation library method to an operator:
159
+
160
+ ```python
161
+ await adapter.remediate_receipt(ingest_seq, "discard")
162
+
163
+ await adapter.remediate_receipt(
164
+ ingest_seq,
165
+ "requeue",
166
+ confirm_duplicate_side_effect_risk=True,
167
+ )
168
+ ```
169
+
170
+ Both actions reset an existing Hermes session first. `discard` records an
171
+ operator decision and never runs the message. `requeue` requires explicit
172
+ confirmation that tools, provider requests, or outbound effects might occur a
173
+ second time. There is no automatic requeue path.
174
+
175
+ During shutdown, the adapter stops admission, drains Hermes processing for the
176
+ configured bound, and then closes the BPP client, inbox, and both ownership
177
+ locks. Work that does not finish by the bound becomes `in_doubt` for the same
178
+ startup quarantine path.
179
+
180
+ A quarantined receipt blocks later ordinary turns only on its own Hermes
181
+ session lane until the operator discards or explicitly requeues it. Other
182
+ sessions remain schedulable; active session keys are excluded before the
183
+ database query applies its global candidate limit.
184
+
185
+ ## Outbound behavior
186
+
187
+ Hermes `send`, `edit_message(finalize=...)`, and `delete_message` map to BPP
188
+ semantic actions. Edit-based Hermes streaming creates a preview with `send`,
189
+ updates it with `edit_message`, and accepts the final `finalize=True` call.
190
+ Typing is a no-op because BPP task lifecycle frames already report real work;
191
+ the adapter does not invent a typing signal.
192
+
193
+ Every outbound message ID is persisted for echo filtering. The resolved Borgee
194
+ agent ID is also filtered, which closes the race where the server broadcasts an
195
+ agent-authored message before the outbound ID transaction completes.
196
+
197
+ Agent config updates are acknowledged as `rejected` with a legal BPP reason.
198
+ The MVP does not pretend to apply Borgee model, prompt, or tool changes to a
199
+ running Hermes conversation. Disabling the Borgee agent stops new intake and
200
+ the connection; BPP has no remote cancellation frame, so the plugin does not
201
+ claim that disable cancels a turn already executing inside Hermes. `/stop`
202
+ remains Hermes' real current-turn cancellation command.
203
+
204
+ ## MVP limits
205
+
206
+ The adapter intentionally excludes attachments, artifacts, history reads,
207
+ server `read_file` requests, REST side channels, multi-agent routing, and
208
+ multi-profile multiplexing. It handles only text messages and mentions.
209
+ Edited, deleted, and reaction events receive durable terminal receipts but do
210
+ not start inference.
@@ -0,0 +1,184 @@
1
+ # Borgee platform for Hermes Agent
2
+
3
+ `borgee-hermes-plugin` connects one Hermes Agent 0.18.2 gateway profile to one Borgee agent over BPP. It depends on `borgee-plugin-sdk==0.1.2`; for local builds, install the SDK wheel before the plugin.
4
+
5
+ ## Compatibility
6
+
7
+ | Component | Supported version |
8
+ | --- | --- |
9
+ | Python | 3.11, 3.12, or 3.13 |
10
+ | Hermes distribution | `hermes-agent==0.18.2` |
11
+ | Hermes release source | `9de9c25f620ff7f1ce0fd5457d596052d5159596` |
12
+ | Borgee Python SDK | `borgee-plugin-sdk==0.1.2` |
13
+
14
+ This package and the SDK are licensed under the MIT License. The repository provides a manual workflow for publishing them to TestPyPI and PyPI; this documentation does not imply that a registry release has occurred.
15
+
16
+ ## Install
17
+
18
+ Build and install the local SDK first:
19
+
20
+ ```bash
21
+ python -m build --wheel packages/sdk/plugin-py
22
+ python -m pip install packages/sdk/plugin-py/dist/borgee_plugin_sdk-0.1.2-*.whl
23
+ python -m pip install packages/plugins/hermes
24
+ ```
25
+
26
+ Enable the entry-point plugin and configure the platform in the active Hermes
27
+ profile's `config.yaml`:
28
+
29
+ ```yaml
30
+ plugins:
31
+ enabled:
32
+ - borgee
33
+
34
+ group_sessions_per_user: false
35
+
36
+ display:
37
+ busy_input_mode: queue
38
+
39
+ streaming:
40
+ enabled: true
41
+
42
+ borgee:
43
+ enabled: true
44
+ base_url: https://chat.example.com
45
+ # Set true only for an explicit http://127.0.0.1 or http://localhost server.
46
+ allow_insecure_loopback: false
47
+ max_concurrent_dispatches: 4
48
+ drain_timeout_seconds: 30
49
+ ```
50
+
51
+ `streaming.enabled` is a global Hermes setting — it applies to every
52
+ connected platform by default. To disable streaming for a specific platform,
53
+ set `platforms.<name>.display.streaming.enabled: false` in that platform's
54
+ config block.
55
+
56
+ Put the agent API key in the active profile's `.env`:
57
+
58
+ ```dotenv
59
+ BORGEE_API_KEY=bgr_replace_with_the_agent_key
60
+ ```
61
+
62
+ `base_url` is non-secret and belongs in `config.yaml`. The API key is accepted
63
+ only through `BORGEE_API_KEY`; values in `config.yaml` are rejected. Hermes
64
+ loads each profile's own `.env`, so the same variable name remains
65
+ profile-isolated without inventing profile-suffixed secret names.
66
+
67
+ Run one Hermes process and one Borgee socket per `HERMES_HOME`. Leave
68
+ `gateway.multiplex_profiles` disabled. The adapter takes two Hermes scoped
69
+ interprocess locks in a fixed order: a canonical real-`HERMES_HOME` hash, then
70
+ the Borgee origin plus credential fingerprint. It releases credential then
71
+ profile. An owner-token registry applies the same exclusions within one process
72
+ where Hermes locks are PID-reentrant.
73
+
74
+ ## Delivery and session behavior
75
+
76
+ Borgee authenticates the BPP socket as one agent and applies channel membership
77
+ and require-mention policy before sending an event. The adapter therefore sets
78
+ Hermes `authorization_is_upstream=True`; it does not maintain a second local
79
+ allowlist.
80
+
81
+ Hermes DMs use `agent:main:borgee:dm:<channel-id>`. Channel conversations use
82
+ `agent:main:borgee:channel:<channel-id>`. The required top-level
83
+ `group_sessions_per_user: false` makes two authors in one channel share that
84
+ channel session while preserving their names on each inbound event.
85
+
86
+ The plugin checkpoints BPP only after it commits the complete receipt to
87
+ `$HERMES_HOME/plugins/borgee/inbox.sqlite3`. The SDK cursor advances after that
88
+ commit, while pending work remains in the durable inbox. A scheduler claims a
89
+ receipt in SQLite before calling Hermes, preserves FIFO within each ordinary
90
+ session, and permits bounded concurrency across sessions. Ingress stores an
91
+ `ordinary`, `control`, or `urgent_stop` dispatch class using Hermes' real
92
+ command, plugin-command, and clarify state before the receipt commit. If that
93
+ classification fails, the delivery is failed without a checkpoint.
94
+
95
+ SQLite open, close, and every submitted actor operation settle before
96
+ cancellation is rethrown. Cancelling open automatically closes any connection
97
+ created in the worker, shuts down that executor, and makes the actor
98
+ non-reusable. Close is idempotent and always finishes both connection and worker
99
+ shutdown, including when concurrent lifecycle callers are cancelled.
100
+
101
+ Hermes slash commands and pending clarify answers bypass an active ordinary
102
+ turn. `/queue <payload>` and `/q <payload>` are different: the adapter removes
103
+ the prefix in the receipt transaction and keeps the payload as a durable
104
+ ordinary turn until the session becomes idle. A bare `/queue` follows Hermes'
105
+ normal inline usage response.
106
+
107
+ The scheduler can find a persisted control past an arbitrarily deep ordinary
108
+ backlog, then rechecks the live Hermes bypass state before dispatch. If the
109
+ session became idle during that check, the receipt must wait for the ordinary
110
+ FIFO head. Ordinary and control work have independent bounded lanes, and
111
+ `/stop` has a separately reserved urgent slot. A timed-out control or urgent
112
+ execution releases its lane slot, suspends the matching Hermes session when it
113
+ exists, and quarantines the claimed receipt for explicit remediation.
114
+
115
+ ## Crash recovery
116
+
117
+ A receipt moves through this state machine:
118
+
119
+ ```text
120
+ pending -> processing -> completed | failed
121
+ \-> in_doubt -> quarantined
122
+ ```
123
+
124
+ The `pending -> processing` claim and its unique token commit before Hermes
125
+ runs. A crash after the claim may have performed tools or sent side effects, so
126
+ restart never replays that receipt automatically. Startup marks leftover
127
+ `processing` rows `in_doubt`, suspends every matching Hermes session before the
128
+ BPP SDK connects, and quarantines the rows. A missing Hermes session needs no
129
+ suspension because the next turn cannot continue its old tool tail, but its
130
+ receipt is still quarantined.
131
+
132
+ The host can expose the adapter's remediation library method to an operator:
133
+
134
+ ```python
135
+ await adapter.remediate_receipt(ingest_seq, "discard")
136
+
137
+ await adapter.remediate_receipt(
138
+ ingest_seq,
139
+ "requeue",
140
+ confirm_duplicate_side_effect_risk=True,
141
+ )
142
+ ```
143
+
144
+ Both actions reset an existing Hermes session first. `discard` records an
145
+ operator decision and never runs the message. `requeue` requires explicit
146
+ confirmation that tools, provider requests, or outbound effects might occur a
147
+ second time. There is no automatic requeue path.
148
+
149
+ During shutdown, the adapter stops admission, drains Hermes processing for the
150
+ configured bound, and then closes the BPP client, inbox, and both ownership
151
+ locks. Work that does not finish by the bound becomes `in_doubt` for the same
152
+ startup quarantine path.
153
+
154
+ A quarantined receipt blocks later ordinary turns only on its own Hermes
155
+ session lane until the operator discards or explicitly requeues it. Other
156
+ sessions remain schedulable; active session keys are excluded before the
157
+ database query applies its global candidate limit.
158
+
159
+ ## Outbound behavior
160
+
161
+ Hermes `send`, `edit_message(finalize=...)`, and `delete_message` map to BPP
162
+ semantic actions. Edit-based Hermes streaming creates a preview with `send`,
163
+ updates it with `edit_message`, and accepts the final `finalize=True` call.
164
+ Typing is a no-op because BPP task lifecycle frames already report real work;
165
+ the adapter does not invent a typing signal.
166
+
167
+ Every outbound message ID is persisted for echo filtering. The resolved Borgee
168
+ agent ID is also filtered, which closes the race where the server broadcasts an
169
+ agent-authored message before the outbound ID transaction completes.
170
+
171
+ Agent config updates are acknowledged as `rejected` with a legal BPP reason.
172
+ The MVP does not pretend to apply Borgee model, prompt, or tool changes to a
173
+ running Hermes conversation. Disabling the Borgee agent stops new intake and
174
+ the connection; BPP has no remote cancellation frame, so the plugin does not
175
+ claim that disable cancels a turn already executing inside Hermes. `/stop`
176
+ remains Hermes' real current-turn cancellation command.
177
+
178
+ ## MVP limits
179
+
180
+ The adapter intentionally excludes attachments, artifacts, history reads,
181
+ server `read_file` requests, REST side channels, multi-agent routing, and
182
+ multi-profile multiplexing. It handles only text messages and mentions.
183
+ Edited, deleted, and reaction events receive durable terminal receipts but do
184
+ not start inference.
@@ -0,0 +1,10 @@
1
+ name: borgee
2
+ label: Borgee
3
+ kind: platform
4
+ version: 0.1.3
5
+ description: Borgee messaging platform adapter
6
+ requires_env:
7
+ - name: BORGEE_API_KEY
8
+ description: Agent API key issued by Borgee
9
+ prompt: Borgee agent API key
10
+ password: true
@@ -0,0 +1,78 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77.0,<83", "wheel==0.46.2"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "borgee-hermes-plugin"
7
+ version = "0.1.3"
8
+ description = "Borgee messaging platform adapter for Hermes Agent"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ requires-python = ">=3.11,<3.14"
13
+ dependencies = [
14
+ "borgee-plugin-sdk==0.1.2",
15
+ "hermes-agent==0.18.2",
16
+ "pyyaml>=6.0",
17
+ ]
18
+ classifiers = [
19
+ "Development Status :: 3 - Alpha",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ ]
25
+
26
+ [project.entry-points."hermes_agent.plugins"]
27
+ borgee = "borgee_hermes"
28
+
29
+ [project.scripts]
30
+ borgee-hermes = "borgee_hermes.cli:main"
31
+
32
+ [project.optional-dependencies]
33
+ test = [
34
+ "build==1.2.2.post1",
35
+ "mypy==1.17.0",
36
+ "pytest==9.0.3",
37
+ "pytest-asyncio==1.3.0",
38
+ "pytest-timeout==2.4.0",
39
+ "ruff==0.12.4",
40
+ "twine==6.1.0",
41
+ ]
42
+
43
+ [tool.setuptools]
44
+ package-dir = {"" = "src"}
45
+ include-package-data = true
46
+
47
+ [tool.setuptools.packages.find]
48
+ where = ["src"]
49
+
50
+ [tool.setuptools.package-data]
51
+ borgee_hermes = ["py.typed"]
52
+
53
+ [tool.setuptools.data-files]
54
+ "share/borgee-hermes-plugin" = ["plugin.yaml"]
55
+
56
+ [tool.pytest.ini_options]
57
+ addopts = "--strict-markers --timeout=30 --timeout-method=signal"
58
+ asyncio_mode = "auto"
59
+ testpaths = ["tests"]
60
+ markers = [
61
+ "integration: tests against the installed Hermes 0.18.2 runtime",
62
+ "e2e: cross-process tests using the real Go server and Hermes gateway",
63
+ ]
64
+
65
+ [tool.ruff]
66
+ target-version = "py311"
67
+ line-length = 110
68
+
69
+ [tool.ruff.lint]
70
+ select = ["E", "F", "I", "UP", "B", "ASYNC", "RUF"]
71
+
72
+ [tool.mypy]
73
+ python_version = "3.11"
74
+ strict = true
75
+ warn_unreachable = true
76
+ packages = ["borgee_hermes"]
77
+ ignore_missing_imports = true
78
+ disallow_subclassing_any = false
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,44 @@
1
+ """Borgee platform plugin for Hermes Agent."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from .adapter import BorgeePlatformAdapter
8
+ from .config import apply_yaml_config, check_requirements, validate_config
9
+ from .tools import register_borgee_tools, set_active_adapter
10
+
11
+ __version__ = "0.1.3"
12
+
13
+
14
+ def _adapter_factory(config: Any) -> BorgeePlatformAdapter:
15
+ """Create the adapter and expose its BPP client to the tool handlers."""
16
+ adapter = BorgeePlatformAdapter(config)
17
+ set_active_adapter(adapter)
18
+ return adapter
19
+
20
+
21
+ def register(ctx: Any) -> None:
22
+ """Register the Borgee messaging platform and tools with Hermes."""
23
+ ctx.register_platform(
24
+ name="borgee",
25
+ label="Borgee",
26
+ adapter_factory=_adapter_factory,
27
+ check_fn=check_requirements,
28
+ validate_config=validate_config,
29
+ required_env=["BORGEE_API_KEY"],
30
+ apply_yaml_config_fn=apply_yaml_config,
31
+ max_message_length=4096,
32
+ pii_safe=True,
33
+ allow_update_command=False,
34
+ platform_hint=(
35
+ "You are chatting through Borgee. Channel conversations are shared "
36
+ "with all channel members, so attribute participants by name."
37
+ ),
38
+ emoji="🟣",
39
+ )
40
+
41
+ register_borgee_tools(ctx)
42
+
43
+
44
+ __all__ = ["BorgeePlatformAdapter", "__version__", "register"]