Skip to content

Add Perplexity Search API tool + Perplexity Embeddings API provider#1903

Open
jliounis wants to merge 9 commits into
NVIDIA:developfrom
jliounis:add-perplexity-internet-search
Open

Add Perplexity Search API tool + Perplexity Embeddings API provider#1903
jliounis wants to merge 9 commits into
NVIDIA:developfrom
jliounis:add-perplexity-internet-search

Conversation

@jliounis
Copy link
Copy Markdown

@jliounis jliounis commented Apr 30, 2026

Summary

Adds two Perplexity API integrations to the NeMo Agent Toolkit so workflows can use Perplexity for web search and for vector embeddings out of the box.

1. perplexity_internet_search — Search API tool

Mirrors the Exa integration added in #1846. Backed by Perplexity's Search API (POST /search) and framework-agnostic so it works with every framework wrapper (langchain, llama_index, crewai, semantic_kernel, agno, adk, strands, autogen).

  • Adds PerplexityInternetSearchToolConfig with configurable max_results, max_retries, max_query_length, search_recency_filter, country, max_tokens_per_page, and api_key (via config or PERPLEXITY_API_KEY).
  • Calls the Perplexity Search API directly with httpx.AsyncClient and sends the X-Pplx-Integration: nemo-agent-toolkit/<version> attribution header.
  • Registers the new perplexity_internet_search function for all supported framework workflows.
  • Updates the web search tutorial with Perplexity setup/config examples.

Minimal config:

functions:
  internet_search:
    _type: perplexity_internet_search

2. perplexity — Embeddings API provider

Adds a dedicated embedder provider backed by Perplexity's Embeddings API (POST /v1/embeddings), shipped in the core nvidia-nat package and wired into both the LangChain and LlamaIndex framework plugins (mirroring openai / azure_openai / nim).

  • PerplexityEmbedderModelConfig supports all four documented models — pplx-embed-v1-0.6b, pplx-embed-v1-4b, and the document-aware pplx-embed-context-v1-0.6b / pplx-embed-context-v1-4b — plus Matryoshka dimensions, batch_size, and the two on-wire encoding_format options (base64_int8, base64_binary).
  • A framework-agnostic PerplexityEmbeddings LangChain client batches inputs (up to 512/request), decodes the base64 payload locally to float vectors, retries transient HTTP failures with backoff, and forwards the X-Pplx-Integration attribution header on every request.
  • A PerplexityLlamaIndexEmbedding adapter wraps the same client to satisfy LlamaIndex's BaseEmbedding interface so the same NAT config drops into LlamaIndex-powered retrievers/RAG flows.
  • Adds Perplexity to the embedder provider table and configuration examples in docs/source/build-workflows/embedders.md, and to the LangChain/LlamaIndex embedder rows in docs/source/components/integrations/frameworks.md.

Minimal config:

embedders:
  perplexity_embedder:
    _type: perplexity
    model_name: pplx-embed-v1-0.6b
    dimensions: 512   # optional Matryoshka truncation

Set PERPLEXITY_API_KEY before using either feature:

export PERPLEXITY_API_KEY=<YOUR_PERPLEXITY_API_KEY>

Testing

  • uv run --extra test pytest packages/nvidia_nat_core/tests/nat/tools/test_perplexity_internet_search.py -v — search tool tests (existing, unchanged)
  • uv run --extra test pytest packages/nvidia_nat_core/tests/nat/embedder/test_perplexity_embedder.py -v8 passing (config validation, model enumeration, dimensions/batch_size bounds, encoding format choices, secret-string masking, model alias)
  • uv run --extra test --extra langchain pytest packages/nvidia_nat_langchain/tests/test_perplexity_embeddings.py -v11 passing (int8/binary decode round-trip, batching, attribution header propagation, dimensions in body, non-retriable status short-circuit, async path, env-key resolution)
  • uv run --extra test --extra langchain --extra llama-index pytest packages/nvidia_nat_llama_index/tests/test_perplexity_embedder_llama_index.py -v4 passing (sync + async delegation through the adapter, env-key registration)
  • ruff check packages/nvidia_nat_core/src/nat/embedder/perplexity_embedder.py packages/nvidia_nat_langchain/src/nat/plugins/langchain/perplexity_embeddings_client.py packages/nvidia_nat_llama_index/src/nat/plugins/llama_index/perplexity_embeddings_client.py

API references:


Summary by CodeRabbit

  • New Features

    • Perplexity Search as an alternate internet search tool included in the core package.
    • Perplexity Embeddings as a new embedder provider (_type: perplexity) available to LangChain and LlamaIndex workflows.
  • Documentation

    • Tutorials updated with Perplexity Search setup, usage, and configuration examples.
    • Embedders guide and frameworks matrix updated with Perplexity embeddings setup, models, dimensions, batching, and encoding-format options.
  • Tests

    • Comprehensive tests covering search retries, query truncation, attribution headers, result formatting, and embeddings batching, decoding, and adapter delegation.
  • Style

    • Whitelist added for the case-sensitive term "Perplexity" in style checks.

@copy-pr-bot
Copy link
Copy Markdown

copy-pr-bot Bot commented Apr 30, 2026

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 30, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a new Perplexity internet search tool: config schema, async HTTP integration with retries and backoff, package registration, docs, tests, and a Vale vocabulary entry for the token "Perplexity". (47 words)

Changes

Perplexity Search Tool Integration

Layer / File(s) Summary
Data Shape / Configuration
packages/nvidia_nat_core/src/nat/tool/perplexity_internet_search.py (lines 34–63)
Adds PERPLEXITY_SEARCH_URL and PerplexityInternetSearchToolConfig with fields: max_results, api_key (secret), max_retries, max_query_length, search_recency_filter, country, max_tokens_per_page.
Helper / Metadata
packages/nvidia_nat_core/src/nat/tool/perplexity_internet_search.py (lines 65–79)
Adds _get_integration_header() to produce X-Pplx-Integration using installed nvidia-nat package version or unknown.
Core Implementation
packages/nvidia_nat_core/src/nat/tool/perplexity_internet_search.py (lines 94–185)
Implements async perplexity_internet_search resolving API key (config or PERPLEXITY_API_KEY), truncating queries, building payload/headers, POSTing to Perplexity with httpx.AsyncClient, retry with exponential backoff, formatting results into <Document href="..."/> blocks, and returning user-facing messages on empty/failure cases.
Registration / Wiring
packages/nvidia_nat_core/src/nat/tool/register.py (line 24)
Imports perplexity_internet_search for automatic tool registration during module import.
Documentation / Examples
docs/source/get-started/tutorials/add-tools-to-a-workflow.md (lines 112, 200–240)
Adds perplexity_internet_search to web search alternatives and a new "Using Perplexity Search" section with install, PERPLEXITY_API_KEY guidance, YAML config example, and supported options.
Style Vocabulary
ci/vale/styles/config/vocabularies/nat/accept.txt (line 1)
Adds case-sensitive token Perplexity to Vale accept list.
Tests
packages/nvidia_nat_core/tests/nat/tools/test_perplexity_internet_search.py
New tests for config validation, secret handling, truncation behavior, empty results handling, retry exhaustion, integration header presence, and successful-result formatting.

Sequence Diagram

sequenceDiagram
    participant Workflow as Workflow / User
    participant Tool as Perplexity Tool
    participant Config as Tool Config
    participant HTTP as httpx.AsyncClient
    participant API as Perplexity Search API

    Workflow->>Tool: Call perplexity_internet_search(config, builder)
    Tool->>Config: Resolve API key (config or env)
    alt API key empty
        Tool-->>Workflow: Return "unavailable" message
    else
        Tool->>Tool: Truncate query if needed
        Tool->>Tool: Build headers (auth, X-Pplx-Integration)
        loop Retry with backoff (up to max_retries)
            Tool->>HTTP: POST to Perplexity Search API
            HTTP->>API: Send search request
            alt API success
                API-->>HTTP: Return results
                HTTP-->>Tool: Parse response
                Tool->>Tool: Format results to <Document> blocks
                Tool-->>Workflow: Return formatted output
            else API error
                API-->>HTTP: Error response
                HTTP-->>Tool: Retry or fail
            end
        end
        alt All retries exhausted
            Tool-->>Workflow: Return failure message
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely describes the main changes: adding Perplexity Search API tool support, and stays within the 72-character limit (67 characters) using imperative mood.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Comment @coderabbitai help to get the list of available commands and usage tips.

Signed-off-by: PSI Bot <psi@perplexity.ai>
Signed-off-by: James <james.liounis@perplexity.ai>
@jliounis jliounis force-pushed the add-perplexity-internet-search branch from 535ac26 to 9b8f95f Compare April 30, 2026 13:31
@jliounis jliounis marked this pull request as ready for review April 30, 2026 13:36
@jliounis jliounis requested a review from a team as a code owner April 30, 2026 13:36
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/nvidia_nat_langchain/tests/test_perplexity_internet_search.py (1)

75-77: ⚡ Quick win

Align fixture declaration with repository pytest fixture conventions.

Please define name= on the fixture decorator and rename the fixture function to use fixture_ prefix or _fixture suffix.

Suggested change
-@pytest.fixture
-def tool_config():
+@pytest.fixture(name="tool_config")
+def tool_config_fixture() -> PerplexityInternetSearchToolConfig:
     return PerplexityInternetSearchToolConfig(api_key="test-key", max_retries=2, max_query_length=50)
As per coding guidelines, "Pytest fixtures should define the name argument ... [and] function being decorated should be named using either a `fixture_` prefix or `_fixture` suffix."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/nvidia_nat_langchain/tests/test_perplexity_internet_search.py`
around lines 75 - 77, Rename the pytest fixture function tool_config to follow
convention (e.g., fixture_tool_config or tool_config_fixture) and update its
`@pytest.fixture` decorator to include the name argument (e.g.,
`@pytest.fixture`(name="tool_config")), ensuring the declared fixture name remains
"tool_config" while the function uses the required fixture_ prefix or _fixture
suffix; keep the returned object creation
(PerplexityInternetSearchToolConfig(api_key="test-key", max_retries=2,
max_query_length=50)) unchanged so tests referencing the "tool_config" fixture
continue to work.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@packages/nvidia_nat_langchain/src/nat/plugins/langchain/tools/perplexity_internet_search.py`:
- Line 53: The country Field currently accepts any string; add schema-level
validation to enforce ISO 3166-1 alpha-2 shape by restricting values to exactly
two ASCII letters and normalising case before use: update the Field declaration
for country to include a regex/constraint for two letters (e.g. /^[A-Za-z]{2}$/)
and add a pydantic validator for the country attribute that uppercases the value
(and returns None if input is None) so invalid values are rejected at model
construction time; reference the existing country Field and its validator in the
same model/class where country: str | None = Field(...) is declared.

---

Nitpick comments:
In `@packages/nvidia_nat_langchain/tests/test_perplexity_internet_search.py`:
- Around line 75-77: Rename the pytest fixture function tool_config to follow
convention (e.g., fixture_tool_config or tool_config_fixture) and update its
`@pytest.fixture` decorator to include the name argument (e.g.,
`@pytest.fixture`(name="tool_config")), ensuring the declared fixture name remains
"tool_config" while the function uses the required fixture_ prefix or _fixture
suffix; keep the returned object creation
(PerplexityInternetSearchToolConfig(api_key="test-key", max_retries=2,
max_query_length=50)) unchanged so tests referencing the "tool_config" fixture
continue to work.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 1ebf83fb-a343-4069-a34b-f464d7bc500e

📥 Commits

Reviewing files that changed from the base of the PR and between ca59672 and 9b8f95f.

📒 Files selected for processing (5)
  • ci/vale/styles/config/vocabularies/nat/accept.txt
  • docs/source/get-started/tutorials/add-tools-to-a-workflow.md
  • packages/nvidia_nat_langchain/src/nat/plugins/langchain/tools/perplexity_internet_search.py
  • packages/nvidia_nat_langchain/src/nat/plugins/langchain/tools/register.py
  • packages/nvidia_nat_langchain/tests/test_perplexity_internet_search.py

Signed-off-by: James Liounis <james.liounis@perplexity.ai>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/nvidia_nat_langchain/src/nat/plugins/langchain/tools/perplexity_internet_search.py (1)

75-76: ⚡ Quick win

Add a public docstring to perplexity_internet_search.

Line 76 exposes a public registration function without a docstring. Add a short Google-style docstring so the public API surface is consistently documented.

Proposed fix
 `@register_function`(config_type=PerplexityInternetSearchToolConfig, framework_wrappers=[LLMFrameworkEnum.LANGCHAIN])
 async def perplexity_internet_search(tool_config: PerplexityInternetSearchToolConfig, builder: Builder):
+    """Register the `perplexity_internet_search` LangChain tool.
+
+    Args:
+        tool_config (PerplexityInternetSearchToolConfig): Tool configuration.
+        builder (Builder): Workflow builder context.
+    """
     import os

As per coding guidelines, "Provide Google-style docstrings for every public module, class, function and CLI command."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/nvidia_nat_langchain/src/nat/plugins/langchain/tools/perplexity_internet_search.py`
around lines 75 - 76, Add a short Google-style docstring to the public function
perplexity_internet_search to document its purpose, parameters, and return
value; specifically describe what the function does, the tool_config parameter
(PerplexityInternetSearchToolConfig) and builder parameter (Builder), and what
the registered/returned object or side-effects are, following the existing
project docstring style for public APIs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@packages/nvidia_nat_langchain/src/nat/plugins/langchain/tools/perplexity_internet_search.py`:
- Around line 117-139: The retry loop in the Perplexity search code (inside the
for loop that posts to PERPLEXITY_SEARCH_URL) currently catches all exceptions
and retries, which causes unnecessary retries for non-retriable client errors;
update the exception handling in that block to inspect HTTP responses and only
retry on transient errors (HTTP 5xx and 429) or network/timeouts, while
returning early for non-retriable 4xx errors (e.g., 401, 403) with a clear error
message; use response.raise_for_status() results or the response.status_code to
branch accordingly and avoid exponential-backoff retries for deterministic
client failures, and retain logger.exception for transient failures. Also add a
Google-style docstring to the public function perplexity_internet_search
describing its purpose, parameters, and return value.

---

Nitpick comments:
In
`@packages/nvidia_nat_langchain/src/nat/plugins/langchain/tools/perplexity_internet_search.py`:
- Around line 75-76: Add a short Google-style docstring to the public function
perplexity_internet_search to document its purpose, parameters, and return
value; specifically describe what the function does, the tool_config parameter
(PerplexityInternetSearchToolConfig) and builder parameter (Builder), and what
the registered/returned object or side-effects are, following the existing
project docstring style for public APIs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: a7b2d2b1-aa99-47e2-9249-08a4186b8b9b

📥 Commits

Reviewing files that changed from the base of the PR and between 9b8f95f and 42c15bd.

📒 Files selected for processing (2)
  • packages/nvidia_nat_langchain/src/nat/plugins/langchain/tools/perplexity_internet_search.py
  • packages/nvidia_nat_langchain/tests/test_perplexity_internet_search.py
✅ Files skipped from review due to trivial changes (1)
  • packages/nvidia_nat_langchain/tests/test_perplexity_internet_search.py

Comment thread packages/nvidia_nat_core/src/nat/tool/perplexity_internet_search.py
…tion-header helper

Addresses CodeRabbit review nit: public registration function and the
integration-header helper now carry Google-style docstrings, raising
docstring coverage on the new module above NeMo's 80% threshold.

Signed-off-by: James Liounis <james.liounis@perplexity.ai>
@jliounis
Copy link
Copy Markdown
Author

Pushed c0bd9ab to address review feedback and prepare this for merge:

Addressed

  • Added Google-style docstring to perplexity_internet_search (the public registration function — addresses CodeRabbit's actionable nit and the "Docstring Coverage" pre-merge check).
  • Added a docstring to the _get_integration_header helper for consistency.

Declined (with reason)

  • CodeRabbit's nit on the test-fixture name (name= arg / fixture_/_fixture suffix) — the Exa test in this same package (test_exa_internet_search.py, line 84) uses the exact same plain @pytest.fixture\ndef tool_config(): pattern, so this PR is consistent with the repo's actual convention.

Still need maintainer help to unblock CI (admin-only):

  1. copy-pr-bot is still gating workflow runs. Could a vetter please run /ok to test c0bd9ab so the test matrix can run on the new commit?
  2. Label Checker was failing on the previous push — would feature request + non-breaking (matching Exa PR Add Exa Search API support as internet search tool #1846) be appropriate?

DCO is green. Tests pass locally (matching the Exa pattern line-for-line). Happy to address anything else.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/nvidia_nat_langchain/src/nat/plugins/langchain/tools/perplexity_internet_search.py (1)

82-82: ⚡ Quick win

Add a return type hint to the public perplexity_internet_search API.

The function is publicly registered and currently omits an explicit return type annotation.

🔧 Suggested change
+from collections.abc import AsyncIterator
@@
-async def perplexity_internet_search(tool_config: PerplexityInternetSearchToolConfig, builder: Builder):
+async def perplexity_internet_search(
+    tool_config: PerplexityInternetSearchToolConfig, builder: Builder
+) -> AsyncIterator[FunctionInfo]:

As per coding guidelines, "All public APIs require Python 3.11+ type hints on parameters and return values."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/nvidia_nat_langchain/src/nat/plugins/langchain/tools/perplexity_internet_search.py`
at line 82, The public async function perplexity_internet_search is missing an
explicit return type hint; update its signature to include the concrete return
annotation that matches what it actually returns (for example ->
PerplexityInternetSearchTool or -> Tool or the specific class/type returned) and
import that type if necessary; if the exact return type is not yet defined, use
a precise typing annotation such as -> typing.Coroutine[typing.Any, typing.Any,
ReturnType] or -> typing.Any as a temporary measure, then run static type checks
and replace with the concrete return type referenced in the function body (refer
to the perplexity_internet_search function and its returned value to pick the
correct symbol).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@packages/nvidia_nat_langchain/src/nat/plugins/langchain/tools/perplexity_internet_search.py`:
- Line 82: The public async function perplexity_internet_search is missing an
explicit return type hint; update its signature to include the concrete return
annotation that matches what it actually returns (for example ->
PerplexityInternetSearchTool or -> Tool or the specific class/type returned) and
import that type if necessary; if the exact return type is not yet defined, use
a precise typing annotation such as -> typing.Coroutine[typing.Any, typing.Any,
ReturnType] or -> typing.Any as a temporary measure, then run static type checks
and replace with the concrete return type referenced in the function body (refer
to the perplexity_internet_search function and its returned value to pick the
correct symbol).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 42315761-b95a-4262-8ed6-30cc688d7949

📥 Commits

Reviewing files that changed from the base of the PR and between 42c15bd and c0bd9ab.

📒 Files selected for processing (1)
  • packages/nvidia_nat_langchain/src/nat/plugins/langchain/tools/perplexity_internet_search.py

@bbednarski9
Copy link
Copy Markdown
Contributor

Hey @jliounis, thanks for submitting this PR. I've been in touch with Rachel, who I presume you're working with on our end. But I wanted to see if you'd be open to a quick sync to discuss a better way to package this feature. We're thinking it makes more sense for this to be a separate Perplexity-owned repo that you guys can maintain and more-quickly bring features into without being bogged down by our review cycle. Additionally, we'd be able to make the features framework-agnostic, so utilization is not just limited to langchain agents but rather all (~8) frameworks that NAT supports. Let me know if you'd be open to it!

@jliounis
Copy link
Copy Markdown
Author

jliounis commented May 5, 2026

@bbednarski9 thanks for the thoughtful framing — happy to sync. Before we lock in a plan, want to push back gently on the separate-repo piece and propose an in-tree alternative that gets you the framework-agnostic outcome without the overhead of a new repo.

Why I'd lean toward keeping this in-tree:

  • Discoverability. Users searching NAT's registry for a search tool find Perplexity alongside Exa/Tavily/Brave, not in a separate ecosystem they have to know about.
  • No second release cadence. A Perplexity-owned repo means we'd need our own release/versioning/CI story that has to track NAT's. In-tree, we just ship with NAT.
  • Compatibility guarantees. NAT's CI validates the integration on every release; an external repo can silently break across NAT minor versions.
  • First-class signal. "Built into NAT" reads very differently from "third-party plugin" for adoption.

The framework-agnostic goal is fully achievable in-tree. Concretely, I'd extend this PR to:

  1. Factor out the framework-agnostic core (HTTP client, auth, retry, X-Pplx-Integration header, response shaping) into a shared module — either under nvidia_nat_core or a thin nvidia_nat_perplexity shared-utils package, whichever you prefer.
  2. Register the Perplexity tool in each of the 8 framework plugins (adk, agno, autogen, crewai, langchain, llama_index, mcp, semantic_kernel), with each wrapper being a ~30-line adapter over the shared core.
  3. Mirror existing multi-framework patterns in the repo so it slots in without you needing to invent a new structure.

On the velocity concern — fully understand the worry about review cycles slowing us down. If that becomes a real issue, the cleanest mitigation is co-CODEOWNERS on **/perplexity* paths so I can land follow-ups without blocking the broader review queue. Happy to discuss that on the sync.

Working with Rachel — happy to grab time whenever works on your end. In parallel, I'll start the in-tree refactor (shared core + 8-framework registration) and push it to this branch. If after the sync you'd still strongly prefer a separate repo, we can pivot — the refactored code ports either way.

jliounis added a commit to jliounis/NeMo-Agent-Toolkit that referenced this pull request May 5, 2026
Per maintainer @bbednarski9's request on PR NVIDIA#1903, extend the Perplexity
internet search tool from LangChain-only to all 8 frameworks supported
by LLMFrameworkEnum: LANGCHAIN, LLAMA_INDEX, CREWAI, SEMANTIC_KERNEL,
AGNO, ADK, STRANDS, AUTOGEN.

The tool implementation is HTTP-only (raw httpx calls to
api.perplexity.ai/search) with no framework-specific imports, so it can
live in a single framework-agnostic location and be wrapped for each
target framework via NAT's existing tool_wrapper.py mechanism in each
plugin package.

Changes:
- Move tool from packages/nvidia_nat_langchain/.../tools/ to
  packages/nvidia_nat_core/.../tool/ (framework-agnostic location)
- Expand framework_wrappers list to include all 8 LLMFrameworkEnum values
- Move tests to nvidia_nat_core's test suite
- Update docs to reflect multi-framework support
Per maintainer @bbednarski9's request on PR NVIDIA#1903, extend the Perplexity
internet search tool from LangChain-only to all 8 frameworks supported
by LLMFrameworkEnum: LANGCHAIN, LLAMA_INDEX, CREWAI, SEMANTIC_KERNEL,
AGNO, ADK, STRANDS, AUTOGEN.

The tool implementation is HTTP-only (raw httpx calls to
api.perplexity.ai/search) with no framework-specific imports, so it can
live in a single framework-agnostic location and be wrapped for each
target framework via NAT's existing tool_wrapper.py mechanism in each
plugin package.

Changes:
- Move tool from packages/nvidia_nat_langchain/.../tools/ to
  packages/nvidia_nat_core/.../tool/ (framework-agnostic location)
- Expand framework_wrappers list to include all 8 LLMFrameworkEnum values
- Move tests to nvidia_nat_core's test suite
- Update docs to reflect multi-framework support

Signed-off-by: James Liounis <james.liounis@perplexity.ai>
@jliounis jliounis force-pushed the add-perplexity-internet-search branch from efbdafd to f3495c0 Compare May 5, 2026 13:30
@jliounis
Copy link
Copy Markdown
Author

jliounis commented May 5, 2026

Pushed f3495c0 extending this PR to all 8 NAT frameworks, in line with the in-tree refactor proposed above.

Changes

  • Moved the tool from packages/nvidia_nat_langchain/src/nat/plugins/langchain/tools/perplexity_internet_search.py to packages/nvidia_nat_core/src/nat/tool/perplexity_internet_search.py — alongside other framework-agnostic tools like datetime_tools, document_search, nvidia_rag. The tool's only HTTP dependency is httpx against https://api.perplexity.ai/search; there are no framework-specific imports, so it slots cleanly into core without needing a new shared package.
  • Expanded the decorator's framework_wrappers list from [LLMFrameworkEnum.LANGCHAIN] to all 8 values: LANGCHAIN, LLAMA_INDEX, CREWAI, SEMANTIC_KERNEL, AGNO, ADK, STRANDS, AUTOGEN.
  • Verified at runtime that GlobalTypeRegistry reports the tool under nat.tool/perplexity_internet_search with all 8 frameworks active.
  • Updated _get_integration_header() to read the version from the nvidia-nat package metadata (was nvidia-nat-langchain) so the X-Pplx-Integration header tracks the new home.
  • Moved tests to packages/nvidia_nat_core/tests/nat/tools/test_perplexity_internet_search.py. 14/14 passing locally; ruff clean.
  • Updated the Perplexity section in docs/source/get-started/tutorials/add-tools-to-a-workflow.md to reflect framework-agnostic packaging (no [langchain] extra required to install the tool).

Net diff is small — most of the work is the file move. Easy to review with git diff --find-renames.

Let me know if there's a different shared-core location you'd prefer (nvidia_nat_perplexity package vs. nvidia_nat_core), or if you'd like me to expose the Agent API client in this PR as well rather than as a follow-up. Otherwise this should be ready for /ok to test f3495c0 from a vetter.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/nvidia_nat_core/tests/nat/tools/test_perplexity_internet_search.py (1)

85-90: ⚡ Quick win

Align fixture declaration with repository fixture naming rules.

Please set an explicit fixture name and rename the fixture function to the required pattern.

Proposed fix
-@pytest.fixture
-def tool_config():
+@pytest.fixture(name="tool_config")
+def tool_config_fixture():
     from nat.tool.perplexity_internet_search import PerplexityInternetSearchToolConfig

     return PerplexityInternetSearchToolConfig(api_key="test-key", max_retries=2, max_query_length=50)

As per coding guidelines, “Pytest fixtures should define the name argument... [and] function being decorated should be named using either a fixture_ prefix or _fixture suffix.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/nvidia_nat_core/tests/nat/tools/test_perplexity_internet_search.py`
around lines 85 - 90, Rename the fixture function and set an explicit pytest
fixture name: change the function currently named tool_config to follow the
repository pattern (e.g., fixture_tool_config or tool_config_fixture) and add
the name argument on the decorator like `@pytest.fixture`(name="tool_config") so
tests using "tool_config" keep working; update the function name in the file
(the function that returns PerplexityInternetSearchToolConfig) to the new
prefixed/suffixed name and keep the decorator name="tool_config" to preserve the
public fixture identifier.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/source/get-started/tutorials/add-tools-to-a-workflow.md`:
- Line 202: Replace the prose usage of "NAT" in the sentence that currently
reads "supported by NAT" with "the toolkit" or "NeMo Agent Toolkit" while
keeping backtick-enclosed `nat` identifiers unchanged; locate the sentence
containing "perplexity_internet_search" and update "supported by NAT" →
"supported by the toolkit" (or "supported by NeMo Agent Toolkit") so that
toolkit names appear only as full names in prose and `nat` remains only in
code/package ticks.

In `@packages/nvidia_nat_core/src/nat/tool/perplexity_internet_search.py`:
- Line 94: The public registration function perplexity_internet_search is an
async generator but lacks a return type; update its signature to return
AsyncIterator[FunctionInfo] (e.g. async def
perplexity_internet_search(tool_config: PerplexityInternetSearchToolConfig,
builder: Builder) -> AsyncIterator[FunctionInfo]:) and add the necessary imports
for AsyncIterator (from typing) and FunctionInfo (where FunctionInfo is defined
in your tool/registration types) so the function signature and exports have
explicit type hints.

---

Nitpick comments:
In `@packages/nvidia_nat_core/tests/nat/tools/test_perplexity_internet_search.py`:
- Around line 85-90: Rename the fixture function and set an explicit pytest
fixture name: change the function currently named tool_config to follow the
repository pattern (e.g., fixture_tool_config or tool_config_fixture) and add
the name argument on the decorator like `@pytest.fixture`(name="tool_config") so
tests using "tool_config" keep working; update the function name in the file
(the function that returns PerplexityInternetSearchToolConfig) to the new
prefixed/suffixed name and keep the decorator name="tool_config" to preserve the
public fixture identifier.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 2317e054-cfd0-4615-827e-cef412381415

📥 Commits

Reviewing files that changed from the base of the PR and between c0bd9ab and efbdafd.

📒 Files selected for processing (4)
  • docs/source/get-started/tutorials/add-tools-to-a-workflow.md
  • packages/nvidia_nat_core/src/nat/tool/perplexity_internet_search.py
  • packages/nvidia_nat_core/src/nat/tool/register.py
  • packages/nvidia_nat_core/tests/nat/tools/test_perplexity_internet_search.py

Comment thread docs/source/get-started/tutorials/add-tools-to-a-workflow.md Outdated
Comment thread packages/nvidia_nat_core/src/nat/tool/perplexity_internet_search.py Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
docs/source/get-started/tutorials/add-tools-to-a-workflow.md (1)

202-202: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Replace "NAT" acronym with "the toolkit" in documentation prose.

Line 202 still contains "supported by NAT" which violates the coding guideline: "Never use 'NAT' or 'nat' to refer to the toolkit in documentation." Use "the toolkit" or "NeMo Agent Toolkit" instead. Keep nat only for code/package identifiers in backticks.

📝 Proposed fix
-The `perplexity_internet_search` tool ships with the core `nvidia-nat` package and is framework-agnostic — it can be used with any of the agent frameworks supported by NAT (`langchain`, `llama_index`, `crewai`, `semantic_kernel`, `agno`, `adk`, `strands`, and `autogen`). No framework-specific extra is required to install it:
+The `perplexity_internet_search` tool ships with the core `nvidia-nat` package and is framework-agnostic — it can be used with any of the agent frameworks supported by the toolkit (`langchain`, `llama_index`, `crewai`, `semantic_kernel`, `agno`, `adk`, `strands`, and `autogen`). No framework-specific extra is required to install it:

As per coding guidelines, "Never use 'NAT' or 'nat' to refer to the toolkit in documentation."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/source/get-started/tutorials/add-tools-to-a-workflow.md` at line 202,
Replace the phrase "supported by NAT" in the sentence that mentions the
`perplexity_internet_search` tool with "supported by the toolkit" (or "supported
by the NeMo Agent Toolkit") so the prose no longer uses the acronym "NAT"; keep
any backticked identifiers like `nvidia-nat` or `nat` unchanged in code/package
contexts and only update the surrounding documentation text (the sentence that
currently reads "it can be used with any of the agent frameworks supported by
NAT").
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@docs/source/get-started/tutorials/add-tools-to-a-workflow.md`:
- Line 202: Replace the phrase "supported by NAT" in the sentence that mentions
the `perplexity_internet_search` tool with "supported by the toolkit" (or
"supported by the NeMo Agent Toolkit") so the prose no longer uses the acronym
"NAT"; keep any backticked identifiers like `nvidia-nat` or `nat` unchanged in
code/package contexts and only update the surrounding documentation text (the
sentence that currently reads "it can be used with any of the agent frameworks
supported by NAT").

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: cb16bec1-cd99-4be4-be2b-b13d3f2abecc

📥 Commits

Reviewing files that changed from the base of the PR and between efbdafd and f3495c0.

📒 Files selected for processing (4)
  • docs/source/get-started/tutorials/add-tools-to-a-workflow.md
  • packages/nvidia_nat_core/src/nat/tool/perplexity_internet_search.py
  • packages/nvidia_nat_core/src/nat/tool/register.py
  • packages/nvidia_nat_core/tests/nat/tools/test_perplexity_internet_search.py
✅ Files skipped from review due to trivial changes (1)
  • packages/nvidia_nat_core/src/nat/tool/register.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/nvidia_nat_core/src/nat/tool/perplexity_internet_search.py
  • packages/nvidia_nat_core/tests/nat/tools/test_perplexity_internet_search.py

- Validate country field as ISO 3166-1 alpha-2 (min/max length 2, pattern ^[A-Z]{2}$)
- Skip retry on non-retriable 4xx (401/403/404); continue retrying 5xx and timeouts
- Replace 'NAT' acronym with 'the toolkit' in user-facing docs (per repo guideline)
- Add AsyncIterator[FunctionInfo] return type annotation to the public registration function

Signed-off-by: James Liounis <james.liounis@perplexity.ai>
@jliounis
Copy link
Copy Markdown
Author

jliounis commented May 5, 2026

Thanks for the thorough review, @coderabbitai! All 4 actionable comments addressed in 470d3b4:

  1. Validate country ISO 3166-1 alpha-2 (Major)packages/nvidia_nat_core/src/nat/tool/perplexity_internet_search.py: added min_length=2, max_length=2, and pattern=r"^[A-Z]{2}$" to the country field on PerplexityInternetSearchToolConfig so invalid country codes are rejected at config-validation time rather than burning retries on a guaranteed-fail server response.

  2. Don't retry on non-retriable 4xx (Major) — same file: refactored the retry loop to short-circuit on 401/403/404 with a clear log + early return, while preserving exponential backoff for 5xx (via httpx.HTTPStatusError), 408/429, and other transient/network errors.

  3. Replace "NAT" with "the toolkit" in user-facing docs (Major)docs/source/get-started/tutorials/add-tools-to-a-workflow.md line 202: swapped the standalone "NAT" acronym for "the toolkit" per the repo's documentation convention. Backticked code identifiers (nat, nvidia-nat) were left untouched. Scanned the rest of the file and there were no other acronym-style usages.

  4. Add AsyncIterator[FunctionInfo] return type (Minor) — same Python file: added from collections.abc import AsyncIterator and annotated the perplexity_internet_search registration function's return type explicitly.

All 14 existing tests in tests/nat/tools/test_perplexity_internet_search.py still pass.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 5, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check the latest state of the main file after the fixes
cat packages/nvidia_nat_core/src/nat/tool/perplexity_internet_search.py

Length of output: 9492


@jliounis: Thanks for the detailed write-up and for pushing 470d3b49! I've verified all four fixes in the code:

  1. country ISO 3166-1 alpha-2 validationmin_length=2, max_length=2, pattern=r"^[A-Z]{2}$" are all present on the country field.
  2. Non-retriable 4xx short-circuit{401, 403, 404} are caught immediately after client.post(...) with an early return, while httpx.HTTPStatusError (covering 5xx and other status errors) still goes through the exponential backoff retry loop.
  3. Docs "NAT" → "the toolkit" — confirmed per your description; code identifiers like `nat` and `nvidia-nat` correctly left as-is.
  4. AsyncIterator[FunctionInfo] return typefrom collections.abc import AsyncIterator is imported and the return type annotation is applied to perplexity_internet_search.

The implementation looks clean and consistent with the rest of the codebase. Good luck getting the CI gates unblocked!

Reorder the 'Alternate Method Using a Web Search Tool' section so that
perplexity_internet_search is the lead example, with tavily_internet_search
and exa_internet_search retained as alternatives below.

perplexity_internet_search ships with nvidia-nat-core and is framework-
agnostic across all 8 LLMFrameworkEnum values, making it the only single
default that works regardless of which agent framework the reader picked
in the earlier tutorial steps. The Tavily and Exa subsections are kept
verbatim for users who prefer those backends.

Signed-off-by: James Liounis <james.liounis@perplexity.ai>
@jliounis
Copy link
Copy Markdown
Author

jliounis commented May 5, 2026

Hi @bbednarski9 — separate from the review thread, want to flag a small follow-on I just pushed onto this PR (commit 0d4d1882) for your consideration: it swaps the lead web-search example in docs/source/get-started/tutorials/add-tools-to-a-workflow.md from tavily_internet_search to perplexity_internet_search, with Tavily and Exa kept verbatim as alternatives below. Docs-only, ~40 lines net. If you'd prefer the tutorial stay vendor-neutral or keep Tavily as the lead, this commit is easy to revert with one click — no hard feelings.

The case for Perplexity as the canonical tutorial example:

  • Single API + LLM-tuned index. Perplexity Search hits the same Sonar index used by perplexity.ai itself. Snippets come pre-filtered for retrieval-augmented generation, so an agent needs fewer tool calls to ground an answer — tighter loops in tutorials.
  • One env var. PERPLEXITY_API_KEY (fallback PPLX_API_KEY) and you're set. No separate scraper / re-ranker / embedding step.
  • Now in nvidia-nat-core. With the in-tree refactor in this PR, perplexity_internet_search is wrapped for all 8 frameworks (LangChain, LlamaIndex, CrewAI, Semantic Kernel, Agno, ADK, Strands, AutoGen) — the only single-default that works regardless of which agent framework the reader picked earlier in the tutorial. Tavily/Exa are gated on the [langchain] extra.
  • Maintained by us. The Perplexity API team owns this integration — direct support channel if anything breaks.

Totally happy to drop the docs commit if you'd rather merge this PR strictly as the tool addition — just let me know and I'll revert. Thanks again for the review.

@bbednarski9
Copy link
Copy Markdown
Contributor

Hey @jliounis thanks for the heads up. Ack on your comments above. Syncing internally to make sure everything is considered per architecture. Will update shortly

@jliounis
Copy link
Copy Markdown
Author

jliounis commented May 7, 2026

@bbednarski9 Looking forward to chatting. In the meantime, is there anything needed on our end to merge this?

jliounis added 2 commits May 11, 2026 19:18
Add a new `perplexity` embedder provider backed by Perplexity's dedicated
Embeddings API (`POST https://api.perplexity.ai/v1/embeddings`). The provider
ships in the core `nvidia-nat` package and is wired into both the LangChain
and LlamaIndex framework plugins, mirroring the existing `openai` /
`azure_openai` / `nim` embedders.

Highlights:

- `PerplexityEmbedderModelConfig` supports all four documented models
  (`pplx-embed-v1-0.6b`, `pplx-embed-v1-4b`, plus the contextualized
  `pplx-embed-context-v1-*` variants), Matryoshka `dimensions`,
  `batch_size`, and the two on-wire `encoding_format` options
  (`base64_int8`, `base64_binary`). Resolves the API key from config or
  `PERPLEXITY_API_KEY`.

- A framework-agnostic `PerplexityEmbeddings` LangChain client batches
  inputs (up to 512/request), decodes the base64 payload locally to a
  float vector, retries transient HTTP failures with backoff, and
  forwards an `X-Pplx-Integration: nemo-agent-toolkit/<version>`
  attribution header on every request.

- A `PerplexityLlamaIndexEmbedding` adapter wraps the shared client to
  satisfy LlamaIndex's `BaseEmbedding` interface so the same NAT config
  can be consumed by LlamaIndex-powered retrievers/RAG flows.

- Docs: adds Perplexity to the embedder provider table and configuration
  examples in `docs/source/build-workflows/embedders.md`, and adds
  Perplexity to the LangChain/LlamaIndex embedder rows in
  `docs/source/components/integrations/frameworks.md`.

- Tests: 8 config tests + 11 LangChain client tests + 4 LlamaIndex
  adapter tests (23 total) covering config validation, batching,
  base64_int8/binary decoding, attribution header propagation,
  non-retriable status short-circuit, async paths, and registration
  with `PERPLEXITY_API_KEY` resolution.

Reference: https://docs.perplexity.ai/api-reference/embeddings-post

Signed-off-by: James Liounis <james.liounis@perplexity.ai>
@jliounis jliounis changed the title Add Perplexity Search API support as internet search tool Add Perplexity Search API tool + Perplexity Embeddings API provider May 11, 2026
@jliounis
Copy link
Copy Markdown
Author

Expanded this PR to cover both Perplexity Search and Perplexity Embeddings — pushed as c19db75. Title and description updated to match.

What's new in this commit

  • New core embedder provider _type: perplexity (PerplexityEmbedderModelConfig) supporting all four documented models — pplx-embed-v1-0.6b, pplx-embed-v1-4b, and the document-aware pplx-embed-context-v1-0.6b / pplx-embed-context-v1-4b — plus Matryoshka dimensions, batch_size, and the two on-wire encoding_format options (base64_int8, base64_binary). Resolves the API key from config or PERPLEXITY_API_KEY.
  • Framework-agnostic PerplexityEmbeddings LangChain client (httpx-based) that batches inputs up to 512/request, decodes the base64 payload locally to float vectors, retries transient HTTP failures with backoff, and forwards the same X-Pplx-Integration: nemo-agent-toolkit/<version> attribution header used by the search tool.
  • PerplexityLlamaIndexEmbedding adapter wrapping the shared client so the same NAT config plugs into LlamaIndex-powered retrievers/RAG flows.
  • Docs: Perplexity row + dedicated section in docs/source/build-workflows/embedders.md, plus updates to the LangChain/LlamaIndex embedder rows in docs/source/components/integrations/frameworks.md.

Tests — 23 new tests, all green locally:

  • 8 config tests (packages/nvidia_nat_core/tests/nat/embedder/test_perplexity_embedder.py)
  • 11 LangChain client tests (packages/nvidia_nat_langchain/tests/test_perplexity_embeddings.py) covering int8/binary decode round-trip, batching, attribution header propagation, dimensions-in-body, 401 short-circuit, async path, env-key resolution
  • 4 LlamaIndex adapter tests (packages/nvidia_nat_llama_index/tests/test_perplexity_embedder_llama_index.py)

Minimal config:

embedders:
  perplexity_embedder:
    _type: perplexity
    model_name: pplx-embed-v1-0.6b
    dimensions: 512   # optional Matryoshka truncation

Set PERPLEXITY_API_KEY to authenticate. API reference: https://docs.perplexity.ai/api-reference/embeddings-post.

@bbednarski9 bbednarski9 self-assigned this May 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants