hermes-agent-api-client 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_agent_api_client-0.1.0/LICENSE +35 -0
- hermes_agent_api_client-0.1.0/PKG-INFO +129 -0
- hermes_agent_api_client-0.1.0/README.md +110 -0
- hermes_agent_api_client-0.1.0/pyproject.toml +105 -0
- hermes_agent_api_client-0.1.0/src/hermes_agent_api_client/__init__.py +40 -0
- hermes_agent_api_client-0.1.0/src/hermes_agent_api_client/client.py +645 -0
- hermes_agent_api_client-0.1.0/src/hermes_agent_api_client/models.py +80 -0
- hermes_agent_api_client-0.1.0/src/hermes_agent_api_client/protocol.py +267 -0
- hermes_agent_api_client-0.1.0/src/hermes_agent_api_client/py.typed +0 -0
- hermes_agent_api_client-0.1.0/src/hermes_agent_api_client/sse.py +426 -0
- hermes_agent_api_client-0.1.0/uv.lock +749 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
Copyright (c) 2026 Avi Miller
|
|
2
|
+
|
|
3
|
+
The Universal Permissive License (UPL), Version 1.0
|
|
4
|
+
|
|
5
|
+
Subject to the condition set forth below, permission is hereby granted to any
|
|
6
|
+
person obtaining a copy of this software, associated documentation and/or data
|
|
7
|
+
(collectively the "Software"), free of charge and under any and all copyright
|
|
8
|
+
rights in the Software, and any and all patent rights owned or freely
|
|
9
|
+
licensable by each licensor hereunder covering either (i) the unmodified
|
|
10
|
+
Software as contributed to or provided by such licensor, or (ii) the Larger
|
|
11
|
+
Works (as defined below), to deal in both
|
|
12
|
+
|
|
13
|
+
(a) the Software, and
|
|
14
|
+
(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
|
|
15
|
+
one is included with the Software (each a "Larger Work" to which the Software
|
|
16
|
+
is contributed by such licensors),
|
|
17
|
+
|
|
18
|
+
without restriction, including without limitation the rights to copy, create
|
|
19
|
+
derivative works of, display, perform, and distribute the Software and make,
|
|
20
|
+
use, sell, offer for sale, import, export, have made, and have sold the
|
|
21
|
+
Software and the Larger Work(s), and to sublicense the foregoing rights on
|
|
22
|
+
either these or other terms.
|
|
23
|
+
|
|
24
|
+
This license is subject to the following condition:
|
|
25
|
+
The above copyright notice and either this complete permission notice or at
|
|
26
|
+
a minimum a reference to the UPL must be included in all copies or
|
|
27
|
+
substantial portions of the Software.
|
|
28
|
+
|
|
29
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
30
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
31
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
32
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
33
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
34
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
35
|
+
SOFTWARE.
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hermes-agent-api-client
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Typed async client for the Hermes Agent API Server
|
|
5
|
+
License-Expression: UPL-1.0
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
|
8
|
+
Classifier: Framework :: AsyncIO
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
12
|
+
Classifier: Typing :: Typed
|
|
13
|
+
Requires-Dist: httpx>=0.28.1,<1
|
|
14
|
+
Requires-Dist: pydantic>=2.13.4,<3
|
|
15
|
+
Requires-Python: >=3.13
|
|
16
|
+
Project-URL: Repository, https://github.com/Djelibeybi/hermes-agent-api-client
|
|
17
|
+
Project-URL: Issues, https://github.com/Djelibeybi/hermes-agent-api-client/issues
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# Hermes Agent API Client
|
|
21
|
+
|
|
22
|
+
Hermes Agent API Client is a typed async Python client for authenticated
|
|
23
|
+
capability discovery and streaming Chat Completions from the Hermes Agent API
|
|
24
|
+
Server. Version 0.1.0 requires Python 3.13 or later.
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
Install the package from PyPI:
|
|
29
|
+
|
|
30
|
+
```console
|
|
31
|
+
uv add hermes-agent-api-client
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Usage
|
|
35
|
+
|
|
36
|
+
`HermesAgentApiClient` is a single-use async context manager. Without an
|
|
37
|
+
injected HTTP client, it creates and closes its own `httpx.AsyncClient`:
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
from hermes_agent_api_client import HermesAgentApiClient, TerminalEvent
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
async def ask_hermes(request: dict[str, object]) -> None:
|
|
44
|
+
async with HermesAgentApiClient(
|
|
45
|
+
"https://hermes.example",
|
|
46
|
+
"bearer-key",
|
|
47
|
+
) as client:
|
|
48
|
+
capabilities = await client.probe_capabilities()
|
|
49
|
+
assert capabilities.chat_completions_streaming
|
|
50
|
+
|
|
51
|
+
async for event in client.stream_chat_events(request):
|
|
52
|
+
if isinstance(event, TerminalEvent):
|
|
53
|
+
print(event.outcome)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The default `verify=None` uses httpx's verified TLS default. An owned client may
|
|
57
|
+
instead receive `verify=False` or an `ssl.SSLContext`. Disabling certificate
|
|
58
|
+
verification weakens transport security and should be limited to controlled
|
|
59
|
+
environments.
|
|
60
|
+
|
|
61
|
+
To share a caller-managed client, inject it explicitly:
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
import httpx
|
|
65
|
+
|
|
66
|
+
from hermes_agent_api_client import HermesAgentApiClient
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
async def probe_with_shared_transport() -> None:
|
|
70
|
+
async with httpx.AsyncClient(verify=True) as http_client:
|
|
71
|
+
async with HermesAgentApiClient(
|
|
72
|
+
"https://hermes.example",
|
|
73
|
+
"bearer-key",
|
|
74
|
+
http_client=http_client,
|
|
75
|
+
) as client:
|
|
76
|
+
await client.probe_capabilities()
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The caller owns an injected client, so exiting `HermesAgentApiClient` does not
|
|
80
|
+
close it. TLS verification must be configured on the injected client; passing
|
|
81
|
+
both `http_client` and a non-`None` `verify` value is rejected.
|
|
82
|
+
|
|
83
|
+
## Supported contract
|
|
84
|
+
|
|
85
|
+
Version 0.1.0 supports only these Hermes operations:
|
|
86
|
+
|
|
87
|
+
- `GET /v1/capabilities` through `probe_capabilities()`.
|
|
88
|
+
- Streaming `POST /v1/chat/completions` through `stream_chat_events()`.
|
|
89
|
+
|
|
90
|
+
The exact OpenAI-compatible request document remains a caller-owned mapping;
|
|
91
|
+
version 0.1.0 does not define additional request-model semantics.
|
|
92
|
+
|
|
93
|
+
The stream yields immutable `AssistantDeltaEvent`, `ToolProgressEvent`,
|
|
94
|
+
`UsageEvent`, `KeepaliveEvent`, and `TerminalEvent` values. Terminal outcomes
|
|
95
|
+
are `success`, `length`, or `upstream_error`.
|
|
96
|
+
|
|
97
|
+
Public failures derive from `HermesContractError` and expose only safe
|
|
98
|
+
`category`, `status_code`, and `retryable` metadata. Authentication, HTTP
|
|
99
|
+
status, transport, and protocol failures are represented by distinct public
|
|
100
|
+
exception types. Callers should not expect upstream response bodies, bearer
|
|
101
|
+
credentials, request payloads, or URLs in public error text.
|
|
102
|
+
|
|
103
|
+
Compatibility targets Hermes v2026.7.7.2. Evidence is derived from captured
|
|
104
|
+
Hermes fixtures for that version and local protocol/transport tests; it is not
|
|
105
|
+
evidence from a live Hermes server.
|
|
106
|
+
|
|
107
|
+
> **Security:** Hermes API access exposes the configured agent toolset. Protect
|
|
108
|
+
> the bearer key, restrict network access, and grant the Hermes agent only the
|
|
109
|
+
> tools appropriate for the calling application.
|
|
110
|
+
|
|
111
|
+
## Development
|
|
112
|
+
|
|
113
|
+
Install the exact locked development environment and run all local gates:
|
|
114
|
+
|
|
115
|
+
```console
|
|
116
|
+
uv sync --locked --all-groups
|
|
117
|
+
uv run ruff format --check .
|
|
118
|
+
uv run ruff check .
|
|
119
|
+
uv run coverage run -m pytest
|
|
120
|
+
uv run coverage report
|
|
121
|
+
npx --yes pyright@1.1.411
|
|
122
|
+
uv run npx --yes pyright@1.1.411 --verifytypes hermes_agent_api_client --ignoreexternal
|
|
123
|
+
uv build
|
|
124
|
+
uv run python scripts/verify_dist.py dist/*.whl dist/*.tar.gz
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## License
|
|
128
|
+
|
|
129
|
+
Licensed under the Universal Permissive License 1.0 (UPL-1.0). See `LICENSE`.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Hermes Agent API Client
|
|
2
|
+
|
|
3
|
+
Hermes Agent API Client is a typed async Python client for authenticated
|
|
4
|
+
capability discovery and streaming Chat Completions from the Hermes Agent API
|
|
5
|
+
Server. Version 0.1.0 requires Python 3.13 or later.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
Install the package from PyPI:
|
|
10
|
+
|
|
11
|
+
```console
|
|
12
|
+
uv add hermes-agent-api-client
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
`HermesAgentApiClient` is a single-use async context manager. Without an
|
|
18
|
+
injected HTTP client, it creates and closes its own `httpx.AsyncClient`:
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
from hermes_agent_api_client import HermesAgentApiClient, TerminalEvent
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
async def ask_hermes(request: dict[str, object]) -> None:
|
|
25
|
+
async with HermesAgentApiClient(
|
|
26
|
+
"https://hermes.example",
|
|
27
|
+
"bearer-key",
|
|
28
|
+
) as client:
|
|
29
|
+
capabilities = await client.probe_capabilities()
|
|
30
|
+
assert capabilities.chat_completions_streaming
|
|
31
|
+
|
|
32
|
+
async for event in client.stream_chat_events(request):
|
|
33
|
+
if isinstance(event, TerminalEvent):
|
|
34
|
+
print(event.outcome)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The default `verify=None` uses httpx's verified TLS default. An owned client may
|
|
38
|
+
instead receive `verify=False` or an `ssl.SSLContext`. Disabling certificate
|
|
39
|
+
verification weakens transport security and should be limited to controlled
|
|
40
|
+
environments.
|
|
41
|
+
|
|
42
|
+
To share a caller-managed client, inject it explicitly:
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
import httpx
|
|
46
|
+
|
|
47
|
+
from hermes_agent_api_client import HermesAgentApiClient
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
async def probe_with_shared_transport() -> None:
|
|
51
|
+
async with httpx.AsyncClient(verify=True) as http_client:
|
|
52
|
+
async with HermesAgentApiClient(
|
|
53
|
+
"https://hermes.example",
|
|
54
|
+
"bearer-key",
|
|
55
|
+
http_client=http_client,
|
|
56
|
+
) as client:
|
|
57
|
+
await client.probe_capabilities()
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The caller owns an injected client, so exiting `HermesAgentApiClient` does not
|
|
61
|
+
close it. TLS verification must be configured on the injected client; passing
|
|
62
|
+
both `http_client` and a non-`None` `verify` value is rejected.
|
|
63
|
+
|
|
64
|
+
## Supported contract
|
|
65
|
+
|
|
66
|
+
Version 0.1.0 supports only these Hermes operations:
|
|
67
|
+
|
|
68
|
+
- `GET /v1/capabilities` through `probe_capabilities()`.
|
|
69
|
+
- Streaming `POST /v1/chat/completions` through `stream_chat_events()`.
|
|
70
|
+
|
|
71
|
+
The exact OpenAI-compatible request document remains a caller-owned mapping;
|
|
72
|
+
version 0.1.0 does not define additional request-model semantics.
|
|
73
|
+
|
|
74
|
+
The stream yields immutable `AssistantDeltaEvent`, `ToolProgressEvent`,
|
|
75
|
+
`UsageEvent`, `KeepaliveEvent`, and `TerminalEvent` values. Terminal outcomes
|
|
76
|
+
are `success`, `length`, or `upstream_error`.
|
|
77
|
+
|
|
78
|
+
Public failures derive from `HermesContractError` and expose only safe
|
|
79
|
+
`category`, `status_code`, and `retryable` metadata. Authentication, HTTP
|
|
80
|
+
status, transport, and protocol failures are represented by distinct public
|
|
81
|
+
exception types. Callers should not expect upstream response bodies, bearer
|
|
82
|
+
credentials, request payloads, or URLs in public error text.
|
|
83
|
+
|
|
84
|
+
Compatibility targets Hermes v2026.7.7.2. Evidence is derived from captured
|
|
85
|
+
Hermes fixtures for that version and local protocol/transport tests; it is not
|
|
86
|
+
evidence from a live Hermes server.
|
|
87
|
+
|
|
88
|
+
> **Security:** Hermes API access exposes the configured agent toolset. Protect
|
|
89
|
+
> the bearer key, restrict network access, and grant the Hermes agent only the
|
|
90
|
+
> tools appropriate for the calling application.
|
|
91
|
+
|
|
92
|
+
## Development
|
|
93
|
+
|
|
94
|
+
Install the exact locked development environment and run all local gates:
|
|
95
|
+
|
|
96
|
+
```console
|
|
97
|
+
uv sync --locked --all-groups
|
|
98
|
+
uv run ruff format --check .
|
|
99
|
+
uv run ruff check .
|
|
100
|
+
uv run coverage run -m pytest
|
|
101
|
+
uv run coverage report
|
|
102
|
+
npx --yes pyright@1.1.411
|
|
103
|
+
uv run npx --yes pyright@1.1.411 --verifytypes hermes_agent_api_client --ignoreexternal
|
|
104
|
+
uv build
|
|
105
|
+
uv run python scripts/verify_dist.py dist/*.whl dist/*.tar.gz
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## License
|
|
109
|
+
|
|
110
|
+
Licensed under the Universal Permissive License 1.0 (UPL-1.0). See `LICENSE`.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["uv_build>=0.11.28,<0.12"]
|
|
3
|
+
build-backend = "uv_build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "hermes-agent-api-client"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Typed async client for the Hermes Agent API Server"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.13"
|
|
11
|
+
license = "UPL-1.0"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 3 - Alpha",
|
|
15
|
+
"Framework :: AsyncIO",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3.13",
|
|
18
|
+
"Programming Language :: Python :: 3.14",
|
|
19
|
+
"Typing :: Typed",
|
|
20
|
+
]
|
|
21
|
+
dependencies = [
|
|
22
|
+
"httpx>=0.28.1,<1",
|
|
23
|
+
"pydantic>=2.13.4,<3",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[project.urls]
|
|
27
|
+
Repository = "https://github.com/Djelibeybi/hermes-agent-api-client"
|
|
28
|
+
Issues = "https://github.com/Djelibeybi/hermes-agent-api-client/issues"
|
|
29
|
+
|
|
30
|
+
[dependency-groups]
|
|
31
|
+
dev = [
|
|
32
|
+
"coverage[toml]==7.15.1",
|
|
33
|
+
"pytest==9.1.1",
|
|
34
|
+
"pytest-asyncio==1.4.0",
|
|
35
|
+
"respx==0.23.1",
|
|
36
|
+
"ruff==0.15.21",
|
|
37
|
+
]
|
|
38
|
+
release = [
|
|
39
|
+
"python-semantic-release==10.6.1",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[tool.uv]
|
|
43
|
+
required-version = "==0.11.28"
|
|
44
|
+
default-groups = ["dev"]
|
|
45
|
+
|
|
46
|
+
[tool.uv.build-backend]
|
|
47
|
+
source-include = ["uv.lock"]
|
|
48
|
+
|
|
49
|
+
[tool.semantic_release]
|
|
50
|
+
allow_zero_version = true
|
|
51
|
+
build_command = """
|
|
52
|
+
uv lock --upgrade-package "$PACKAGE_NAME"
|
|
53
|
+
uv build
|
|
54
|
+
"""
|
|
55
|
+
commit_message = "chore(release): {version} [skip ci]\n\nSigned-off-by: Avi Miller <me@dje.li>"
|
|
56
|
+
major_on_zero = false
|
|
57
|
+
version_toml = ["pyproject.toml:project.version"]
|
|
58
|
+
|
|
59
|
+
[tool.semantic_release.commit_parser_options]
|
|
60
|
+
ignore_merge_commits = true
|
|
61
|
+
minor_tags = ["feat"]
|
|
62
|
+
parse_squash_commits = true
|
|
63
|
+
patch_tags = ["fix", "perf"]
|
|
64
|
+
|
|
65
|
+
[tool.pytest.ini_options]
|
|
66
|
+
addopts = "-ra --strict-config --strict-markers"
|
|
67
|
+
asyncio_mode = "auto"
|
|
68
|
+
testpaths = ["tests"]
|
|
69
|
+
|
|
70
|
+
[tool.coverage.run]
|
|
71
|
+
branch = true
|
|
72
|
+
source = ["hermes_agent_api_client"]
|
|
73
|
+
|
|
74
|
+
[tool.coverage.report]
|
|
75
|
+
fail_under = 100
|
|
76
|
+
show_missing = true
|
|
77
|
+
skip_covered = true
|
|
78
|
+
|
|
79
|
+
[tool.ruff]
|
|
80
|
+
line-length = 88
|
|
81
|
+
target-version = "py313"
|
|
82
|
+
|
|
83
|
+
[tool.ruff.lint]
|
|
84
|
+
select = ["ALL"]
|
|
85
|
+
ignore = ["COM812", "D203", "D213", "ISC001"]
|
|
86
|
+
|
|
87
|
+
[tool.ruff.lint.per-file-ignores]
|
|
88
|
+
"tests/**/*.py" = ["S101", "SLF001"]
|
|
89
|
+
"tests/helpers/hermes.py" = [
|
|
90
|
+
"ANN401",
|
|
91
|
+
"B905",
|
|
92
|
+
"EM101",
|
|
93
|
+
"I001",
|
|
94
|
+
"RUF007",
|
|
95
|
+
"TC003",
|
|
96
|
+
"TRY003",
|
|
97
|
+
]
|
|
98
|
+
|
|
99
|
+
[tool.pyright]
|
|
100
|
+
include = ["src", "tests"]
|
|
101
|
+
ignore = ["tests/helpers/hermes.py"]
|
|
102
|
+
pythonVersion = "3.13"
|
|
103
|
+
typeCheckingMode = "strict"
|
|
104
|
+
venv = ".venv"
|
|
105
|
+
venvPath = "."
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""Typed async client for the Hermes Agent API Server."""
|
|
2
|
+
|
|
3
|
+
from .client import HermesAgentApiClient
|
|
4
|
+
from .models import (
|
|
5
|
+
AssistantDeltaEvent,
|
|
6
|
+
HermesCapabilities,
|
|
7
|
+
HermesEvent,
|
|
8
|
+
KeepaliveEvent,
|
|
9
|
+
TerminalEvent,
|
|
10
|
+
TerminalOutcome,
|
|
11
|
+
ToolProgressEvent,
|
|
12
|
+
UsageEvent,
|
|
13
|
+
)
|
|
14
|
+
from .protocol import (
|
|
15
|
+
HermesAuthenticationError,
|
|
16
|
+
HermesContractError,
|
|
17
|
+
HermesHttpStatusError,
|
|
18
|
+
HermesProtocolError,
|
|
19
|
+
HermesTransportError,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
__version__ = "0.1.0"
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"AssistantDeltaEvent",
|
|
26
|
+
"HermesAgentApiClient",
|
|
27
|
+
"HermesAuthenticationError",
|
|
28
|
+
"HermesCapabilities",
|
|
29
|
+
"HermesContractError",
|
|
30
|
+
"HermesEvent",
|
|
31
|
+
"HermesHttpStatusError",
|
|
32
|
+
"HermesProtocolError",
|
|
33
|
+
"HermesTransportError",
|
|
34
|
+
"KeepaliveEvent",
|
|
35
|
+
"TerminalEvent",
|
|
36
|
+
"TerminalOutcome",
|
|
37
|
+
"ToolProgressEvent",
|
|
38
|
+
"UsageEvent",
|
|
39
|
+
"__version__",
|
|
40
|
+
]
|