Skip to content
Draft
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
112 changes: 106 additions & 6 deletions plugins/nemo-agents/examples/nemo-agent-config/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Fabric-Backed Agent Config
# Fabric-Backed Agent Examples

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

Fabric dependencies are currently optional so the default workspace does not
force other Fabric consumers onto the `0.1.0a20260724` SDK API before they migrate.
Expand All @@ -11,10 +11,110 @@ Install them explicitly before local Fabric smoke tests:
uv pip install -e "plugins/nemo-agents[fabric]"
```

Top-level `skills`, `mcp`, and `tools` are Platform-owned shared fields that
Top-level `models`, `skills`, `mcp`, and `tools` are Platform-owned fields that
translate into `FabricConfig`. Prompt settings are harness-specific for now and
should be configured under `harnesses.<name>.settings`.

The shared `agent.yaml` configures Codex, Hermes, and NAT. Select one by setting
`default_harness` to `codex`, `hermes`, or `nat` before invoking it.

## NAT

The plugin install includes the Platform-packaged calculator and email phishing
NAT components. Each has a dedicated `agent.yaml` because they are distinct NAT
workflows. For the harness comparison, the shared `agent.yaml` uses calculator
as its representative NAT harness so all three harness kinds can be exercised
from one Platform config. `agent.yaml` is the only configuration source: the
adapter translates its normalized Fabric model and NAT harness settings into an
in-memory typed NAT configuration.

The initial NAT contract supports `react` and `current_timezone` workflows. A
`react` workflow accepts the Platform-packaged `calculator`,
`current_datetime`, and `email_phishing_analyzer` tools. The adapter maps those
names to NAT functions and function groups; those native details are not part of
the public Platform config.

```yaml
harnesses:
nat:
kind: nat
settings:
workflow: react
tools:
- calculator
- current_datetime

models:
default:
provider: nvidia
model: nvidia/nemotron-3-nano-30b-a3b
api_key_env: NVIDIA_API_KEY
temperature: 0.0
settings:
max_tokens: 1024
```

For `react`, the adapter translates `models.default` into NAT's `default` LLM.
The `nvidia` and `nim` providers select NAT's NIM client, while `openai` selects
its OpenAI-compatible client. Provider-specific fields such as `base_url` and
`max_tokens` belong in `models.default.settings`.

Set `default_harness: nat` in the shared `agent.yaml`, then run:

```bash
export NVIDIA_API_KEY="<your NVIDIA API key>"

nemo agents invoke \
--agent-config plugins/nemo-agents/examples/nemo-agent-config/agent.yaml \
--input "What is 12 multiplied by 8?"
```

Run the dedicated calculator config:

```bash
export NVIDIA_API_KEY="<your NVIDIA API key>"

nemo agents invoke \
--agent-config plugins/nemo-agents/examples/nemo-agent-config/nat-calculator/agent.yaml \
--input "What is 12 multiplied by 8?"
```

Run the email phishing analyzer:

```bash
export NVIDIA_API_KEY="<your NVIDIA API key>"

nemo agents invoke \
--agent-config plugins/nemo-agents/examples/nemo-agent-config/nat-email-phishing/agent.yaml \
--input "Subject: Verify your account. Send your password immediately."
```

Unsupported workflow and tool names fail during Platform translation. Expanding
the supported set requires an explicit Platform-to-NAT mapping in the adapter;
the adapter does not accept arbitrary native NAT configuration.

For NAT, `harness_native` MCP servers become `mcp_client` function groups and
are added to workflows that expose `tool_names`. `tools.blocked` removes named
NAT functions or function groups and can exclude a group member by its
`<group>__<function>` name. For example:

```yaml
mcp:
servers:
math:
transport: streamable-http
url: http://localhost:9901/mcp
exposure: harness_native
tools:
blocked:
- calculator__divide
```

NAT 1.8 does not expose a runtime contract for `SKILL.md` directories, so the
NAT adapter rejects non-empty `skills.paths` rather than silently ignoring
them. Put React-specific instructions in
`harnesses.<name>.settings.instructions`.

## Codex

Authenticate Codex, leave `default_harness: codex` in `agent.yaml`, and run:
Expand All @@ -34,8 +134,8 @@ 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 \
uv venv --python 3.12 .venv-hermes
uv --no-config pip install \
--python .venv-hermes/bin/python \
"nemo-fabric-adapters-hermes>=0.1.0a20260724,<0.2.0" \
"hermes-agent==0.19.0"
Expand Down
17 changes: 16 additions & 1 deletion plugins/nemo-agents/examples/nemo-agent-config/agent.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,27 @@ harnesses:
system_prompt: You are a concise test assistant.
config_overrides:
model_reasoning_effort: high
nat:
kind: nat
model:
provider: nvidia
model: nvidia/nemotron-3-nano-30b-a3b
api_key_env: NVIDIA_API_KEY
temperature: 0.0
settings:
max_tokens: 1024
chat_template_kwargs:
enable_thinking: false
settings:
workflow: react
tools:
- calculator
- current_datetime

models:
default:
provider: openai
model: openai/gpt-5.4

skills:
paths: []

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
config_format: nemo-agents-spec-v1
name: nat-simple-calculator
description: Invoke the NAT simple calculator workflow through NeMo Fabric.

default_harness: nat

harnesses:
nat:
kind: nat
settings:
workflow: react
tools:
- calculator
- current_datetime

models:
default:
provider: nvidia
model: nvidia/nemotron-3-nano-30b-a3b
api_key_env: NVIDIA_API_KEY
temperature: 0.0
settings:
max_tokens: 1024
chat_template_kwargs:
enable_thinking: false

tools:
blocked:
- calculator__divide

environment:
workspace: ./workspace
artifacts: ./artifacts

telemetry:
enabled: false
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
config_format: nemo-agents-spec-v1
name: nat-email-phishing-analyzer
description: Invoke the NAT email phishing analyzer through NeMo Fabric.

default_harness: nat

harnesses:
nat:
kind: nat
settings:
workflow: react
tools:
- email_phishing_analyzer
instructions: The final response should indicate that the email is either "phishing" or "benign".

models:
default:
provider: openai
model: nvidia/nemotron-3-nano-30b-a3b
api_key_env: NVIDIA_API_KEY
temperature: 0.0
settings:
base_url: https://integrate.api.nvidia.com/v1
max_tokens: 1024

environment:
workspace: ./workspace
artifacts: ./artifacts

telemetry:
enabled: false
8 changes: 8 additions & 0 deletions plugins/nemo-agents/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ dependencies = [
"nemo-agents-example-email-phishing",
"nvidia-nat-core>=1.8.0,<1.9",
"nvidia-nat-langchain>=1.8.0,<1.9",
"nvidia-nat-mcp>=1.8.0,<1.9",
"nvidia-nat-config-optimizer>=1.8.0,<1.9",
# ASTD-164: tight pins avoid pip ResolutionTooDeep via aioboto3/langchain-aws.
"langchain-aws==1.1.0",
Expand Down Expand Up @@ -65,6 +66,7 @@ fabric = [
# 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[runtime]>=0.1.0a20260724,<0.2.0",
"nemo-fabric-adapters-common>=0.1.0a20260724,<0.2.0",
"nemo-fabric-adapters-codex>=0.1.0a20260724,<0.2.0",
"nemo-fabric-adapters-hermes>=0.1.0a20260724,<0.2.0; python_version < '3.14'",
]
Expand Down Expand Up @@ -94,6 +96,9 @@ packages = [
"vendor/openclaw_agent_adapter/src/nat_openclaw_agent_adapter",
]

[tool.hatch.build.targets.wheel.shared-data]
"src/nemo_agents_plugin/fabric/adapters/nat/fabric-adapter.json" = "share/nemo-fabric/adapters/nemo-platform-nat/fabric-adapter.json"


[tool.uv.sources]
nemo-platform = { workspace = true }
Expand All @@ -105,6 +110,9 @@ nemo-agents-example-email-phishing = { workspace = true }
[tool.pytest.ini_options]
testpaths = ["tests"]
asyncio_mode = "auto"
markers = [
"integration: high-level tests that exercise installed runtime boundaries",
]
# "src" puts nemo_agents_plugin on sys.path. nemo-platform is resolved
# from the workspace — run `uv sync` at the repo root before running these tests.
pythonpath = ["src"]
Expand Down
18 changes: 18 additions & 0 deletions plugins/nemo-agents/src/nemo_agents_plugin/agent_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,24 @@ class HarnessConfig(BaseModel):
settings: dict[str, Any] = Field(default_factory=dict)


class NatHarnessSettings(BaseModel):
"""Platform-owned NAT workflow settings supported by the Fabric adapter."""

model_config = ConfigDict(extra="forbid")

workflow: Literal["react", "current_timezone"]
tools: list[Literal["calculator", "current_datetime", "email_phishing_analyzer"]] = Field(default_factory=list)
instructions: str | None = Field(default=None, min_length=1)

@model_validator(mode="after")
def _validate_workflow(self) -> Self:
if len(self.tools) != len(set(self.tools)):
raise ValueError("tools must not contain duplicates")
if self.workflow == "current_timezone" and (self.tools or self.instructions):
raise ValueError("current_timezone does not accept tools or instructions")
return self


class EnvironmentConfig(BaseModel):
model_config = ConfigDict(extra="forbid")

Expand Down
Loading
Loading