Repository navigation
Add framework-parity harness + CrewAI example #2201
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
5808029
353c1ad
45abde0
4eb43b9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| <!-- | ||
| SPDX-FileCopyrightText: Copyright (c) 2025-2026, 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. | ||
| --> | ||
|
|
||
| # CrewAI Example | ||
|
|
||
| **Complexity:** 🟢 Beginner | ||
|
|
||
| A minimal example using CrewAI showcasing a multi-agent travel planning system where an Itinerary Expert plans activities, a Budget Advisor prices lodging and totals the trip cost, and a Summarizer compiles the final plan. | ||
|
|
||
| ## Table of Contents | ||
|
|
||
| - [Key Features](#key-features) | ||
| - [Installation and Setup](#installation-and-setup) | ||
| - [Install this Workflow](#install-this-workflow) | ||
| - [Set Up API Keys](#set-up-api-keys) | ||
| - [Run the Workflow](#run-the-workflow) | ||
|
|
||
| ## Key Features | ||
|
|
||
| - **CrewAI Framework Integration:** Demonstrates NeMo Agent Toolkit support for CrewAI alongside other frameworks like LangChain/LangGraph and Semantic Kernel. | ||
| - **Multi-Agent Travel Planning:** Three role-based agents (Itinerary Expert, Budget Advisor, Summarizer) running as a sequential `Crew`, each contributing its own specialized `Task`. | ||
| - **Shared Tools Across Agents:** Both the itinerary and budget agents draw on the same two NAT-registered tools (`hotel_price`, `local_events`), demonstrating that a single tool implementation is reusable across every supported framework, not rewritten per integration. | ||
| - **Task Context Chaining:** The budget and summary tasks receive prior tasks' output via CrewAI's `context=[...]`, so later agents build on earlier agents' work rather than repeating it. | ||
|
|
||
| ## Installation and Setup | ||
|
|
||
| If you have not already done so, follow the instructions in the [Install Guide](../../../docs/source/get-started/installation.md#install-from-source) to create the development environment and install NeMo Agent Toolkit. | ||
|
|
||
| ### Install this Workflow | ||
|
|
||
| From the root directory of the NeMo Agent Toolkit library, run the following commands: | ||
|
|
||
| ```bash | ||
| uv pip install -e examples/frameworks/crewai_demo | ||
| ``` | ||
|
|
||
| ### Set Up API Keys | ||
|
|
||
| You need to set your OpenAI API key as an environment variable to access OpenAI AI services: | ||
|
|
||
| ```bash | ||
| export OPENAI_API_KEY=<YOUR_API_KEY> | ||
| ``` | ||
|
|
||
| ## Run the Workflow | ||
|
|
||
| ```bash | ||
| nat run --config_file examples/frameworks/crewai_demo/configs/config.yml --input "Create a 3-day travel itinerary for Tokyo in April, covering hotels and activities within a USD 2000 budget." | ||
|
willkill07 marked this conversation as resolved.
Resolved
|
||
| ``` | ||
|
|
||
| **Expected Workflow Output** | ||
|
|
||
| The workflow produces a day-by-day itinerary, a lodging + activity cost breakdown, and a total estimated cost, compiled by the Summarizer agent into a single final plan — structurally the same kind of output the Semantic Kernel example produces for the same prompt, which is the point: the two examples are meant to be comparable, not just individually correct. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| # SPDX-FileCopyrightText: Copyright (c) 2025-2026, 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. | ||
|
|
||
| [build-system] | ||
| build-backend = "setuptools.build_meta" | ||
| requires = ["setuptools>=64", "setuptools-scm>=8", "setuptools_dynamic_dependencies>=1.0.0"] | ||
|
willkill07 marked this conversation as resolved.
Resolved
|
||
|
|
||
| [tool.setuptools_scm] | ||
| git_describe_command = "git describe --long --first-parent" | ||
| root = "../../.." | ||
|
|
||
| [tool.setuptools.packages.find] | ||
| where = ["src"] | ||
|
|
||
| [project] | ||
| name = "nat_crewai_demo" | ||
| dynamic = ["version", "dependencies"] | ||
| requires-python = ">=3.11,<3.14" | ||
| description = "CrewAI Example" | ||
| keywords = ["ai", "rag", "agents"] | ||
| classifiers = ["Programming Language :: Python"] | ||
|
|
||
| [tool.setuptools_dynamic_dependencies] | ||
| dependencies = [ | ||
| "nvidia-nat[crewai,test] == {version}", | ||
| ] | ||
|
|
||
| [tool.uv.sources] | ||
| nvidia-nat = { path = "../../..", editable = true } | ||
|
|
||
| [project.entry-points.'nat.components'] | ||
| nat_crewai_demo = "nat_crewai_demo.register" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| # SPDX-FileCopyrightText: Copyright (c) 2025-2026, 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. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Document the new public Python surface. The new package module, public classes, public functions, and CLI entry point lack the required Google-style docstrings.
As per coding guidelines: 📍 Affects 4 files
🤖 Prompt for AI AgentsSource: Coding guidelines |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| # SPDX-FileCopyrightText: Copyright (c) 2025-2026, 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: fastapi | ||
| cors: | ||
| allow_origins: ['*'] | ||
| step_adaptor: | ||
| mode: default | ||
|
|
||
| functions: | ||
| hotel_price: | ||
| _type: hotel_price | ||
| local_events: | ||
| _type: local_events | ||
|
|
||
| llms: | ||
| openai_llm: | ||
| _type: openai | ||
| model_name: gpt-5.4-mini | ||
| temperature: 0.0 | ||
|
|
||
| workflow: | ||
| _type: crewai | ||
| tool_names: [hotel_price, local_events] | ||
| llm_name: openai_llm | ||
| verbose: true | ||
| itinerary_expert_role: Itinerary Expert | ||
| itinerary_expert_goal: Build detailed, well-paced day-by-day travel itineraries. | ||
| itinerary_expert_backstory: | | ||
| You specialize in attractions, local events, and trip logistics. You focus purely on what to do and when; | ||
| you leave hotel pricing and overall budgeting to the Budget Advisor. | ||
|
|
||
| budget_advisor_role: Budget Advisor | ||
| budget_advisor_goal: Produce an accurate, itemized cost estimate for the whole trip. | ||
| budget_advisor_backstory: | | ||
| You specialize in estimating and optimizing travel costs. You use the hotel price tool to find lodging costs | ||
| and combine them with the itinerary's activity costs into one clear total. | ||
|
|
||
| summarize_agent_role: Summarizer | ||
| summarize_agent_goal: Turn the itinerary and the budget into one polished, user-facing travel plan. | ||
| summarize_agent_backstory: | | ||
| You specialize in taking detailed notes from other specialists and compiling them into a clear, | ||
| well-structured final document, without duplicating information or losing any details. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| # SPDX-FileCopyrightText: Copyright (c) 2025-2026, 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 pydantic import BaseModel | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Add required Google-style docstrings to public Python APIs.
As per coding guidelines, “Provide Google-style docstrings for every public module, class, function and CLI command.” 📍 Affects 4 files
🤖 Prompt for AI AgentsSource: Coding guidelines |
||
|
|
||
| from nat.builder.builder import Builder | ||
| from nat.builder.function_info import FunctionInfo | ||
| from nat.cli.register_workflow import register_function | ||
| from nat.data_models.function import FunctionBaseConfig | ||
|
|
||
|
|
||
| class HotelPriceToolConfig(FunctionBaseConfig, name="hotel_price"): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With both I ran Unique names here and in |
||
| data_path: str = "examples/frameworks/crewai_demo/src/nat_crewai_demo/data/hotel_prices.json" | ||
| date_format: str = "%Y-%m-%d" | ||
|
|
||
|
|
||
| class HotelOffer(BaseModel): | ||
| name: str | ||
| price_per_night: float | ||
| total_price: float | ||
| city: str | ||
| checkin: str | ||
| checkout: str | ||
|
|
||
|
|
||
| class HotelOffersResponse(BaseModel): | ||
| offers: list[HotelOffer] | ||
|
|
||
|
|
||
| @register_function(config_type=HotelPriceToolConfig) | ||
| async def hotel_price(tool_config: HotelPriceToolConfig, builder: Builder): | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Declare the return type of
As per coding guidelines, all public APIs require Python 3.11+ type hints on parameters and return values. 🤖 Prompt for AI AgentsSource: Coding guidelines |
||
|
|
||
| import json | ||
|
|
||
| with open(tool_config.data_path, encoding='utf-8') as f: | ||
| hotel_prices = json.load(f) | ||
|
|
||
| search_date_format = tool_config.date_format | ||
|
|
||
| async def _get_hotel_price(city: str, checkin: str, checkout: str) -> HotelOffersResponse: | ||
| from datetime import datetime | ||
|
|
||
| base_hotels = hotel_prices | ||
|
|
||
| checkin_dt = datetime.strptime(checkin, search_date_format) | ||
| checkout_dt = datetime.strptime(checkout, search_date_format) | ||
| nights = (checkout_dt - checkin_dt).days | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Reject invalid hotel date ranges. If 🤖 Prompt for AI Agents |
||
|
|
||
| offers = [] | ||
| for hotel in base_hotels: | ||
| total_price = hotel["price_per_night"] * nights | ||
| offers.append( | ||
| HotelOffer(name=hotel["name"], | ||
| price_per_night=hotel["price_per_night"], | ||
| total_price=total_price, | ||
| city=city, | ||
| checkin=checkin, | ||
| checkout=checkout)) | ||
|
|
||
| return HotelOffersResponse(offers=offers) | ||
|
|
||
| yield FunctionInfo.from_fn( | ||
| _get_hotel_price, | ||
| description=( | ||
| "This tool returns a list of hotels and nightly prices for the given city and checkin/checkout dates.")) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| # SPDX-FileCopyrightText: Copyright (c) 2025-2026, 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 pydantic import BaseModel | ||
|
|
||
| from nat.builder.builder import Builder | ||
| from nat.builder.function_info import FunctionInfo | ||
| from nat.cli.register_workflow import register_function | ||
| from nat.data_models.function import FunctionBaseConfig | ||
|
|
||
|
|
||
| class LocalEvent(BaseModel): | ||
| name: str | ||
| cost: float | ||
| city: str | ||
|
|
||
|
|
||
| class LocalEventsResponse(BaseModel): | ||
| events: list[LocalEvent] | ||
|
|
||
|
|
||
| class LocalEventsToolConfig(FunctionBaseConfig, name="local_events"): | ||
| data_path: str = "examples/frameworks/crewai_demo/src/nat_crewai_demo/data/local_events.json" | ||
|
|
||
|
|
||
| @register_function(config_type=LocalEventsToolConfig) | ||
| async def local_events(tool_config: LocalEventsToolConfig, builder: Builder): | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: #!/bin/bash
set -e
printf '%s\n' '--- repository guidance ---'
find /tmp/coderabbit-repo-knowledge/nvidia-nemo-agent-toolkit-dc359612 -maxdepth 2 -type f -name '*.md' -print \
| sort | while read -r f; do
case "$f" in
*/examples/*|*/frameworks/*|*/python/*|*/scripts/*) printf '\n### %s\n' "$f"; cat "$f";;
esac
done
printf '%s\n' '--- target outlines ---'
ast-grep outline examples/frameworks/crewai_demo/src/nat_crewai_demo/local_events_tool.py
ast-grep outline examples/frameworks/crewai_demo/src/nat_crewai_demo/register.py
printf '%s\n' '--- target source ---'
cat -n examples/frameworks/crewai_demo/src/nat_crewai_demo/local_events_tool.py
sed -n '1,110p' examples/frameworks/crewai_demo/src/nat_crewai_demo/register.py
printf '%s\n' '--- relevant typing configuration and examples ---'
rg -n -C 3 'AsyncGenerator|async def .*builder|FunctionInfo|python_version|typeCheckingMode|pyright' \
pyproject.toml examples/frameworks/crewai_demo scripts/framework_parity \
-g '*.py' -g '*.toml' -g '*.json' -g '*.yaml' -g '*.yml'Repository: NVIDIA/NeMo-Agent-Toolkit Length of output: 20798 🏁 Script executed: #!/bin/bash
set -e
printf '%s\n' '--- pyright configuration ---'
sed -n '387,430p' pyproject.toml
printf '%s\n' '--- registered async-generator annotation patterns ---'
rg -n -C 2 'async def .*->|AsyncGenerator\[|AsyncIterator\[|register_function' \
examples scripts src -g '*.py' 2>/dev/null | head -240
printf '%s\n' '--- FunctionInfo contract ---'
find . -type f -name 'function_info.py' -print
find . -type f -name 'register_workflow.py' -printRepository: NVIDIA/NeMo-Agent-Toolkit Length of output: 23586 🏁 Script executed: #!/bin/bash
set -e
printf '%s\n' '--- repository annotation precedent ---'
sed -n '1,75p' examples/frameworks/strands_demo/src/nat_strands_demo/register.py
printf '%s\n' '--- package Python requirement ---'
rg -n -C 2 'requires-python|python_requires|target-version|python_version' \
pyproject.toml packages/nvidia_nat_core/pyproject.toml examples/frameworks/crewai_demo/pyproject.toml
printf '%s\n' '--- registration contract ---'
sed -n '1,180p' packages/nvidia_nat_core/src/nat/cli/register_workflow.pyRepository: NVIDIA/NeMo-Agent-Toolkit Length of output: 13302 Add return annotations to the registered workflow APIs. Both public async-generator functions yield 📍 Affects 2 files
🤖 Prompt for AI AgentsSource: Coding guidelines |
||
|
|
||
| import json | ||
|
|
||
| with open(tool_config.data_path) as f: | ||
| events = LocalEventsResponse.model_validate({"events": json.load(f)}).events | ||
|
|
||
| async def _local_events(city: str) -> LocalEventsResponse: | ||
| return LocalEventsResponse(events=[e for e in events if e.city == city]) | ||
|
|
||
| yield FunctionInfo.from_fn( | ||
| _local_events, | ||
| description=("This tool can provide information and cost of local events and activities in a city")) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Replace standalone
NATproduct terminology.The documentation policy rejects
NATas a standalone product name.examples/frameworks/crewai_demo/README.md#L36-L36: replaceNAT-registeredwithNeMo Agent Toolkit-registeredor reword the sentence.scripts/framework_parity/matrix.py#L18-L18: replaceNAT claimswithNeMo Agent Toolkit claims.As per path instructions:
Documentation in Markdown files should not use NAT as an acronymand the reject vocabulary prohibitsNATas a standalone product name.🧰 Tools
🪛 Vale (3.17.1)
[error] 36-36: Avoid using 'NAT'.
(Vale.Avoid)
📍 Affects 2 files
examples/frameworks/crewai_demo/README.md#L36-L36(this comment)scripts/framework_parity/matrix.py#L18-L18🤖 Prompt for AI Agents
Source: Path instructions