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.
@@ -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
+ ]