Skip to content

feat: add DuckDuckGoSearchTool (keyless web search)#6498

Open
m-hamza9752 wants to merge 2 commits into
crewAIInc:mainfrom
m-hamza9752:add-duckduckgo-search-tool
Open

feat: add DuckDuckGoSearchTool (keyless web search)#6498
m-hamza9752 wants to merge 2 commits into
crewAIInc:mainfrom
m-hamza9752:add-duckduckgo-search-tool

Conversation

@m-hamza9752

Copy link
Copy Markdown

What

Adds a new DuckDuckGoSearchTool to crewai-tools, providing web search via DuckDuckGo powered by the ddgs package.

Why

Every existing web-search tool in crewai-tools requires an API key — BraveSearchTool, SerpApiGoogleSearchTool, SerperDevTool, SerplyWebSearchTool, EXASearchTool, TavilySearchTool, LinkupSearchTool. There is currently no keyless web-search option.

DuckDuckGo requires no API key, which makes it a convenient, zero-configuration default for giving an agent internet-search capability — ideal for quick prototypes, examples, and first-time users. It's a common default across other agent frameworks, so it fills a real gap here.

Implementation

Mirrors the existing search tools (e.g. TavilySearchTool, BraveSearchTool) and follows the repo conventions:

  • New package lib/crewai-tools/src/crewai_tools/tools/duckduckgo_search_tool/ (duckduckgo_search_tool.py, __init__.py, README.md)
  • args_schema (DuckDuckGoSearchToolSchema) with a described, required search_query
  • Configurable n_results, region, and safesearch
  • Lazy import of ddgs with a clear, actionable install message
  • Graceful error handling — returns a friendly message instead of raising; no prints
  • package_dependencies via Field(default_factory=...)
  • Compact Title / Link / Snippet output, ready for an agent transcript
  • Exported from crewai_tools and crewai_tools.tools (import + __all__)
  • ddgs registered as an optional extra in lib/crewai-tools/pyproject.toml, with uv.lock updated accordingly

Usage

from crewai_tools import DuckDuckGoSearchTool

tool = DuckDuckGoSearchTool(n_results=5)
print(tool.run(search_query="latest developments in AI agents"))

Install the optional dependency:

uv add crewai-tools --extra ddgs   # or: pip install ddgs

Testing

  • Added lib/crewai-tools/tests/tools/duckduckgo_search_tool_test.py — 5 tests covering initialization, missing-query handling, the happy path, no-results, and error handling. All mocked; no network calls in CI.
  • Verified locally: ruff check and ruff format --check pass, mypy passes, pytest passes, and a real live search returns correctly-formatted results.

Add a DuckDuckGoSearchTool that lets agents search the web via
DuckDuckGo using the `ddgs` package. Unlike the existing search tools
(Brave, SerpApi, Serper, Serply, Exa, Tavily, Linkup), it requires no
API key, providing a zero-configuration default for web search.

- New tool under lib/crewai-tools/src/crewai_tools/tools/duckduckgo_search_tool/
- Configurable n_results, region and safesearch
- Lazy import of ddgs with a clear, actionable install message
- Graceful error handling; returns compact title/link/snippet text
- Unit tests under lib/crewai-tools/tests/tools/ (mocked, no network)
- Register `ddgs` as an optional extra in pyproject.toml
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: aea2c1eb-59c4-4bc9-8186-d6640998e589

📥 Commits

Reviewing files that changed from the base of the PR and between 37e65bc and a8c3972.

📒 Files selected for processing (2)
  • lib/crewai-tools/src/crewai_tools/tools/duckduckgo_search_tool/duckduckgo_search_tool.py
  • lib/crewai-tools/tests/tools/duckduckgo_search_tool_test.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • lib/crewai-tools/src/crewai_tools/tools/duckduckgo_search_tool/duckduckgo_search_tool.py
  • lib/crewai-tools/tests/tools/duckduckgo_search_tool_test.py

📝 Walkthrough

Walkthrough

Adds a new DuckDuckGoSearchTool backed by ddgs, exposes it through package exports, documents usage, and adds tests for initialization and search result, no-result, and error handling.

Changes

DuckDuckGo Search Tool

Layer / File(s) Summary
Optional dependency declaration
lib/crewai-tools/pyproject.toml
Adds a new ddgs optional-dependency extra requiring ddgs>=9.0.0.
Tool implementation and dependency check
lib/crewai-tools/src/crewai_tools/tools/duckduckgo_search_tool/duckduckgo_search_tool.py
Defines DuckDuckGoSearchToolSchema and DuckDuckGoSearchTool with configurable n_results, region, safesearch; validates the optional ddgs dependency on init and raises ImportError if missing; _run executes DDGS().text(...) and returns formatted results, a no-results message, or an error string.
Public exports
lib/crewai-tools/src/crewai_tools/__init__.py, lib/crewai-tools/src/crewai_tools/tools/__init__.py
Imports and adds DuckDuckGoSearchTool to __all__ in both the top-level and tools package __init__.py files.
Documentation and tests
lib/crewai-tools/src/crewai_tools/tools/duckduckgo_search_tool/README.md, lib/crewai-tools/tests/tools/duckduckgo_search_tool_test.py
Adds README covering installation and usage; adds tests for default initialization, empty-query handling, and mocked ddgs.DDGS success, no-results, and error scenarios.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant DuckDuckGoSearchTool
  participant DDGS

  Caller->>DuckDuckGoSearchTool: _run(search_query)
  DuckDuckGoSearchTool->>DuckDuckGoSearchTool: validate search_query
  DuckDuckGoSearchTool->>DDGS: text(query, n_results, region, safesearch)
  DDGS-->>DuckDuckGoSearchTool: results or exception
  DuckDuckGoSearchTool-->>Caller: formatted results, no-results message, or error string
Loading

Suggested reviewers: akaKuruma

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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
Title check ✅ Passed The title clearly names the new DuckDuckGoSearchTool and its keyless web search purpose.
Description check ✅ Passed The description directly matches the change set by explaining the new tool, optional dependency, exports, and tests.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
lib/crewai-tools/tests/tools/duckduckgo_search_tool_test.py (1)

30-47: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Verify that region, safesearch, and max_results are passed correctly to DDGS().text().

test_ddg_tool_search asserts instance.text.assert_called_once() but doesn't verify the arguments. Adding assert_called_once_with would catch regressions if the parameter-passing logic in _run changes.

♻️ Proposed improvement
-    instance.text.assert_called_once()
+    instance.text.assert_called_once_with(
+        "test",
+        region="wt-wt",
+        safesearch="moderate",
+        max_results=2,
+    )
🤖 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 `@lib/crewai-tools/tests/tools/duckduckgo_search_tool_test.py` around lines 30
- 47, The DuckDuckGo search test only checks that DDGS().text() is called, not
that _run passes the expected parameters. Update test_ddg_tool_search in
DuckDuckGoSearchTool to assert the exact call arguments with
assert_called_once_with, including region, safesearch, and max_results, so
regressions in parameter wiring are caught.
🤖 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.

Nitpick comments:
In `@lib/crewai-tools/tests/tools/duckduckgo_search_tool_test.py`:
- Around line 30-47: The DuckDuckGo search test only checks that DDGS().text()
is called, not that _run passes the expected parameters. Update
test_ddg_tool_search in DuckDuckGoSearchTool to assert the exact call arguments
with assert_called_once_with, including region, safesearch, and max_results, so
regressions in parameter wiring are caught.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 760d7e53-0351-4f7b-855b-6fbec7bb5b32

📥 Commits

Reviewing files that changed from the base of the PR and between 289686a and 37e65bc.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • lib/crewai-tools/pyproject.toml
  • lib/crewai-tools/src/crewai_tools/__init__.py
  • lib/crewai-tools/src/crewai_tools/tools/__init__.py
  • lib/crewai-tools/src/crewai_tools/tools/duckduckgo_search_tool/README.md
  • lib/crewai-tools/src/crewai_tools/tools/duckduckgo_search_tool/__init__.py
  • lib/crewai-tools/src/crewai_tools/tools/duckduckgo_search_tool/duckduckgo_search_tool.py
  • lib/crewai-tools/tests/tools/duckduckgo_search_tool_test.py

Address review feedback:
- test_ddg_tool_search now asserts the exact ddgs.text() call arguments
  (region, safesearch, max_results) via assert_called_once_with, so a
  parameter-wiring regression is caught.
- Add docstrings to DuckDuckGoSearchTool.__init__ and _run.
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.

1 participant