hermes-agent/tests/hermes_cli/test_memory_providers.py
Ben 03d9a95a74
fix(desktop): show Hindsight memory provider (#37546)
* fix(desktop): show Hindsight memory provider

* feat(desktop): configure Hindsight memory provider

* fix(desktop): limit Hindsight modes to supported setup

* refactor(desktop): generic memory-provider config surface

Replace the bespoke Hindsight settings surface with a declarative,
schema-driven path so adding a memory provider is pure declaration —
no per-provider page, conditional, or endpoint.

- memory_providers.py: declarative registry. Each provider lists its
  fields {key, label, kind, default, options, secret-vs-plain}. Hindsight's
  mode is a select(cloud, local_external), so rejecting local_embedded
  falls out of generic enum validation instead of a hand-written check.
- One generic endpoint pair GET/PUT /api/memory/providers/{name}/config.
  GET returns declared fields + current values (secrets only as is_set,
  never read back); PUT validates selects against their options, writes
  plain fields to the provider config file, secrets to the env store,
  and flips memory.provider.
- ProviderConfigPanel renders straight from the schema, replacing
  hindsight-settings.tsx and the memory.provider === 'hindsight'
  conditional in config-settings.tsx — same pattern as
  toolset-config-panel.tsx off env_vars.

Scoped to memory providers; storage layout is unchanged so the runtime
Hindsight plugin reads the same config.json / HINDSIGHT_API_KEY / provider
keys as before. Tests cover the registry, endpoint behavior (defaults,
write+secret, select rejection, unknown provider, secret-never-returned),
and the generic panel.
2026-06-18 16:48:47 -05:00

46 lines
1.3 KiB
Python

"""Tests for the declarative memory-provider registry."""
from hermes_cli.memory_providers import (
KIND_SECRET,
KIND_SELECT,
get_memory_provider,
)
def test_hindsight_is_declared():
provider = get_memory_provider("hindsight")
assert provider is not None
assert provider.label == "Hindsight"
assert {field.key for field in provider.fields} == {
"mode",
"api_key",
"api_url",
"bank_id",
"recall_budget",
}
def test_hindsight_mode_gating_is_expressed_as_select_options():
provider = get_memory_provider("hindsight")
assert provider is not None
mode = next(field for field in provider.fields if field.key == "mode")
assert mode.kind == KIND_SELECT
assert mode.allowed_values() == {"cloud", "local_external"}
# local_embedded is intentionally unsupported on desktop.
assert "local_embedded" not in mode.allowed_values()
def test_api_key_is_a_secret_bound_to_env():
provider = get_memory_provider("hindsight")
assert provider is not None
api_key = next(field for field in provider.fields if field.key == "api_key")
assert api_key.kind == KIND_SECRET
assert api_key.is_secret is True
assert api_key.env_key == "HINDSIGHT_API_KEY"
def test_unknown_provider_is_none():
assert get_memory_provider("builtin") is None