f7d5ac3230
A DM relayed from another Hermes profile ran as a turn in the recipient's Bot Chat session. sync_turn wrote the bot's words and the recipient's reply into that session, and before per-author writes they landed under the human's peer. The human's representation absorbed conversations the human never had. The turn context now marks such turns with scope a2a:<bot id>. sync_turn routes a bot-authored turn into a separate Honcho session keyed <session>:a2a:<sanitized bot id>, created with the sender bot as its user peer, and never writes it into the human's session. The key is deterministic so every turn from the same bot reaches the same session, and it stays inside Honcho's 100 character session id limit. Recall still reads the human's session only. a2aSessions (host block, then root, default true) turns the routing on. With it off, bot-authored turns are skipped. A bot turn that names no author id is skipped as well, because nothing can key its session. Human turns are unchanged. get_or_create takes a user_peer_id override so the a2a session's roster is the bot and the assistant, not the runtime human.
93 lines
3.2 KiB
Python
93 lines
3.2 KiB
Python
"""Tests for Honcho's declared config surface."""
|
|
|
|
from plugins.memory.config_schema import (
|
|
KIND_BOOL,
|
|
KIND_JSON,
|
|
KIND_NUMBER,
|
|
KIND_SECRET,
|
|
KIND_SELECT,
|
|
STORAGE_HONCHO_HOST_BLOCK,
|
|
get_provider_config_schema,
|
|
)
|
|
|
|
# The curated set shown in the compact panel; everything else lives in the modal.
|
|
INLINE_KEYS = {
|
|
"apiKey",
|
|
"baseUrl",
|
|
"environment",
|
|
"workspace",
|
|
"peerName",
|
|
"aiPeer",
|
|
"sessionStrategy",
|
|
}
|
|
|
|
|
|
def test_honcho_is_declared():
|
|
provider = get_provider_config_schema("honcho")
|
|
|
|
assert provider is not None
|
|
assert provider.label == "Honcho"
|
|
assert provider.storage == STORAGE_HONCHO_HOST_BLOCK
|
|
# Field keys are unique, and the curated inline set is present.
|
|
keys = [field.key for field in provider.fields]
|
|
assert len(keys) == len(set(keys))
|
|
assert INLINE_KEYS <= set(keys)
|
|
|
|
|
|
def test_inline_fields_are_the_curated_subset():
|
|
provider = get_provider_config_schema("honcho")
|
|
assert provider is not None
|
|
|
|
assert {field.key for field in provider.inline_fields()} == INLINE_KEYS
|
|
# The modal-only fields are a non-empty remainder.
|
|
non_inline = {f.key for f in provider.fields} - INLINE_KEYS
|
|
assert {"writeFrequency", "recallMode", "userPeerAliases"} <= non_inline
|
|
|
|
|
|
def test_declares_the_new_field_kinds():
|
|
provider = get_provider_config_schema("honcho")
|
|
assert provider is not None
|
|
|
|
by_key = {f.key: f for f in provider.fields}
|
|
assert by_key["saveMessages"].kind == KIND_BOOL
|
|
assert by_key["a2aSessions"].kind == KIND_BOOL
|
|
assert by_key["a2aSessions"].default == "true"
|
|
assert by_key["dialecticMaxChars"].kind == KIND_NUMBER
|
|
assert by_key["userPeerAliases"].kind == KIND_JSON
|
|
assert by_key["recallMode"].allowed_values() == {"hybrid", "context", "tools"}
|
|
assert by_key["observationMode"].allowed_values() == {"directional", "unified"}
|
|
|
|
|
|
def test_selects_constrain_their_values():
|
|
provider = get_provider_config_schema("honcho")
|
|
assert provider is not None
|
|
|
|
environment = next(f for f in provider.fields if f.key == "environment")
|
|
assert environment.kind == KIND_SELECT
|
|
# Honcho SDK only accepts local/production; "demo" is not a valid environment.
|
|
assert environment.allowed_values() == {"production", "local"}
|
|
|
|
strategy = next(f for f in provider.fields if f.key == "sessionStrategy")
|
|
assert strategy.allowed_values() == {"per-directory", "per-repo", "per-session", "global"}
|
|
|
|
|
|
def test_api_key_is_a_secret_bound_to_env():
|
|
provider = get_provider_config_schema("honcho")
|
|
assert provider is not None
|
|
|
|
api_key = next(f for f in provider.fields if f.key == "apiKey")
|
|
assert api_key.kind == KIND_SECRET
|
|
assert api_key.is_secret is True
|
|
assert api_key.env_key == "HONCHO_API_KEY"
|
|
|
|
|
|
def test_root_scoped_fields_are_exactly_the_global_ones():
|
|
provider = get_provider_config_schema("honcho")
|
|
assert provider is not None
|
|
|
|
scopes = {f.key: f.scope for f in provider.fields}
|
|
root_keys = {k for k, scope in scopes.items() if scope == "root"}
|
|
# baseUrl, timeout and sessions live at the config root in Honcho's schema;
|
|
# everything else is per-profile host-scoped.
|
|
assert root_keys == {"baseUrl", "timeout", "sessions"}
|