Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
e1abda3
Add deepagents extra
dagardner-nv May 12, 2026
92ca845
Import improvement
dagardner-nv May 12, 2026
d8912c9
WIP: First pass at deep agents integration
dagardner-nv May 12, 2026
3ce8bc7
Use a nim model, remove unnecessary helper method
dagardner-nv May 12, 2026
649e9f8
Rename helper method
dagardner-nv May 12, 2026
2e2b9f0
Document constants, remove unneeded truncation
dagardner-nv May 12, 2026
561eb93
Add protocol type hints
dagardner-nv May 12, 2026
4d4435c
Cleanups to callbacks class, distinguish between hitl and other graph…
dagardner-nv May 12, 2026
6a67371
Nitpicky formatting
dagardner-nv May 12, 2026
bc51450
Update attribs
dagardner-nv May 12, 2026
601e771
Move the subscribed_events fixture to be shared
dagardner-nv May 12, 2026
822bab7
WIP: [skip ci]
dagardner-nv May 12, 2026
445bdff
Formatting [skip ci]
dagardner-nv May 12, 2026
aa3b66e
Fix linting errors
dagardner-nv May 12, 2026
a1eecc3
Add deepagents in ci
dagardner-nv May 12, 2026
e609300
Add return type hint per code rabbit suggestion
dagardner-nv May 12, 2026
bdbe385
Install dependencies in the CI check stage needed for ty tool
dagardner-nv May 12, 2026
92e3908
Install OpenSSL via vcpkg for Windows-arm64
dagardner-nv May 12, 2026
59e01c8
Merge branch 'main' of github.com:NVIDIA/NeMo-Flow into david-deepage…
dagardner-nv May 12, 2026
c6f0eff
Add more tests
dagardner-nv May 12, 2026
9948131
Formatting
dagardner-nv May 12, 2026
47b225e
Merge branch 'main' of github.com:NVIDIA/NeMo-Flow into david-deepage…
dagardner-nv May 12, 2026
9b7e117
Apply suggestions from coderabbit
dagardner-nv May 12, 2026
b3aba0d
Merge branch 'main' of github.com:NVIDIA/NeMo-Flow into david-deepage…
dagardner-nv May 13, 2026
dd2e39c
Merge branch 'release/0.2' of github.com:NVIDIA/NeMo-Flow into david-…
dagardner-nv May 14, 2026
05ac673
Record skills as tool scopes not marks
dagardner-nv May 14, 2026
e5faedb
Replace tool marks with scopes
dagardner-nv May 14, 2026
5fe997f
Remove redundant backend.py
dagardner-nv May 14, 2026
cb3ef49
Remove overloads of wrap_tool_call and awrap_tool_call and therefore …
dagardner-nv May 14, 2026
0606d75
WIP
dagardner-nv May 14, 2026
e175f04
Set to warning not debug, failing to pop due to a failure in _prepare…
dagardner-nv May 14, 2026
9c49a65
Handle pydantic classes in _serialize_value
dagardner-nv May 14, 2026
95bf464
Handle langgraph command and send types in prepare_outputs
dagardner-nv May 14, 2026
ab8a14b
Update lock
dagardner-nv May 14, 2026
cd2ec54
Remove unused methods
dagardner-nv May 14, 2026
7016a3c
Formatting
dagardner-nv May 14, 2026
869edaf
Expand e2e test to include a subagent
dagardner-nv May 14, 2026
08870f7
Improve event validation
dagardner-nv May 14, 2026
85577cc
Merge branch 'release/0.2' of github.com:NVIDIA/NeMo-Flow into david-…
dagardner-nv May 14, 2026
342b367
Move documentation
dagardner-nv May 14, 2026
c478f91
Forgot to check in moved file
dagardner-nv May 14, 2026
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
1 change: 1 addition & 0 deletions .github/workflows/ci_check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ jobs:
run: |
set -e
uv tool install pre-commit==${{ steps.ci-config.outputs.pre_commit_version }}
uv sync --inexact --no-install-project --no-install-package nemo-flow --extra langchain --extra langgraph --extra deepagents
if [[ "$FULL_CI" == "true" || -z "$PRE_COMMIT_BASE" ]]; then
pre-commit run --all-files --show-diff-on-failure
else
Expand Down
17 changes: 17 additions & 0 deletions .github/workflows/ci_python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,23 @@ jobs:
set -e
UV_PYTHON_DOWNLOADS=manual uv python install --managed-python ${{ steps.ci-config.outputs.default_python_version }}

- name: Install Windows ARM64 OpenSSL
if: ${{ matrix.platform == 'windows-arm64' }}
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
$vcpkgRoot = Join-Path $env:RUNNER_TEMP 'vcpkg'
git clone https://github.com/microsoft/vcpkg $vcpkgRoot
git -C $vcpkgRoot checkout --detach 56bb2411609227288b70117ead2c47585ba07713
& (Join-Path $vcpkgRoot 'bootstrap-vcpkg.bat') -disableMetrics
& (Join-Path $vcpkgRoot 'vcpkg.exe') install openssl:arm64-windows-static-md --clean-after-build --disable-metrics

$opensslDir = Join-Path $vcpkgRoot 'installed\arm64-windows-static-md'
Add-Content -Path $env:GITHUB_ENV -Value "OPENSSL_DIR=$opensslDir"
Add-Content -Path $env:GITHUB_ENV -Value "OPENSSL_STATIC=1"
Add-Content -Path $env:GITHUB_ENV -Value "VCPKG_ROOT=$vcpkgRoot"
Add-Content -Path $env:GITHUB_ENV -Value "VCPKGRS_TRIPLET=arm64-windows-static-md"
Comment thread
coderabbitai[bot] marked this conversation as resolved.

- name: Run Python tests with coverage
working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }}
run: just --set ci true --set output_dir "${{ github.workspace }}" test-python
Expand Down
1,215 changes: 1,120 additions & 95 deletions ATTRIBUTIONS-Python.md

Large diffs are not rendered by default.

120 changes: 120 additions & 0 deletions docs/getting-started/python/deepagents.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<!--
SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
SPDX-License-Identifier: Apache-2.0
-->

# NeMo Flow Deep Agents Integration

Use the `nemo_flow.integrations.deepagents` package to add NeMo Flow
observability to Deep Agents applications through the LangChain and LangGraph
integration surfaces that Deep Agents builds on.

## Setup

Install the Deep Agents integration extra in your application environment.

::::{tab-set}
:sync-group: install-tool

:::{tab-item} uv
:selected:
:sync: uv

```bash
uv add "nemo-flow[deepagents]"
```
:::

:::{tab-item} pip
:sync: pip

```bash
pip install "nemo-flow[deepagents]"
```
:::

::::

The example below uses the NVIDIA LangChain provider. Install that provider
extra too if you want to run the example as written:

::::{tab-set}
:sync-group: install-tool

:::{tab-item} uv
:selected:
:sync: uv

```bash
uv add "nemo-flow[deepagents,langchain-nvidia]"
```
:::

:::{tab-item} pip
:sync: pip

```bash
pip install "nemo-flow[deepagents,langchain-nvidia]"
```
:::

::::

## Usage Example

```python
import nemo_flow
from deepagents import create_deep_agent
from nemo_flow.integrations.deepagents import (
NemoFlowDeepAgentsCallbackHandler,
add_nemo_flow_integration,
)

agent = create_deep_agent(
**add_nemo_flow_integration(
model="nvidia:nvidia/nemotron-3-nano-30b-a3b",
tools=[],
skills=["/skills/research/"],
name="main-agent",
)
)

input_payload = {
"messages": [
{
"role": "user",
"content": "Research recent GPU news",
}
]
}

with nemo_flow.scope.scope("deepagents-request", nemo_flow.ScopeType.Agent):
result = agent.invoke(
input_payload,
config={"callbacks": [NemoFlowDeepAgentsCallbackHandler()]},
)

final_message = result["messages"][-1]
print(f"Final response: {final_message.content}")
```

## Observability

The integration composes the existing NeMo Flow LangChain and LangGraph hooks,
then emits Deep Agents-specific marks for configured skills, subagents, and
human-in-the-loop lifecycle events.

It captures:

- LangChain model and tool calls through NeMo Flow managed execution.
- LangGraph run scopes through callbacks.
- Human-in-the-loop interrupt and resume marks.
- Configured skills and subagent summaries at agent-run start.
- In-process dictionary-style subagents with the same NeMo Flow middleware, so
their model and tool calls are captured when Deep Agents invokes them.

Remote graphs or processes still need NeMo Flow instrumentation in that graph
or process to capture their internal model and tool calls.

Refer to [Export Observability Data](../../export-observability-data/about.md)
for details on exporting NeMo Flow observability data to third-party systems.
9 changes: 6 additions & 3 deletions docs/getting-started/python/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ SPDX-License-Identifier: Apache-2.0

This quick start shows the smallest Python workflow that emits scope, tool, and LLM events.

[LangChain](https://www.langchain.com/langchain) and [LangGraph](https://www.langchain.com/langgraph) users should start with the [LangChain integration](langchain.md) or [LangGraph integration](langgraph.md) guides for the best experience in those frameworks.
[LangChain](https://www.langchain.com/langchain), [LangGraph](https://www.langchain.com/langgraph), and [Deep Agents](https://www.langchain.com/deep-agents) users should start with the [LangChain integration](langchain.md), [LangGraph integration](langgraph.md), and [Deep Agents integration](deepagents.md) guides for the best experience in those frameworks.

## Choose an Install Path

Expand Down Expand Up @@ -129,18 +129,21 @@ Use these links to continue from the quick start into the core runtime concepts.

- [LangChain integration](langchain.md)
- [LangGraph integration](langgraph.md)
- [Deep Agents integration](deepagents.md)
- [Scopes](../../about/concepts/scopes.md)
- [Middleware](../../about/concepts/middleware.md)
- [Plugins](../../about/concepts/plugins.md)

## Framework Integrations

Use these guides when your Python application already uses LangChain or
LangGraph and you want NeMo Flow observability through their public APIs.
Use these guides when your Python application already uses LangChain,
LangGraph, or Deep Agents and you want NeMo Flow observability through their
public APIs.

```{toctree}
:maxdepth: 1

LangChain Integration <langchain>
LangGraph Integration <langgraph>
Deep Agents Integration <deepagents>
```
6 changes: 2 additions & 4 deletions docs/integrate-frameworks/about.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,8 @@ Use these signals to decide whether this documentation path matches your current
- Are building or reviewing third-party integration patches

If you own the application call sites directly, use [Instrument Applications](../instrument-applications/about.md) first.
If your application uses [LangChain](https://www.langchain.com/langchain) or
[LangGraph](https://www.langchain.com/langgraph), start with
[LangChain Integration](../getting-started/python/langchain.md) or
[LangGraph Integration](../getting-started/python/langgraph.md).
If your application uses [LangChain](https://www.langchain.com/langchain),
[LangGraph](https://www.langchain.com/langgraph), or [Deep Agents](https://www.langchain.com/deep-agents), start with [LangChain Integration](../getting-started/python/langchain.md), [LangGraph Integration](../getting-started/python/langgraph.md), or [Deep Agents Integration](../getting-started/python/deepagents.md).

## Guides

Expand Down
4 changes: 2 additions & 2 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -725,7 +725,7 @@ build-python:
#!/usr/bin/env bash
{{ bash_helpers }}
cd "$NEMO_FLOW_REPO_ROOT"
uv sync --inexact --no-install-project --no-install-package nemo-flow --extra langchain
uv sync --inexact --no-install-project --no-install-package nemo-flow --extra langchain --extra langgraph --extra deepagents
activate_project_venv
if is_true "{{ ci }}"; then
prepare_llvm_cov_workspace
Expand Down Expand Up @@ -854,7 +854,7 @@ test-python:
fi
cargo test -p nemo-flow-python --lib
fi
uv sync --inexact --no-install-project --no-install-package nemo-flow --extra langchain
uv sync --inexact --no-install-project --no-install-package nemo-flow --extra langchain --extra langgraph --extra deepagents
activate_project_venv
python_executable="$(project_python_executable)"
use_project_python_source "$python_executable"
Expand Down
6 changes: 6 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,19 @@ docs = [
langchain = [
"langchain>=1.2.11,<2.0.0",
"langchain-core",
"langgraph", # allow any compatible version
]

langgraph = [
"nemo-flow[langchain]",
"langgraph>=1.1.10,<2.0.0",
]

deepagents = [
"nemo-flow[langgraph]",
"deepagents>=0.5.3,<0.6.0",
]

langchain-nvidia = [
"nemo-flow[langchain]",
"langchain-nvidia-ai-endpoints~=1.0",
Expand Down
113 changes: 113 additions & 0 deletions python/nemo_flow/integrations/deepagents/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

"""NeMo Flow integrations for Deep Agents."""

from __future__ import annotations

from collections.abc import Mapping, Sequence
from typing import Any

from nemo_flow.integrations.deepagents.callbacks import NemoFlowDeepAgentsCallbackHandler
from nemo_flow.integrations.deepagents.middleware import NemoFlowDeepAgentsMiddleware


def add_nemo_flow_integration(
kwargs: Mapping[str, Any] | None = None,
*,
instrument_subagents: bool = True,
**overrides: Any,
) -> dict[str, Any]:
"""
Receives the keyword arguments for ``create_deep_agent`` and returns them with NeMo Flow observability attached.

Use this helper as ``create_deep_agent(**add_nemo_flow_integration(...))``.
It injects Deep Agents-aware middleware at the top level, adds the same
middleware to dictionary-style custom subagents that do not inherit parent
middleware, and leaves any provided backend unchanged.
"""
observed = dict(kwargs or {})
observed.update(overrides)

skills = _string_sequence(observed.get("skills"))
subagents = list(observed.get("subagents") or ())
subagent_summaries = [_subagent_summary(subagent) for subagent in subagents]
backend = observed.get("backend")
backend_name = type(backend).__name__ if backend is not None else None

middleware = list(observed.get("middleware") or ())
_append_middleware(
middleware,
NemoFlowDeepAgentsMiddleware(
agent_name=observed.get("name"),
skills=skills,
subagents=subagent_summaries,
backend_name=backend_name,
),
)
observed["middleware"] = middleware

if instrument_subagents and subagents:
observed["subagents"] = [_instrument_subagent(subagent) for subagent in subagents]

return observed


def _append_middleware(middleware: list[Any], new_middleware: NemoFlowDeepAgentsMiddleware) -> None:
if any(isinstance(item, NemoFlowDeepAgentsMiddleware) for item in middleware):
return
middleware.append(new_middleware)


def _instrument_subagent(subagent: Any) -> Any:
if not isinstance(subagent, dict):
return subagent

observed = dict(subagent)
middleware = list(observed.get("middleware") or ())
_append_middleware(
middleware,
NemoFlowDeepAgentsMiddleware(
agent_name=observed.get("name"),
skills=_string_sequence(observed.get("skills")),
subagents=None,
),
)
observed["middleware"] = middleware
return observed


def _subagent_summary(subagent: Any) -> Mapping[str, Any]:
if isinstance(subagent, Mapping):
summary: dict[str, Any] = {"type": "subagent"}
for key in ("name", "description", "model", "graph_id", "url"):
value = subagent.get(key)
if value is not None:
summary[key] = value
if "skills" in subagent:
summary["skills"] = _string_sequence(subagent.get("skills"))
return summary

summary = {"type": type(subagent).__name__}
for attr in ("name", "description", "graph_id", "url"):
value = getattr(subagent, attr, None)
if value is not None:
summary[attr] = value
return summary


def _string_sequence(value: Any) -> Sequence[str] | None:
if value is None:
return None
if isinstance(value, str):
return [value]
if isinstance(value, Sequence):
return [str(item) for item in value]
return [str(value)]


__all__ = [
"NemoFlowDeepAgentsCallbackHandler",
"NemoFlowDeepAgentsMiddleware",
"add_nemo_flow_integration",
]
Loading
Loading