Compare commits

...
Author SHA1 Message Date
Jai Suphavadeeprasit 06d11e3316 test(providers): expect conversation tags in Nous summaries
Update max-iteration summary assertions to include the agent session ID now attached to Nous Portal requests.
2026-07-15 16:39:06 -04:00
Jai Suphavadeeprasit 341f093b25 test(providers): update Nous parity test for conversation tag
The end-to-end _build_api_kwargs parity test asserted the Nous Portal
tags exactly equal the base two-tag list. With the per-session
conversation tag, a real agent (which has a session_id) now emits a
third `conversation=<session_id>` tag. Assert against
nous_portal_tags(session_id=agent.session_id) so the check stays exact.
2026-07-15 16:12:38 -04:00
Jai Suphavadeeprasit 76500c8b73 init 2026-07-15 16:06:49 -04:00
6 changed files with 65 additions and 6 deletions
+24 -2
View File
@@ -55,10 +55,32 @@ def hermes_client_tag() -> str:
return f"client=hermes-client-v{_hermes_version()}"
def nous_portal_tags() -> List[str]:
def conversation_tag(session_id: str) -> str:
"""Return the ``conversation=...`` tag for a Hermes session/conversation.
Format: ``conversation=<session_id>``. ``session_id`` is the canonical
Hermes conversation identifier (``AIAgent.session_id``) — the same value
used for ``~/.hermes/sessions/`` storage, session logs, and lineage.
Unlike the product/client tags this is high-cardinality (one value per
conversation), so it is only appended when a session id is actually
available — never as part of the always-on base tag set.
"""
return f"conversation={session_id}"
def nous_portal_tags(session_id: str | None = None) -> List[str]:
"""Return the canonical list of Nous Portal product tags.
Always returns a fresh list so callers can mutate it freely
(e.g. ``merged_extra.setdefault("tags", []).extend(nous_portal_tags())``).
When ``session_id`` is provided, a ``conversation=<session_id>`` tag is
appended so Portal usage can be attributed to a specific Hermes
conversation. Callers without a session id (e.g. the auxiliary client's
always-on base tags) omit it and get the canonical two-tag set.
"""
return ["product=hermes-agent", hermes_client_tag()]
tags = ["product=hermes-agent", hermes_client_tag()]
if session_id:
tags.append(conversation_tag(session_id))
return tags
+1 -1
View File
@@ -13,7 +13,7 @@ class NousProfile(ProviderProfile):
def build_extra_body(
self, *, session_id: str | None = None, **context
) -> dict[str, Any]:
body: dict[str, Any] = {"tags": nous_portal_tags()}
body: dict[str, Any] = {"tags": nous_portal_tags(session_id=session_id)}
provider_preferences = context.get("provider_preferences")
if provider_preferences:
body["provider"] = provider_preferences
+27
View File
@@ -42,6 +42,33 @@ def test_nous_portal_tags_returns_fresh_list():
assert "client=test-mutation" not in b
def test_conversation_tag_format():
"""The conversation tag carries the session id verbatim."""
from agent.portal_tags import conversation_tag
assert conversation_tag("abc-123") == "conversation=abc-123"
def test_nous_portal_tags_appends_conversation_when_session_id_given():
"""A session id adds a third, high-cardinality conversation tag."""
from agent.portal_tags import conversation_tag, nous_portal_tags
tags = nous_portal_tags(session_id="sess-42")
assert "product=hermes-agent" in tags
assert conversation_tag("sess-42") in tags
assert len(tags) == 3
def test_nous_portal_tags_omits_conversation_without_session_id():
"""Base tag set stays at two tags when no session id is available."""
from agent.portal_tags import nous_portal_tags
for empty in (None, ""):
tags = nous_portal_tags(session_id=empty)
assert len(tags) == 2
assert not any(t.startswith("conversation=") for t in tags)
def test_auxiliary_client_nous_extra_body_uses_helper():
"""auxiliary_client.NOUS_EXTRA_BODY must match the canonical helper output."""
from agent.auxiliary_client import NOUS_EXTRA_BODY
@@ -425,6 +425,12 @@ class TestNousProfile:
"provider": preferences,
}
def test_tags_include_conversation_when_session_id(self):
from agent.portal_tags import conversation_tag
p = get_provider_profile("nous")
body = p.build_extra_body(session_id="sess-99")
assert conversation_tag("sess-99") in body["tags"]
def test_auth_type(self):
p = get_provider_profile("nous")
assert p.auth_type == "oauth_device_code"
+1 -1
View File
@@ -429,7 +429,7 @@ class TestBuildApiKwargsNousPortal:
messages = [{"role": "user", "content": "hi"}]
kwargs = agent._build_api_kwargs(messages)
extra = kwargs.get("extra_body", {})
assert extra.get("tags") == nous_portal_tags()
assert extra.get("tags") == nous_portal_tags(session_id=agent.session_id)
def test_uses_chat_completions_format(self, monkeypatch):
agent = _make_agent(
+6 -2
View File
@@ -3973,7 +3973,9 @@ class TestHandleMaxIterations:
kwargs = agent.client.chat.completions.create.call_args.kwargs
from agent.portal_tags import nous_portal_tags
assert kwargs["extra_body"]["tags"] == nous_portal_tags()
assert kwargs["extra_body"]["tags"] == nous_portal_tags(
session_id=agent.session_id
)
assert kwargs["extra_body"]["provider"] == {
"only": ["deepseek"],
"ignore": ["deepinfra"],
@@ -3995,7 +3997,9 @@ class TestHandleMaxIterations:
kwargs = agent.client.chat.completions.create.call_args.kwargs
from agent.portal_tags import nous_portal_tags
assert kwargs["extra_body"] == {"tags": nous_portal_tags()}
assert kwargs["extra_body"] == {
"tags": nous_portal_tags(session_id=agent.session_id)
}
def test_summary_drops_invalid_provider_sort(self, agent):
agent.base_url = "https://openrouter.ai/api/v1"