simplify(compat): plugins/memory — drop 15 re-exports + 1 alias, repoint 13 test callers

hindsight: drop _PORT_HEALTH_GRACE_ENV/_sanitize_bank_segment facade re-exports (tests -> .embedded/.settings).
honcho: drop 5 tool-schema re-exports, _credential_fingerprint (-> client_cache), _is_auth_error (-> session_auth),
and the _redact_tokens alias (callers renamed to redact_tokens).
openviking: drop 5 _setup re-exports; tests call openviking_module._setup.* directly.
This commit is contained in:
Teknium
2026-09-03 13:04:16 -07:00
parent 9e3df66e95
commit ecf760db96
16 changed files with 25 additions and 124 deletions
-24
View File
@@ -1,24 +0,0 @@
"""Compatibility shim — the real implementation is ``hermes_startup_watchdog``.
The startup-liveness watchdog must be armable *before* the ``gateway`` package
is imported (``gateway/__init__`` eagerly pulls in the config/session/delivery
graph, and an import-time deadlock is inside the watchdog's coverage mandate),
so the implementation lives at the repository top level as a stdlib-only
module. This shim keeps ``gateway.startup_watchdog`` importable for code that
runs after the package is loaded (the disarm site in ``gateway.run``, tests).
"""
from hermes_startup_watchdog import ( # noqa: F401
DEFAULT_STARTUP_WATCHDOG_TIMEOUT_S,
ENV_STARTUP_WATCHDOG,
ENV_STARTUP_WATCHDOG_TIMEOUT_S,
SERVICE_RESTART_EXIT_CODE,
StartupWatchdogHandle,
arm_startup_watchdog,
disarm_startup_watchdog,
get_startup_watchdog_dump_path,
kick_startup_watchdog,
report_startup_progress,
resolve_startup_watchdog_timeout,
startup_watchdog_disabled,
)
@@ -1,9 +0,0 @@
"""Compatibility alias for the core Hermes Relay runtime."""
from __future__ import annotations
import sys
from agent import relay_runtime as _core_relay_runtime
sys.modules[__name__] = _core_relay_runtime
+4 -5
View File
@@ -32,18 +32,17 @@ from hermes_constants import get_hermes_home
from hermes_time import now as _hermes_now
from tools.registry import tool_error
# Re-exported (tests patch/import these via this module).
from .embedded import ( # noqa: F401
_PORT_HEALTH_GRACE_ENV, _RETRIABLE_CONNECTION_MARKERS, _build_embedded_profile_env,
from .embedded import (
_RETRIABLE_CONNECTION_MARKERS, _build_embedded_profile_env,
_check_local_runtime, _embedded_llm_api_key, _embedded_profile_env_path,
_export_port_health_grace_timeout, _load_simple_env, _local_runtime_hint, _materialize_embedded_profile_env,
)
from .settings import ( # noqa: F401
from .settings import (
_DEFAULT_API_URL, _DEFAULT_IDLE_TIMEOUT, _DEFAULT_LOCAL_URL, _DEFAULT_RETAIN_SOURCE,
_DEFAULT_TIMEOUT, _HINDSIGHT_GLYPH, _MIN_CLIENT_VERSION, _MIN_VERSION_FOR_UPDATE_MODE_APPEND,
_PROVIDER_DEFAULT_MODELS, _VALID_BUDGETS, _daemon_llm_provider,
_normalize_observation_scopes, _normalize_retain_tags, _parse_int_setting,
_resolve_bank_id_template, _sanitize_bank_segment,
_resolve_bank_id_template,
)
logger = logging.getLogger(__name__)
+1 -3
View File
@@ -19,9 +19,7 @@ from agent.memory_manager import sanitize_context
from agent.memory_provider import MemoryProvider, is_trivial_prompt
from plugins.memory.honcho.client import spawn_context_thread
from plugins.memory.honcho.dialectic import DialecticMixin
from plugins.memory.honcho.tool_schemas import ( # noqa: F401 — re-exported
ALL_TOOL_SCHEMAS, CONCLUDE_SCHEMA, CONTEXT_SCHEMA, PROFILE_SCHEMA, REASONING_SCHEMA, SEARCH_SCHEMA,
)
from plugins.memory.honcho.tool_schemas import ALL_TOOL_SCHEMAS
from tools.registry import tool_error
logger = logging.getLogger(__name__)
+2 -4
View File
@@ -27,10 +27,8 @@ from agent.secret_scope import get_secret
from hermes_cli.profiles import _get_default_hermes_home
from hermes_constants import get_hermes_home
# Cache/slot cluster lives in client_cache.py; re-exported because tests and reset
# bookkeeping reach these names through this module.
from plugins.memory.honcho.client_cache import ( # noqa: F401
_DEFAULT_HTTP_TIMEOUT, _client_cache_key, _client_slots, _client_slots_lock, _credential_fingerprint,
from plugins.memory.honcho.client_cache import (
_DEFAULT_HTTP_TIMEOUT, _client_cache_key, _client_slots, _client_slots_lock,
_honcho_json_timeout_memo, _refresh_oauth, _slot_for,
)
+3 -5
View File
@@ -43,8 +43,6 @@ def redact_tokens(text: str) -> str:
"""Replace any embedded token values with their prefix plus a placeholder."""
return _TOKEN_VALUE_RE.sub(lambda m: f"{m.group(1)}[redacted]", text)
_redact_tokens = redact_tokens # backward-compat alias for older importers
class OAuthRefreshError(Exception):
"""Token endpoint rejected the refresh. ``permanent`` means re-login is required."""
@@ -231,7 +229,7 @@ def _exchange_refresh_token(
if status >= 400:
error, description = str(body.get("error") or ""), str(body.get("error_description") or "")
detail = " — ".join(p for p in (error, description) if p) or "no error body"
message = _redact_tokens(f"token endpoint returned HTTP {status}: {detail}")
message = redact_tokens(f"token endpoint returned HTTP {status}: {detail}")
raise OAuthRefreshError(message, error=error, permanent=error in _PERMANENT_OAUTH_ERRORS)
return OAuthCredential.from_token_response(
body, now=now, client_id=cred.client_id, token_endpoint=cred.token_endpoint,
@@ -251,7 +249,7 @@ def _exchange_with_retry(cred: OAuthCredential, *, now: float) -> OAuthCredentia
remaining = deadline - time.monotonic() - _REFRESH_RETRY_DELAY_SECONDS
if remaining <= 0:
raise first
logger.warning("Honcho OAuth token exchange failed, retrying once: %s", _redact_tokens(str(first)))
logger.warning("Honcho OAuth token exchange failed, retrying once: %s", redact_tokens(str(first)))
time.sleep(_REFRESH_RETRY_DELAY_SECONDS)
return _exchange_refresh_token(cred, now=now, timeout=min(remaining, _REFRESH_TIMEOUT_SECONDS))
@@ -269,7 +267,7 @@ def _rotate_and_persist(
"run 'hermes honcho setup' to re-authenticate", host, exc)
return None
_refresh_failure_at[key] = time.monotonic()
logger.warning("Honcho OAuth %s failed for host %s: %s", op_label, host, _redact_tokens(str(exc)))
logger.warning("Honcho OAuth %s failed for host %s: %s", op_label, host, redact_tokens(str(exc)))
return None
_persist_credential(path, host, rotated)
return rotated
+1 -1
View File
@@ -11,7 +11,7 @@ from datetime import datetime
from typing import Any, TYPE_CHECKING
from plugins.memory.honcho.client import get_honcho_client, spawn_context_thread
from plugins.memory.honcho.session_auth import HonchoAuthError, SessionAuthMixin, _is_auth_error # noqa: F401 — re-exported
from plugins.memory.honcho.session_auth import HonchoAuthError, SessionAuthMixin
from plugins.memory.honcho.session_context import SessionContextMixin
from plugins.memory.honcho.session_migration import SessionMigrationMixin
from plugins.memory.honcho.session_peers import SessionPeersMixin
-7
View File
@@ -1037,13 +1037,6 @@ def _classify_runtime_openviking_health(client: _VikingClient, endpoint: str) ->
from . import _setup # noqa: E402 (needs the helpers above at call time)
from ._setup import ( # noqa: E402,F401 re-exported: tests and callers patch these here
_SETUP_CANCELLED,
_handle_unreachable_endpoint,
_link_ovcli_profile,
_prompt_manual_connection_values,
_save_hermes_only_config,
)
# -- MemoryProvider implementation ------------------------------------------
@@ -1,53 +0,0 @@
"""Descriptor <- PlatformEntry projection (relay Phase 0, Task 0.3).
Proves the CapabilityDescriptor is a projection of the existing PlatformEntry,
not a parallel concept: the entry's label/limit/emoji/hint/pii fields carry
straight through.
"""
from gateway.platform_registry import PlatformEntry
from gateway.relay.descriptor import CONTRACT_VERSION, CapabilityDescriptor
def _entry(**overrides) -> PlatformEntry:
base = dict(
name="telegram",
label="Telegram",
adapter_factory=lambda cfg: None,
check_fn=lambda: True,
max_message_length=4096,
pii_safe=False,
emoji="\u2708\ufe0f",
platform_hint="You are on Telegram.",
)
base.update(overrides)
return PlatformEntry(**base)
def test_projection_carries_platform_entry_fields():
d = CapabilityDescriptor.from_platform_entry(_entry(), len_unit="utf16")
assert d.contract_version == CONTRACT_VERSION
assert d.platform == "telegram"
assert d.label == "Telegram"
assert d.max_message_length == 4096
assert d.emoji == "\u2708\ufe0f"
assert d.platform_hint == "You are on Telegram."
assert d.pii_safe is False
assert d.len_unit == "utf16"
def test_projection_defaults_for_runtime_bits():
# Bits PlatformEntry does not encode take the documented defaults.
d = CapabilityDescriptor.from_platform_entry(_entry())
assert d.len_unit == "chars"
assert d.supports_draft_streaming is False
assert d.supports_edit is True
assert d.supports_threads is False
assert d.markdown_dialect == "plain"
def test_zero_unlimited_length_normalizes_to_chunking_default():
# PlatformEntry uses 0 for "no limit"; the descriptor must always carry a
# concrete chunking bound (the stream_consumer default of 4096).
d = CapabilityDescriptor.from_platform_entry(_entry(max_message_length=0))
assert d.max_message_length == 4096
+2 -2
View File
@@ -18,8 +18,8 @@ from plugins.memory.honcho.session import (
HonchoAuthError,
HonchoSession,
HonchoSessionManager,
_is_auth_error,
)
from plugins.memory.honcho.session_auth import _is_auth_error
def _host_block(refresh="hch-rt-old", expires_at=100):
@@ -154,7 +154,7 @@ class TestExchangeRetry:
assert "grant revoked" in caplog.text
def test_redaction_strips_token_values(self):
redacted = oauth._redact_tokens(
redacted = oauth.redact_tokens(
"exchange failed for hch-rt-supersecret123 got hch-at-alsosecret456"
)
assert "supersecret123" not in redacted
@@ -21,6 +21,7 @@ import threading
import pytest
import plugins.memory.honcho.client as client_mod
import plugins.memory.honcho.client_cache as client_cache_mod
from hermes_constants import reset_hermes_home_override, set_hermes_home_override
from plugins.memory.honcho.client import (
HonchoClientConfig,
@@ -245,12 +246,12 @@ class TestCredentialIdentity:
token = set_hermes_home_override(home)
try:
cfg1 = HonchoClientConfig.from_global_config()
fp1 = client_mod._credential_fingerprint(cfg1)
fp1 = client_cache_mod._credential_fingerprint(cfg1)
# Access token rotates in place; refresh token unchanged.
cfg_rotated = HonchoClientConfig.from_global_config()
cfg_rotated.api_key = "access-token-2"
fp_rotated = client_mod._credential_fingerprint(cfg_rotated)
fp_rotated = client_cache_mod._credential_fingerprint(cfg_rotated)
# Re-auth: new refresh token.
oauth_block2 = dict(oauth_block, refreshToken="refresh-2")
@@ -259,7 +260,7 @@ class TestCredentialIdentity:
"oauth": oauth_block2}},
}))
cfg2 = HonchoClientConfig.from_global_config()
fp2 = client_mod._credential_fingerprint(cfg2)
fp2 = client_cache_mod._credential_fingerprint(cfg2)
finally:
reset_hermes_home_override(token)
+1 -1
View File
@@ -131,7 +131,7 @@ class TestPeerLookupHelpers:
class TestConcludeToolDispatch:
def test_conclude_schema_has_no_anyof(self):
"""anyOf/oneOf/allOf breaks Anthropic and Fireworks APIs — schema must be plain object."""
from plugins.memory.honcho import CONCLUDE_SCHEMA
from plugins.memory.honcho.tool_schemas import CONCLUDE_SCHEMA
params = CONCLUDE_SCHEMA["parameters"]
assert params["type"] == "object"
assert "conclusion" in params["properties"]
@@ -32,9 +32,9 @@ from plugins.memory.hindsight import (
_normalize_observation_scopes,
_normalize_retain_tags,
_resolve_bank_id_template,
_sanitize_bank_segment,
_WRITER_SENTINEL,
)
from plugins.memory.hindsight.settings import _sanitize_bank_segment
# ---------------------------------------------------------------------------
@@ -192,7 +192,7 @@ def test_hermes_only_save_uses_the_same_clean_values_in_file_and_process(
from dotenv import dotenv_values
env_path = tmp_path / ".env"
ov._save_hermes_only_config(
ov._setup._save_hermes_only_config(
config={"memory": {}},
provider_config={},
env_path=env_path,
@@ -226,7 +226,7 @@ def test_hermes_only_save_failure_leaves_process_environment_unchanged(
monkeypatch.setattr(ov, "_write_env_vars", fail_write)
with pytest.raises(OSError, match="test write failure"):
ov._save_hermes_only_config(
ov._setup._save_hermes_only_config(
config={"memory": {}},
provider_config={},
env_path=tmp_path / ".env",
@@ -243,7 +243,7 @@ def test_link_ovcli_profile_removes_stale_inline_config(tmp_path):
}
ovcli_path = tmp_path / "ovcli.conf.VPS_ROOT"
openviking_module._link_ovcli_profile(
openviking_module._setup._link_ovcli_profile(
config=config,
provider_config=provider_config,
env_path=env_path,
@@ -347,7 +347,7 @@ def test_local_setup_recommends_user_api_key_before_unauthenticated_mode(monkeyp
return "user-key"
raise AssertionError(f"Unexpected prompt: {label}")
values = openviking_module._prompt_manual_connection_values(
values = openviking_module._setup._prompt_manual_connection_values(
prompt,
select,
-1,
@@ -611,7 +611,7 @@ def test_handle_unreachable_endpoint_waits_long_enough_after_autostart(monkeypat
lambda endpoint, *, timeout_seconds=0: wait_calls.append((endpoint, timeout_seconds)) or True,
)
result = openviking_module._handle_unreachable_endpoint(
result = openviking_module._setup._handle_unreachable_endpoint(
"http://127.0.0.1:1934",
"OpenViking server is not reachable.",
lambda *args, **kwargs: 0,
@@ -13,7 +13,7 @@ import pytest
hindsight = importlib.import_module("plugins.memory.hindsight")
_export = hindsight._export_port_health_grace_timeout
_ENV = hindsight._PORT_HEALTH_GRACE_ENV
_ENV = importlib.import_module("plugins.memory.hindsight.embedded")._PORT_HEALTH_GRACE_ENV
@pytest.fixture(autouse=True)