Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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 packages/nemo_platform/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,9 @@ nemo-agents-plugin = [
"boto3>=1.40.46,<1.40.62",
"botocore>=1.40.46,<1.40.62",
"httpx>=0.27",
"nemo-fabric>=0.1.0a20260717,<0.2.0",
"nemo-fabric[runtime]==0.1.0a1",
"nemo-fabric-adapters-codex==0.1.0a1",
"nemo-fabric-adapters-hermes==0.1.0a1; python_version < '3.14'",
"pyyaml>=6.0",
"anthropic>=0.88.0",
"rich>=13.7.1",
Expand Down
2 changes: 2 additions & 0 deletions plugins/nemo-agents/examples/nemo-agent-config/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
artifacts/
workspace/
41 changes: 41 additions & 0 deletions plugins/nemo-agents/examples/nemo-agent-config/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Fabric-Backed Agent Config

This Platform-owned config invokes Codex or Hermes through NeMo Fabric. Run the
commands below from the repository root.

## Codex

Authenticate Codex, leave `default_harness: codex` in `agent.yaml`, and run:

```bash
npm install -g @openai/codex
codex login

nemo agents invoke \
--agent-config plugins/nemo-agents/examples/nemo-agent-config/agent.yaml \
--input "Reply with exactly: platform fabric works"
```

## Hermes

Hermes Agent has dependencies that conflict with the Platform environment, so
install it with the Fabric adapter in a separate Python 3.12 environment:

```bash
uvx uv@0.9.14 venv --python 3.12 .venv-hermes
uvx uv@0.9.14 --no-config pip install \
--python .venv-hermes/bin/python \
"nemo-fabric-adapters-hermes==0.1.0a20260722" \
"hermes-agent==0.19.0"

export HERMES_ADAPTER_PYTHON="$PWD/.venv-hermes/bin/python"
export NVIDIA_API_KEY="<your NVIDIA API key>"
```

Temporarily set `default_harness: hermes` in `agent.yaml`, then run:

```bash
nemo agents invoke \
--agent-config plugins/nemo-agents/examples/nemo-agent-config/agent.yaml \
--input "Reply with exactly: platform hermes works"
```
Comment thread
mmogallapalli marked this conversation as resolved.
4 changes: 2 additions & 2 deletions plugins/nemo-agents/examples/nemo-agent-config/agent.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ config_format: nemo-agents-spec-v1
name: test-agent
description: Test agent config

default_harness: hermes
default_harness: codex

harnesses:
hermes:
Expand All @@ -13,6 +13,7 @@ harnesses:
api_key_env: NVIDIA_API_KEY
temperature: 0.0
settings:
python_env: HERMES_ADAPTER_PYTHON
base_url: https://integrate.api.nvidia.com/v1
max_iterations: 1
max_tokens: 512
Expand All @@ -24,7 +25,6 @@ harnesses:
kind: codex
settings:
sandbox: workspace-write
skip_git_repo_check: true
config_overrides:
model_reasoning_effort: high

Expand Down
4 changes: 3 additions & 1 deletion plugins/nemo-agents/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ dependencies = [
"httpx>=0.27",
# TODO(AIRCORE-897): Move this to a stable Fabric version before release once available.
# TODO(AIRCORE-897): Add the `relay` extra once nemo-evaluator-sdk's nemo-relay pin allows >=0.5.
"nemo-fabric>=0.1.0a20260717,<0.2.0",
"nemo-fabric[runtime]==0.1.0a1",
"nemo-fabric-adapters-codex==0.1.0a1",
"nemo-fabric-adapters-hermes==0.1.0a1; python_version < '3.14'",
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
"pyyaml>=6.0",
# improvement/ subpackage — agent-improvement workflow (POC).
"anthropic>=0.88.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

HARNESS_ADAPTER_IDS = {
"claude": "nvidia.fabric.claude",
"codex": "nvidia.fabric.codex.cli",
"codex": "nvidia.fabric.codex",
"deepagents": "nvidia.fabric.langchain.deepagents",
"hermes": "nvidia.fabric.hermes",
}
Expand Down
3 changes: 2 additions & 1 deletion plugins/nemo-agents/tests/unit/test_agent_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def _example_yaml_config() -> dict:
"temperature": 0.0,
},
"settings": {
"python_env": "HERMES_ADAPTER_PYTHON",
"base_url": "https://integrate.api.nvidia.com/v1",
"max_iterations": 1,
"max_tokens": 512,
Expand All @@ -46,7 +47,6 @@ def _example_yaml_config() -> dict:
"kind": "codex",
"settings": {
"sandbox": "workspace-write",
"skip_git_repo_check": True,
"config_overrides": {"model_reasoning_effort": "high"},
},
},
Expand Down Expand Up @@ -92,6 +92,7 @@ def test_example_yaml_config_validates(self) -> None:
assert config.default_harness == "hermes"
assert config.harnesses["hermes"].model is not None
assert config.harnesses["hermes"].model.provider == "nvidia"
assert config.harnesses["hermes"].settings["python_env"] == "HERMES_ADAPTER_PYTHON"
assert config.harnesses["codex"].settings["sandbox"] == "workspace-write"
assert config.models["default"].model == "openai/gpt-5.4"
assert config.skills is None
Expand Down
22 changes: 18 additions & 4 deletions plugins/nemo-agents/tests/unit/test_fabric_translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
from __future__ import annotations

import copy
from pathlib import Path
from typing import Any

import pytest
from nemo_agents_plugin.agent_config import AgentConfig
from nemo_agents_plugin.agent_config import AgentConfig, load_agent_config
from nemo_agents_plugin.fabric.translator import FabricTranslationError, translate_agent_config


Expand All @@ -29,6 +30,7 @@ def _example_yaml_config() -> dict[str, Any]:
"temperature": 0.0,
},
"settings": {
"python_env": "HERMES_ADAPTER_PYTHON",
"base_url": "https://integrate.api.nvidia.com/v1",
"system_prompt": "You are a concise assistant.",
},
Expand All @@ -37,7 +39,6 @@ def _example_yaml_config() -> dict[str, Any]:
"kind": "codex",
"settings": {
"sandbox": "workspace-write",
"skip_git_repo_check": True,
},
},
},
Expand Down Expand Up @@ -70,6 +71,18 @@ def _example_yaml_config() -> dict[str, Any]:


class TestTranslateAgentConfig:
def test_repository_example_uses_current_codex_and_isolated_hermes_adapters(self) -> None:
example_path = Path(__file__).parents[2] / "examples/nemo-agent-config/agent.yaml"
config = load_agent_config(example_path)

codex_config = translate_agent_config(config, harness_name="codex")
hermes_config = translate_agent_config(config, harness_name="hermes")

assert codex_config.harness.adapter_id == "nvidia.fabric.codex"
assert "skip_git_repo_check" not in codex_config.harness.settings
assert hermes_config.harness.adapter_id == "nvidia.fabric.hermes"
assert hermes_config.harness.settings["python_env"] == "HERMES_ADAPTER_PYTHON"

Comment thread
mmogallapalli marked this conversation as resolved.
def test_translates_default_harness(self) -> None:
config = AgentConfig.model_validate(_example_yaml_config())

Expand All @@ -79,6 +92,7 @@ def test_translates_default_harness(self) -> None:
assert fabric_config.metadata.description == "Example Agent"
assert fabric_config.harness.adapter_id == "nvidia.fabric.hermes"
assert fabric_config.harness.resolution == "preinstalled"
assert fabric_config.harness.settings["python_env"] == "HERMES_ADAPTER_PYTHON"
assert fabric_config.harness.settings["system_prompt"] == "You are a concise assistant."
assert fabric_config.models["default"].provider == "nvidia"
assert fabric_config.models["default"].model == "nvidia/nemotron-3-nano-30b-a3b"
Expand All @@ -92,7 +106,7 @@ def test_selected_harness_uses_default_model(self) -> None:

fabric_config = translate_agent_config(config, harness_name="codex")

assert fabric_config.harness.adapter_id == "nvidia.fabric.codex.cli"
assert fabric_config.harness.adapter_id == "nvidia.fabric.codex"
assert fabric_config.harness.settings["sandbox"] == "workspace-write"
assert fabric_config.models["default"].provider == "openai"
assert fabric_config.models["default"].model == "openai/gpt-5.4"
Expand All @@ -101,7 +115,7 @@ def test_selected_harness_uses_default_model(self) -> None:
("kind", "adapter_id"),
[
("claude", "nvidia.fabric.claude"),
("codex", "nvidia.fabric.codex.cli"),
("codex", "nvidia.fabric.codex"),
("deepagents", "nvidia.fabric.langchain.deepagents"),
("hermes", "nvidia.fabric.hermes"),
],
Expand Down
2 changes: 1 addition & 1 deletion plugins/nemo-agents/tests/unit/test_fabric_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ async def test_selected_harness_is_translated(self, fake_fabric_stack: None) ->
fabric=_FakeFabric(),
)

assert result.fabric_config.harness.adapter_id == "nvidia.fabric.codex.cli"
assert result.fabric_config.harness.adapter_id == "nvidia.fabric.codex"
assert result.fabric_config.models["default"].model == "openai/gpt-5.4"

async def test_invalid_platform_config_is_reported(self, fake_fabric_stack: None) -> None:
Expand Down
7 changes: 7 additions & 0 deletions third_party/licenses.jsonl
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@
{"name": "mypy-extensions", "license": "MIT", "compatible": true}
{"name": "nemo-anonymizer", "license": "APACHE-2.0", "compatible": true}
{"name": "nemo-fabric", "license": "APACHE-2.0", "compatible": true}
{"name": "nemo-fabric-adapters-codex", "license": "APACHE-2.0", "compatible": true}
{"name": "nemo-fabric-adapters-common", "license": "APACHE-2.0", "compatible": true}
{"name": "nemo-fabric-adapters-hermes", "license": "APACHE-2.0", "compatible": true}
{"name": "nemo-fabric-runtime", "license": "APACHE-2.0", "compatible": true}
{"name": "nemo-relay", "license": "APACHE-2.0", "compatible": true}
{"name": "nemo-safe-synthesizer", "license": "APACHE-2.0", "compatible": true}
{"name": "nemoguardrails", "license": "APACHE-2.0", "compatible": true}
Expand All @@ -174,6 +178,8 @@
{"name": "oci-openai", "license": "UPL-1.0", "compatible": true}
{"name": "onnxruntime", "license": "MIT", "compatible": true}
{"name": "openai", "license": "APACHE-2.0", "compatible": true}
{"name": "openai-codex", "license": "APACHE-2.0", "compatible": true}
{"name": "openai-codex-cli-bin", "license": "APACHE-2.0", "compatible": true}
{"name": "openapi-pydantic", "license": "MIT", "compatible": true}
{"name": "openevals", "license": "MIT", "compatible": true}
{"name": "openinference-semantic-conventions", "license": "APACHE-2.0", "compatible": true}
Expand Down Expand Up @@ -285,6 +291,7 @@
{"name": "tenacity", "license": "APACHE-2.0", "compatible": true}
{"name": "tiktoken", "license": "MIT", "compatible": true}
{"name": "tokenizers", "license": "APACHE-2.0", "compatible": true}
{"name": "tomli-w", "license": "MIT", "compatible": true}
{"name": "tomlkit", "license": "MIT", "compatible": true}
{"name": "tornado", "license": "APACHE-2.0", "compatible": true}
{"name": "tqdm", "license": "MIT", "compatible": true}
Expand Down
Loading
Loading