Skip to content
Open
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
126 changes: 126 additions & 0 deletions examples/frameworks/nat_autogen_demo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<!--
SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
SPDX-License-Identifier: Apache-2.0

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- path-check-skip-file -->

# AutoGen Framework Example

A minimal example using Microsoft's AutoGen framework showcasing a multi-agent weather and time information system where agents collaborate through AutoGen's conversation system to provide accurate weather and time data for specified cities.

## Key Features

- **AutoGen Framework Integration:** Demonstrates NeMo Agent Toolkit support for Microsoft's AutoGen framework alongside other frameworks like LangChain/LangGraph and Semantic Kernel.
- **Multi-Agent Collaboration:** Shows two specialized agents working together - a WeatherAndTimeAgent for data retrieval and a FinalResponseAgent for response formatting.
- **MCP Server Integration:** Demonstrates how NAT can interact with MCP (Model Context Protocol) servers to provide time information through external services.
- **Tool Integration:** Showcases integration of both local tools (weather updates) and remote tools (MCP time service) within the AutoGen framework.
- **Round-Robin Group Chat:** Uses AutoGen's RoundRobinGroupChat for structured agent communication with termination conditions.

## Installation and Setup

If you have not already done so, follow the instructions in the [Install Guide](../../../docs/source/quick-start/installing.md#install-from-source) to create the development environment and install NeMo Agent Toolkit.

### Install this Workflow

From the root directory of the NAT library, run the following commands:

```bash
uv pip install -e examples/getting_started/simple_calculator # required to run the current_datetime MCP tool used in example workflow.
uv pip install -e examples/frameworks/nat_autogen_demo
```

### Export required ENV variables
If you have not already done so, follow the [Obtaining API Keys](../../../docs/source/quick-start/installing.md#obtaining-api-keys) instructions to obtain API keys.

For OpenAI Export these:
- OPENAI_MODEL_NAME
- OPENAI_API_KEY
- OPENAI_API_BASE

### Run the Workflow

#### Set up the MCP server
This example demonstrates how NAT can interact with MCP servers on behalf of AutoGen agents.

First run the MCP server with this command:

```bash
nat mcp serve --config_file examples/getting_started/simple_calculator/configs/config.yml --tool_names current_datetime
Comment on lines +54 to +60
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been thinking about this more.

I (personally) do not see any advantage for using MCP internals of frameworks when NAT can already abstract this away by being able to treat MCP functions like ordinary tools.

By preferring what exists in NAT, it provides less of an API surface for integration while providing all of the benefits.

The only change here would be in the configuration file. See here:

function_groups:
mcp_time:
_type: mcp_client
server:
transport: stdio
command: "python"
args: ["-m", "mcp_server_time", "--local-timezone=America/Los_Angeles"]
tool_overrides:
# Optionally override the tool name and description from the MCP server
get_current_time:
alias: get_current_time_mcp_tool
description: "Returns the current date and time"
mcp_math:
_type: mcp_client
server:
transport: streamable-http
url: "http://localhost:9901/mcp"
include:
- calculator_multiply
- calculator_inequality
- calculator_divide
- calculator_subtract

```

Then run the workflow with the NAT CLI:

```bash
nat run --config_file examples/frameworks/nat_autogen_demo/configs/config.yml --input "What is the weather and time in New York today?"
```

### Expected output

```console
2025-10-07 14:34:28,122 - nat.cli.commands.start - INFO - Starting NAT from config file: 'examples/frameworks/nat_autogen_demo/configs/config.yml'
2025-10-07 14:34:30,285 - mcp.client.streamable_http - INFO - Received session ID: 652a05b6646c4ddb945cf2adf0b3ec18
Received session ID: 652a05b6646c4ddb945cf2adf0b3ec18
2025-10-07 14:34:30,287 - mcp.client.streamable_http - INFO - Negotiated protocol version: 2025-06-18
Negotiated protocol version: 2025-06-18

Configuration Summary:
--------------------
Workflow Type: autogen_team
Number of Functions: 1
Number of Function Groups: 0
Number of LLMs: 1
Number of Embedders: 0
Number of Memory: 0
Number of Object Stores: 0
Number of Retrievers: 0
Number of TTC Strategies: 0
Number of Authentication Providers: 0

2025-10-07 14:34:30,301 - nat.observability.exporter_manager - INFO - Started exporter 'otelcollector'
2025-10-07 14:34:46,704 - nat.front_ends.console.console_front_end_plugin - INFO -
.
.
.
<snipped for brevity>
.
.
.
--------------------------------------------------
Workflow Result:
['New York weather: Sunny, around 25°C (77°F).\nCurrent local time in New York: 5:34 PM EDT (UTC−4) on October 7, 2025.\n\nAPPROVE']
--------------------------------------------------

Comment on lines +100 to +104
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicated

Suggested change
--------------------------------------------------
Workflow Result:
['New York weather: Sunny, around 25°C (77°F).\nCurrent local time in New York: 5:34 PM EDT (UTC−4) on October 7, 2025.\n\nAPPROVE']
--------------------------------------------------

--------------------------------------------------
Workflow Result:
['New York weather: Sunny, around 25°C (77°F).\nCurrent local time in New York: 5:34 PM EDT (UTC−4) on October 7, 2025.\n\nAPPROVE']
--------------------------------------------------

```

## Architecture

The AutoGen workflow consists of two main agents:

1. **WeatherAndTimeAgent**: Retrieves weather and time information using tools
- Uses the `weather_update_tool` for current weather conditions
- Connects to MCP server for accurate time information
- Responds with "DONE" when task is completed

2. **FinalResponseAgent**: Formats and presents the final response
- Consolidates information from other agents
- Provides clear, concise answers to user queries
- Terminates the conversation with "APPROVE".

The agents communicate through AutoGen's RoundRobinGroupChat system, which manages the conversation flow and ensures proper termination when the task is complete.
60 changes: 60 additions & 0 deletions examples/frameworks/nat_autogen_demo/configs/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

general:
front_end:
_type: console
cors:
allow_origins: ["*"]
Comment on lines +17 to +20
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

console front-end probably doesn't need to be concerned with cors

Suggested change
front_end:
_type: console
cors:
allow_origins: ["*"]

telemetry:
logging:
console:
_type: console
level: debug
tracing:
otelcollector:
_type: otelcollector
endpoint: ${OTEL_ENDPOINT:-http://localhost:6006/v1/traces}
project: nat_autogen_demo

llms:
openai_llm:
_type: openai
model_name: ${OPENAI_MODEL_NAME:-gpt-5}
api_key: ${OPENAI_API_KEY}
base_url: ${OPENAI_API_BASE}

functions:
weather_update_tool:
_type: nat_autogen_demo/weather_update_autogen
description: "Get the current weather for a specified city"

workflow:
_type: autogen_team
llm_name: openai_llm
description: "To get the current weather and time in a specific city"
tool_names: [weather_update_tool]
query_processing_agent_name: WeatherAndTimeAgent
query_processing_agent_instructions: |
You are an agent that provides the current weather and time information.
When asked about the weather, provide the current weather conditions.
When asked about the time, provide the current local time.
If asked about anything else, respond with 'I can only provide weather and time information.'
Once you are done, reply with the text 'DONE'.
final_response_agent_name: FinalResponseAgent
final_response_agent_instructions: |
You are the final response agent.
Your role is to provide a concise and clear answer based on the information provided by other agents.
Once you are done, reply with the final answer and then say 'APPROVE'.
24 changes: 24 additions & 0 deletions examples/frameworks/nat_autogen_demo/pyproject.toml
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just letting you know that we (will) have additional things listed in the pyproject file. If you want to see ahead of time, look at what's on the release/1.3 branch (it will all be forward merged into develop)

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[build-system]
build-backend = "setuptools.build_meta"
requires = ["setuptools >= 64", "setuptools-scm>=8"]

[tool.setuptools_scm]
git_describe_command = "git describe --long --first-parent"
root = "../../.."

[project]
name = "nat_autogen_demo"
dynamic = ["version"]
dependencies = [
"nvidia-nat[autogen]~=1.4",
]
requires-python = ">=3.11,<3.14"
description = "AutoGen Workflow Example"
keywords = ["ai", "rag", "agents", "autogen", "multi-agent"]
classifiers = ["Programming Language :: Python"]

[tool.uv.sources]
nvidia-nat = { path = "../../..", editable = true }

[project.entry-points.'nat.components']
nat_autogen_demo = "nat_autogen_demo.register"
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import logging
from collections.abc import AsyncGenerator

from pydantic import Field

from nat.builder.builder import Builder
from nat.builder.framework_enum import LLMFrameworkEnum
from nat.builder.function_info import FunctionInfo
from nat.cli.register_workflow import register_function
from nat.data_models.component_ref import LLMRef
from nat.data_models.function import FunctionBaseConfig

logger = logging.getLogger(__name__)


class AutoGenFunctionConfig(FunctionBaseConfig, name="autogen_team"):
"""Configuration for AutoGen Agent workflow."""

llm_name: LLMRef = Field(description="The LLM model to use with AutoGen agents.")
tool_names: list[str] = Field(default_factory=list, description="List of tool names to be used by the agents.")
mcp_server_url: str = Field(
default="http://0.0.0.0:9901/mcp",
description="URL for the MCP time server.",
)
query_processing_agent_name: str = Field(description="Name of the query processing agent")
query_processing_agent_instructions: str = Field(description="Instructions for the query processing agent")
final_response_agent_name: str = Field(description="Name of the final response agent")
final_response_agent_instructions: str = Field(description="Instructions for the final response agent")


@register_function(config_type=AutoGenFunctionConfig, framework_wrappers=[LLMFrameworkEnum.AUTOGEN])
async def autogen_team(config: AutoGenFunctionConfig, builder: Builder) -> AsyncGenerator[FunctionInfo, None]:
"""
AutoGen multi-agent workflow that demonstrates collaborative agents in a team.
The agents communicate through AutoGen's conversation system to produce output.

Args:
config (AutoGenFunctionConfig): Configuration for the workflow.
builder (Builder): The NAT workflow builder to access registered components.

Yields:
AsyncGenerator[FunctionInfo, None]: Yields a FunctionInfo object encapsulating the workflow.
"""

from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.conditions import TextMentionTermination
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_ext.tools.mcp import StreamableHttpMcpToolAdapter
from autogen_ext.tools.mcp import StreamableHttpServerParams

try:
llm_client = await builder.get_llm(config.llm_name, wrapper_type=LLMFrameworkEnum.AUTOGEN)
tools = await builder.get_tools(config.tool_names, wrapper_type=LLMFrameworkEnum.AUTOGEN)

time_server_params = StreamableHttpServerParams(
url=config.mcp_server_url,
headers={"Content-Type": "application/json"},
timeout=30,
)
adapter = await StreamableHttpMcpToolAdapter.from_server_params(time_server_params, "current_datetime")
tools.append(adapter)

query_processing_agent = AssistantAgent(name=config.query_processing_agent_name,
model_client=llm_client,
tools=tools,
system_message=config.query_processing_agent_instructions)
final_response_agent = AssistantAgent(name=config.final_response_agent_name,
model_client=llm_client,
system_message=config.final_response_agent_instructions)

team = RoundRobinGroupChat(participants=[query_processing_agent, final_response_agent],
termination_condition=TextMentionTermination("APPROVE"))

async def _autogen_team_workflow(user_input: str) -> str:
"""Execute the workflow with the given input.

Args:
user_input (str): User's query

Returns:
str: The final response generated by the team.
"""
try:
result = await team.run(task=user_input)

if hasattr(result, 'messages') and result.messages:
return result.messages[-1].content
else:
return "The workflow finished but no output was generated."

except Exception as e:
logger.exception("Error in AutoGen workflow")
return f"Error occurred during AutoGen workflow: {e!s}"

# Yield the function info
yield FunctionInfo.create(single_fn=_autogen_team_workflow)

except GeneratorExit:
logger.info("AutoGen workflow exited early")
except Exception as _e:
logger.exception("Failed to initialize AutoGen workflow")
raise
finally:
logger.debug("AutoGen workflow cleanup completed")
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from . import autogen_team # noqa: F401 # pylint: disable=W0611 #imported for side effects (registration)
from . import weather_update_tool # noqa: F401 # pylint: disable=W0611 #imported for side effects (registration)
Loading
Loading