mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-24 16:54:43 +00:00
test(gateway): cover gateway.api_server YAML discovery + extra bridge; docs: document config.yaml support
Follow-up for salvaged PR #66633 (fixes #66630): - 5 tests: nested gateway.api_server discovery, port/key/host/model_name bridged into extra, explicit extra wins over top-level key, non-platform gateway keys (streaming/timeout) not misparsed, gateway.platforms.api_server path regression-guarded. - docs: api-server.md (en + zh-Hans) now documents the gateway.api_server YAML section instead of 'not yet supported'.
This commit is contained in:
parent
53e6435908
commit
6ced760a3d
3 changed files with 158 additions and 4 deletions
|
|
@ -728,6 +728,140 @@ class TestLoadGatewayConfig:
|
|||
|
||||
assert config.stt_echo_transcripts is False
|
||||
|
||||
@staticmethod
|
||||
def _clear_api_server_env(monkeypatch):
|
||||
"""Keep _apply_env_overrides from masking the YAML path under test."""
|
||||
for key in (
|
||||
"API_SERVER_ENABLED",
|
||||
"API_SERVER_KEY",
|
||||
"API_SERVER_PORT",
|
||||
"API_SERVER_HOST",
|
||||
"API_SERVER_CORS_ORIGINS",
|
||||
"API_SERVER_MODEL_NAME",
|
||||
):
|
||||
monkeypatch.delenv(key, raising=False)
|
||||
|
||||
def test_api_server_from_nested_gateway_section(self, tmp_path, monkeypatch):
|
||||
"""``gateway.api_server:`` (nested YAML form) must be discovered and
|
||||
enable the platform.
|
||||
|
||||
Regression for #66630: load_gateway_config handled gateway.streaming
|
||||
and gateway.platforms.* but silently dropped nested gateway.<platform>
|
||||
blocks, so ``gateway.api_server.enabled: true`` never started the API
|
||||
server unless API_SERVER_* env vars were also set.
|
||||
"""
|
||||
self._clear_api_server_env(monkeypatch)
|
||||
hermes_home = tmp_path / ".hermes"
|
||||
hermes_home.mkdir()
|
||||
(hermes_home / "config.yaml").write_text(
|
||||
"gateway:\n api_server:\n enabled: true\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
monkeypatch.setenv("HERMES_HOME", str(hermes_home))
|
||||
|
||||
config = load_gateway_config()
|
||||
|
||||
assert Platform.API_SERVER in config.platforms
|
||||
assert config.platforms[Platform.API_SERVER].enabled is True
|
||||
|
||||
def test_api_server_port_bridged_into_extra(self, tmp_path, monkeypatch):
|
||||
"""``gateway.api_server.port`` must land in PlatformConfig.extra —
|
||||
the adapter reads port/key/host/cors_origins/model_name from extra
|
||||
(gateway/platforms/api_server.py), and from_dict discards unknown
|
||||
top-level keys, so without the bridge the port is silently lost."""
|
||||
self._clear_api_server_env(monkeypatch)
|
||||
hermes_home = tmp_path / ".hermes"
|
||||
hermes_home.mkdir()
|
||||
(hermes_home / "config.yaml").write_text(
|
||||
"gateway:\n"
|
||||
" api_server:\n"
|
||||
" enabled: true\n"
|
||||
" port: 8642\n"
|
||||
" host: 0.0.0.0\n"
|
||||
" key: sekrit\n"
|
||||
" model_name: my-hermes\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
monkeypatch.setenv("HERMES_HOME", str(hermes_home))
|
||||
|
||||
config = load_gateway_config()
|
||||
|
||||
extra = config.platforms[Platform.API_SERVER].extra
|
||||
assert extra["port"] == 8642
|
||||
assert extra["host"] == "0.0.0.0"
|
||||
assert extra["key"] == "sekrit"
|
||||
assert extra["model_name"] == "my-hermes"
|
||||
|
||||
def test_api_server_explicit_extra_wins_over_toplevel_key(self, tmp_path, monkeypatch):
|
||||
"""An explicit ``extra: {port: X}`` must beat a sibling top-level
|
||||
``port:`` — the bridge's ``not in _api_extra`` guard must never
|
||||
clobber a value the user placed in extra deliberately."""
|
||||
self._clear_api_server_env(monkeypatch)
|
||||
hermes_home = tmp_path / ".hermes"
|
||||
hermes_home.mkdir()
|
||||
(hermes_home / "config.yaml").write_text(
|
||||
"gateway:\n"
|
||||
" api_server:\n"
|
||||
" enabled: true\n"
|
||||
" port: 9999\n"
|
||||
" extra:\n"
|
||||
" port: 8642\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
monkeypatch.setenv("HERMES_HOME", str(hermes_home))
|
||||
|
||||
config = load_gateway_config()
|
||||
|
||||
assert config.platforms[Platform.API_SERVER].extra["port"] == 8642
|
||||
|
||||
def test_non_platform_gateway_keys_not_misparsed_as_platforms(self, tmp_path, monkeypatch):
|
||||
"""Nested-platform discovery must only pick up keys matching the
|
||||
Platform enum: ``gateway.streaming`` / ``gateway.timeout`` must not
|
||||
be turned into phantom platform entries or break loading."""
|
||||
self._clear_api_server_env(monkeypatch)
|
||||
hermes_home = tmp_path / ".hermes"
|
||||
hermes_home.mkdir()
|
||||
(hermes_home / "config.yaml").write_text(
|
||||
"gateway:\n"
|
||||
" streaming:\n"
|
||||
" enabled: false\n"
|
||||
" timeout: 120\n"
|
||||
" api_server:\n"
|
||||
" enabled: true\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
monkeypatch.setenv("HERMES_HOME", str(hermes_home))
|
||||
|
||||
config = load_gateway_config()
|
||||
|
||||
# streaming still parsed as the streaming subsection, not a platform
|
||||
assert config.streaming.enabled is False
|
||||
# only real platforms present; nothing named streaming/timeout leaked in
|
||||
assert all(isinstance(p, Platform) for p in config.platforms)
|
||||
assert config.platforms[Platform.API_SERVER].enabled is True
|
||||
|
||||
def test_api_server_via_gateway_platforms_block_still_works(self, tmp_path, monkeypatch):
|
||||
"""No regression: the pre-existing ``gateway.platforms.api_server``
|
||||
path must keep working alongside the new nested discovery, and its
|
||||
api_server keys get the same extra bridge."""
|
||||
self._clear_api_server_env(monkeypatch)
|
||||
hermes_home = tmp_path / ".hermes"
|
||||
hermes_home.mkdir()
|
||||
(hermes_home / "config.yaml").write_text(
|
||||
"gateway:\n"
|
||||
" platforms:\n"
|
||||
" api_server:\n"
|
||||
" enabled: true\n"
|
||||
" port: 8643\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
monkeypatch.setenv("HERMES_HOME", str(hermes_home))
|
||||
|
||||
config = load_gateway_config()
|
||||
|
||||
assert config.platforms[Platform.API_SERVER].enabled is True
|
||||
assert config.platforms[Platform.API_SERVER].extra["port"] == 8643
|
||||
|
||||
def test_group_sessions_per_user_from_nested_gateway_section(self, tmp_path, monkeypatch):
|
||||
hermes_home = tmp_path / ".hermes"
|
||||
hermes_home.mkdir()
|
||||
|
|
|
|||
|
|
@ -426,11 +426,21 @@ The API server gives full access to hermes-agent's toolset, **including terminal
|
|||
|
||||
### config.yaml
|
||||
|
||||
The same settings can live in `~/.hermes/config.yaml` under a nested `gateway.api_server:` section:
|
||||
|
||||
```yaml
|
||||
# Not yet supported — use environment variables.
|
||||
# config.yaml support coming in a future release.
|
||||
gateway:
|
||||
api_server:
|
||||
enabled: true
|
||||
port: 8642
|
||||
host: 127.0.0.1
|
||||
key: your-secret-key
|
||||
cors_origins: http://localhost:3000
|
||||
model_name: my-hermes
|
||||
```
|
||||
|
||||
`port`, `key`, `host`, `cors_origins`, and `model_name` are automatically bridged into the platform's `extra` settings, so they behave exactly like their `API_SERVER_*` environment-variable counterparts. Environment variables take precedence over `config.yaml` values. The block is also accepted under `gateway.platforms.api_server:` or a top-level `platforms.api_server:` section.
|
||||
|
||||
## Security Headers
|
||||
|
||||
All responses include security headers:
|
||||
|
|
|
|||
|
|
@ -352,11 +352,21 @@ API 服务器提供对 hermes-agent 工具集的完整访问权限,**包括终
|
|||
|
||||
### config.yaml
|
||||
|
||||
相同的设置也可以写在 `~/.hermes/config.yaml` 中嵌套的 `gateway.api_server:` 小节下:
|
||||
|
||||
```yaml
|
||||
# 暂不支持——请使用环境变量。
|
||||
# config.yaml 支持将在未来版本中推出。
|
||||
gateway:
|
||||
api_server:
|
||||
enabled: true
|
||||
port: 8642
|
||||
host: 127.0.0.1
|
||||
key: your-secret-key
|
||||
cors_origins: http://localhost:3000
|
||||
model_name: my-hermes
|
||||
```
|
||||
|
||||
`port`、`key`、`host`、`cors_origins` 和 `model_name` 会自动桥接到该平台的 `extra` 设置中,行为与对应的 `API_SERVER_*` 环境变量完全一致。环境变量优先于 `config.yaml` 中的值。该配置块同样可以放在 `gateway.platforms.api_server:` 或顶层 `platforms.api_server:` 小节下。
|
||||
|
||||
## 安全响应头
|
||||
|
||||
所有响应均包含安全响应头:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue