Skip to content

feat(tools): add SkimReaderTool (x402-paid clean web reader)#6266

Open
JessieJanie wants to merge 2 commits into
crewAIInc:mainfrom
JessieJanie:feat/skim-reader-tool
Open

feat(tools): add SkimReaderTool (x402-paid clean web reader)#6266
JessieJanie wants to merge 2 commits into
crewAIInc:mainfrom
JessieJanie:feat/skim-reader-tool

Conversation

@JessieJanie

@JessieJanie JessieJanie commented Jun 20, 2026

Copy link
Copy Markdown

Summary

Adds SkimReaderTool — a tool that fetches any URL and returns clean, agent-ready Markdown plus structured metadata (title, byline, published date, language, excerpt) via Skim, the x402-native clean reader API for AI agents.

Reads are paid per call over the x402 protocol ($0.002 in USDC on Base) using a wallet the user controls — no API keys, no signup. The wallet private key is used only to sign USDC payment authorizations locally and is never transmitted. This mirrors the existing reader/scraper tools (e.g. FirecrawlScrapeWebsiteTool) but with x402 micropayments instead of API keys.

What's included

  • lib/crewai-tools/src/crewai_tools/tools/skim_reader_tool/ — the tool, package __init__.py, and README.md
  • Exports wired into tools/__init__.py and crewai_tools/__init__.py (alphabetical)
  • A new optional x402 extra in lib/crewai-tools/pyproject.toml (x402[evm], eth-account, requests)
  • tests/tools/skim_reader_tool_test.py — fully mocked and offline (no network, no real payments), compatible with the --block-network test policy

Usage

from crewai_tools import SkimReaderTool

tool = SkimReaderTool()  # reads SKIM_WALLET_PRIVATE_KEY from env
markdown = tool.run(url="https://en.wikipedia.org/wiki/HTTP_402")

The x402 client dependencies are imported lazily, so importing crewai_tools without the x402 extra installed is unaffected; the tool raises a clear error only when actually run without the extra or a wallet key.

Notes

  • ruff check and ruff format --check pass locally against the repo config (ruff 0.15.1).
  • I did not regenerate tool.specs.json since the spec-generation workflow runs from the base repo on merge; happy to add it if maintainers prefer it in the PR.

Summary by CodeRabbit

  • New Features
    • Added SkimReaderTool to fetch web pages and return clean Markdown, with optional YAML frontmatter metadata. Includes configurable base URL, per-request price cap, and request timeout; supports wallet-backed x402 access.
  • Documentation
    • Added a README with installation and usage examples for SkimReaderTool.
  • Tests
    • Expanded unit tests for URL validation, response parsing, session setup, and error handling.
  • Chores
    • Exposed SkimReaderTool at the package and tools level; added the x402 optional dependency group.

Adds SkimReaderTool, which fetches any URL and returns clean, agent-ready
Markdown plus structured metadata via Skim (skim402.com). Each call is paid
automatically over the x402 protocol ($0.002 in USDC on Base) using a wallet
the user controls; no API keys or signup. The private key signs USDC payment
authorizations locally and is never transmitted.

- lib/crewai-tools/src/crewai_tools/tools/skim_reader_tool/ (tool + README)
- wires exports in tools/__init__.py and crewai_tools/__init__.py
- adds the optional 'x402' extra in lib/crewai-tools/pyproject.toml
- adds tests/tools/skim_reader_tool_test.py (fully mocked, offline)
@coderabbitai

coderabbitai Bot commented Jun 20, 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: 74c7cc71-3e01-4644-a804-5c256cf224fb

📥 Commits

Reviewing files that changed from the base of the PR and between 7033a68 and 855d0b3.

📒 Files selected for processing (1)
  • lib/crewai-tools/tests/tools/skim_reader_tool_test.py

📝 Walkthrough

Walkthrough

Adds a new SkimReaderTool to crewai-tools that fetches clean Markdown from Skim's API using an x402 HTTP 402 payment flow backed by an EVM wallet. Includes the tool implementation, an x402 optional dependency group, package exports in both __init__.py files, mocked unit tests, and a README.

Changes

SkimReaderTool

Layer / File(s) Summary
x402 dependency group and package exports
lib/crewai-tools/pyproject.toml, lib/crewai-tools/src/crewai_tools/__init__.py, lib/crewai-tools/src/crewai_tools/tools/__init__.py
Declares the x402 optional dependency group (x402[evm]>=2.0.0, eth-account>=0.13.0, requests>=2.31.0) and registers SkimReaderTool in both package-level __init__.py import and __all__ lists.
Tool constants, schema, and class configuration
lib/crewai-tools/src/crewai_tools/tools/skim_reader_tool/skim_reader_tool.py
Defines DEFAULT_BASE_URL, _yaml_scalar YAML scalar helper, _TOOL_DESCRIPTION, SkimReaderToolSchema (with url field), and the SkimReaderTool class with public fields private_key, base_url, max_price_usd, include_metadata, timeout, package_dependencies, and env_vars.
Session construction and _run execution
lib/crewai-tools/src/crewai_tools/tools/skim_reader_tool/skim_reader_tool.py
_get_session() dynamically imports x402/EVM/eth-account components, validates and normalizes the wallet private key (64-hex enforcement), computes a USDC cap, and caches a payment-wrapped requests.Session. _run() validates the URL, POSTs to /api/v1/read in basic mode, handles HTTP/JSON errors, extracts markdown or text, and prepends YAML frontmatter from metadata when include_metadata=True.
Unit tests and README
lib/crewai-tools/tests/tools/skim_reader_tool_test.py, lib/crewai-tools/src/crewai_tools/tools/skim_reader_tool/README.md
Fully mocked test suite with _FakeResponse/_FakeSession stubs and a monkeypatched validate_url covering defaults, frontmatter generation, metadata field filtering, text fallback, HTTP error propagation, and private key validation. README documents installation, wallet setup, usage examples, and all configurable arguments.

Sequence Diagram

sequenceDiagram
  participant Agent
  participant SkimReaderTool
  participant _get_session
  participant x402Session
  participant SkimAPI

  Agent->>SkimReaderTool: _run(url)
  SkimReaderTool->>SkimReaderTool: validate_url(url)
  SkimReaderTool->>_get_session: request cached session
  _get_session->>_get_session: import x402/EVM deps, validate private key (hex-64)
  _get_session->>x402Session: wrap requests.Session with EVM payment policy (USDC cap)
  _get_session-->>SkimReaderTool: payment-aware Session
  SkimReaderTool->>SkimAPI: POST /api/v1/read {url, mode: "basic"}
  SkimAPI-->>SkimReaderTool: JSON {markdown, metadata}
  SkimReaderTool->>SkimReaderTool: extract markdown/text, build YAML frontmatter (if include_metadata)
  SkimReaderTool-->>Agent: Markdown string
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.70% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding a new SkimReaderTool that uses x402 protocol for micropayments.
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.

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

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

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 and usage tips.

@corridor-security corridor-security 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.

Security Issues

  • Software Supply Chain Failure
    The new x402 extra declares direct dependencies with open-ended lower-bound-only specifiers and no corresponding lockfile update in this diff. Installing crewai-tools[x402] can resolve arbitrary future upstream releases, including compromised or malicious packages.

Summary: This PR adds a paid Skim web reader tool and introduces new optional third-party dependencies for x402/EVM payment support.

Risk: Medium risk. The runtime target URL is validated before use, but the new user-installable extra weakens the repository’s supply-chain guardrails by allowing unbounded dependency resolution.

Recommendations:

  • Replace the open-ended dependency specifiers with bounded constraints and regenerate/commit the root uv.lock so installs remain reproducible.

"eth-account>=0.13.0",
"requests>=2.31.0",
]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The new optional extra uses lower-bound-only dependency specifiers:

x402 = [
    "x402[evm]>=2.0.0",
    "eth-account>=0.13.0",
    "requests>=2.31.0",
]

These are direct dependencies resolved when users install crewai-tools[x402]; without upper bounds and an updated root uv.lock, a future compromised or malicious release could be pulled into builds automatically. The project supply-chain guardrail requires bounded (~= or >=,<) constraints and committed lockfile updates.

Remediation: Use bounded version constraints for each new direct dependency and regenerate/commit the repository uv.lock.

For more details, see the finding in Corridor.

Provide feedback: Reply with whether this is a valid vulnerability or false positive to help improve Corridor's accuracy.

…ation tests

Adds an offline (mocked) test that _get_session builds and caches the
x402-wrapped requests session, and a test asserting _run validates the URL
before issuing the request. Addresses review feedback.

@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.

Actionable comments posted: 1

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

77-81: ⚡ Quick win

Assert request timeout to lock the call contract.

_run() passes timeout=self.timeout; adding assert call["timeout"] == 60.0 here prevents silent regressions in request behavior.

🤖 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/skim_reader_tool_test.py` around lines 77 - 81,
The test is not verifying that the timeout parameter is passed correctly to the
request call. After the existing assertions for endpoint and json in the test
block (following the assertion on the json parameter), add a new assertion to
verify that the timeout value equals the expected value of 60.0 by checking
call["timeout"]. This ensures that the timeout parameter passed by _run() is
correctly captured and prevents regressions in request behavior.
lib/crewai-tools/src/crewai_tools/tools/skim_reader_tool/skim_reader_tool.py (1)

151-158: 💤 Low value

Consider case-insensitive handling of 0x prefix.

The prefix check only handles lowercase 0x. Users occasionally provide keys with uppercase 0X, which would fail validation even though it's a valid hex prefix in Ethereum tooling.

Suggested fix
-        normalized = key[2:] if key.startswith("0x") else key
+        normalized = key[2:] if key.lower().startswith("0x") else key
🤖 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/src/crewai_tools/tools/skim_reader_tool/skim_reader_tool.py`
around lines 151 - 158, The prefix validation in the skim_reader_tool.py file
only checks for lowercase "0x" prefix using key.startswith("0x"), which means
uppercase "0X" prefixes will not be recognized and will fail validation. Modify
the prefix check to be case-insensitive by either converting the key to
lowercase before checking (key.lower().startswith("0x")) or explicitly checking
for both variations using key.startswith(("0x", "0X")). This ensures that both
"0x" and "0X" prefixes are properly stripped before validation, allowing users
to provide private keys with either case format.
🤖 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 `@lib/crewai-tools/tests/tools/skim_reader_tool_test.py`:
- Around line 109-122: The tests test_get_session_requires_a_key and
test_get_session_rejects_malformed_key fail non-deterministically because
_get_session() performs dynamic imports of x402 and eth-account modules before
validating the key parameters, causing ImportError in environments without these
optional extras rather than the expected ValueError. Monkeypatch the
importlib.import_module function (or whatever dynamic import mechanism is used
within _get_session) to return mock objects so that the key validation logic is
tested in isolation without being blocked by missing optional dependencies. Add
the monkeypatch fixture parameter to both test functions and configure it to
intercept the import calls within _get_session.

---

Nitpick comments:
In
`@lib/crewai-tools/src/crewai_tools/tools/skim_reader_tool/skim_reader_tool.py`:
- Around line 151-158: The prefix validation in the skim_reader_tool.py file
only checks for lowercase "0x" prefix using key.startswith("0x"), which means
uppercase "0X" prefixes will not be recognized and will fail validation. Modify
the prefix check to be case-insensitive by either converting the key to
lowercase before checking (key.lower().startswith("0x")) or explicitly checking
for both variations using key.startswith(("0x", "0X")). This ensures that both
"0x" and "0X" prefixes are properly stripped before validation, allowing users
to provide private keys with either case format.

In `@lib/crewai-tools/tests/tools/skim_reader_tool_test.py`:
- Around line 77-81: The test is not verifying that the timeout parameter is
passed correctly to the request call. After the existing assertions for endpoint
and json in the test block (following the assertion on the json parameter), add
a new assertion to verify that the timeout value equals the expected value of
60.0 by checking call["timeout"]. This ensures that the timeout parameter passed
by _run() is correctly captured and prevents regressions in request behavior.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 523bd38d-9f30-4a1b-b196-0868c5f4cb95

📥 Commits

Reviewing files that changed from the base of the PR and between 9db2d44 and 7033a68.

📒 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/skim_reader_tool/README.md
  • lib/crewai-tools/src/crewai_tools/tools/skim_reader_tool/__init__.py
  • lib/crewai-tools/src/crewai_tools/tools/skim_reader_tool/skim_reader_tool.py
  • lib/crewai-tools/tests/tools/skim_reader_tool_test.py

Comment thread lib/crewai-tools/tests/tools/skim_reader_tool_test.py
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