Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion adapters/common/src/nemo_fabric_adapters/common/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,9 +219,11 @@ def merge_unique(*values: Any) -> list[str]:
merged.append(item)
return merged


def without_none(mapping: dict[str, Any]) -> dict[str, Any]:
return {key: value for key, value in mapping.items() if value is not None}


def dump_yaml(value: dict[str, Any]) -> str:
try:
import yaml
Expand Down Expand Up @@ -409,7 +411,7 @@ def write_relay_configs(
relay_config_path.write_text(tomli_w.dumps(relay_config), encoding="utf-8")

if plugin_config is not None:
if observability_version != 2:
if observability_version not in {2, 3}:
raise ValueError(
f"unsupported NeMo Relay observability config version {observability_version}"
)
Expand Down
4 changes: 2 additions & 2 deletions adapters/hermes/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ harness = [
"hermes-agent[mcp]>=0.19.0; python_version < '3.14'",
]
relay = [
"nemo-relay>=0.6.0,<0.7",
"nemo-relay>=0.6.0,<0.8",
]
full = [
"hermes-agent[mcp]>=0.19.0; python_version < '3.14'",
"nemo-relay>=0.6.0,<0.7",
"nemo-relay>=0.6.0,<0.8",
Comment thread
zhongxuanwang-nv marked this conversation as resolved.
]

[project.urls]
Expand Down
281 changes: 164 additions & 117 deletions adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py

Large diffs are not rendered by default.

22 changes: 11 additions & 11 deletions adapters/hermes/uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 33 additions & 2 deletions python/src/nemo_fabric/streaming.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ def __init__(
self._accepting = False
self._request_id: str | None = None
self._turn_index: int | None = None
self._upstream_hermes_turn_id: str | None = None
self._turn_root_uuid: str | None = None
self._turn_scope_uuids: set[str] = set()
self._saw_atof_data = False
Expand Down Expand Up @@ -307,6 +308,7 @@ def begin_stream(
self._queue.get_nowait()
self._request_id = request_id
self._turn_index = turn_index
self._upstream_hermes_turn_id = None
self._turn_root_uuid = None
self._turn_scope_uuids.clear()
self._saw_atof_data = False
Expand All @@ -321,6 +323,7 @@ def end_stream(self) -> None:
self._accepting = False
self._request_id = None
self._turn_index = None
self._upstream_hermes_turn_id = None
self._turn_root_uuid = None
self._turn_scope_uuids.clear()

Expand Down Expand Up @@ -521,9 +524,28 @@ def _belongs_to_active_turn(self, record: dict[str, Any]) -> bool:
uuid = record.get("uuid")
if not isinstance(uuid, str):
return False
metadata = record.get("metadata")

# Hermes copies the task ID passed by Fabric into its Relay turn markers.
if (
self._upstream_hermes_turn_id is not None
and isinstance(metadata, dict)
and metadata.get("turn_id") == self._upstream_hermes_turn_id
):
if (
record.get("kind") == "scope"
and record.get("scope_category") == "start"
):
self._turn_scope_uuids.add(uuid)
return True

if self._turn_root_uuid is None:
if not self._matches_turn_root(record):
return False
if isinstance(metadata, dict) and record.get("kind") == "mark":
turn_id = metadata.get("turn_id")
if isinstance(turn_id, str):
self._upstream_hermes_turn_id = turn_id
self._turn_root_uuid = uuid
self._turn_scope_uuids.add(uuid)
self._matched_turn_root = True
Expand All @@ -542,11 +564,20 @@ def _belongs_to_active_turn(self, record: dict[str, Any]) -> bool:
return True

def _matches_turn_root(self, record: dict[str, Any]) -> bool:
if record.get("kind") != "scope" or record.get("scope_category") != "start":
return False
metadata = record.get("metadata")
if not isinstance(metadata, dict):
return False
if (
record.get("kind") == "mark"
and record.get("name") == "hermes.turn.start"
and metadata.get("platform") == "fabric"
and self._request_id is not None
and metadata.get("task_id") == self._request_id
and isinstance(metadata.get("turn_id"), str)
):
return True
Comment thread
zhongxuanwang-nv marked this conversation as resolved.
if record.get("kind") != "scope" or record.get("scope_category") != "start":
return False
if (
self._request_id is not None
and metadata.get("nemo_fabric_request_id") == self._request_id
Expand Down
6 changes: 2 additions & 4 deletions tests/adapters/test_adapter_package_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,8 @@ def load_pyproject(path: str) -> dict:
f"nemo-fabric-adapters-hermes[harness] == {PACKAGE_VERSION}; "
"python_version < '3.14'"
),
"harness": [
"hermes-agent[mcp]>=0.19.0; python_version < '3.14'"
],
"relay": ["nemo-relay>=0.6.0,<0.7"],
"harness": ["hermes-agent[mcp]>=0.19.0; python_version < '3.14'"],
"relay": ["nemo-relay>=0.6.0,<0.8"],
},
}

Expand Down
Loading
Loading