Skip to content

Feature/hackernews tool#6842

Open
wasi-ahmedd wants to merge 2 commits intoaden-hive:mainfrom
wasi-ahmedd:feature/hackernews-tool
Open

Feature/hackernews tool#6842
wasi-ahmedd wants to merge 2 commits intoaden-hive:mainfrom
wasi-ahmedd:feature/hackernews-tool

Conversation

@wasi-ahmedd
Copy link
Copy Markdown

@wasi-ahmedd wasi-ahmedd commented Mar 28, 2026

Description

Brief description of the changes in this PR.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactoring (no functional changes)

Related Issues

Fixes #(issue number)

Changes Made

  • Change 1
  • Change 2
  • Change 3

Testing

Describe the tests you ran to verify your changes:

  • Unit tests pass (cd core && pytest tests/)
  • Lint passes (cd core && ruff check .)
  • Manual testing performed

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

Screenshots (if applicable)

Add screenshots to demonstrate UI changes.

Summary by CodeRabbit

Release Notes

  • New Features

    • Hacker News integration: fetch top stories and retrieve story details including metadata and top-level comments using the Hacker News public API.
  • Bug Fixes

    • Enhanced error handling across multiple tools with more specific error messages for timeouts and network issues, replacing generic catch-all error handling.

@github-actions
Copy link
Copy Markdown

PR Requirements Warning

This PR does not meet the contribution requirements.
If the issue is not fixed within ~24 hours, it may be automatically closed.

Missing: No linked issue found.

To fix:

  1. Create or find an existing issue for this work
  2. Assign yourself to the issue
  3. Re-open this PR and add Fixes #123 in the description

Exception: To bypass this requirement, you can:

  • Add the micro-fix label or include micro-fix in your PR title for trivial fixes
  • Add the documentation label or include doc/docs in your PR title for documentation changes

Micro-fix requirements (must meet ALL):

Qualifies Disqualifies
< 20 lines changed Any functional bug fix
Typos & Documentation & Linting Refactoring for "clean code"
No logic/API/DB changes New features (even tiny ones)

Why is this required? See #472 for details.

@github-actions github-actions bot added the pr-requirements-warning PR doesn't follow contribution guidelines. Please fix or it will be auto-closed. label Mar 28, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 28, 2026

📝 Walkthrough

Walkthrough

This pull request introduces a new Hacker News tool integration that fetches top stories and retrieves story details with comments via the public Firebase API, while simultaneously refining exception handling across multiple existing tools to be more specific about httpx errors.

Changes

Cohort / File(s) Summary
Hacker News Tool
tools/src/aden_tools/tools/hackernews_tool/__init__.py, tools/src/aden_tools/tools/hackernews_tool/hackernews_tool.py, tools/src/aden_tools/tools/hackernews_tool/README.md
New Hacker News tool package with two MCP tools: get_top_hn_stories() fetches top story IDs from the public API and retrieves details for each; get_hn_story_details() retrieves a single story and optionally fetches top-level comments (capped to 20). Includes documentation and explicit public exports.
Tool Registration
tools/src/aden_tools/tools/__init__.py
Integrated Hacker News tool registration into the main tools module, making it available when include_unverified=True is passed to register_all_tools().
Exception Handling Refinements
tools/src/aden_tools/tools/news_tool/news_tool.py, tools/src/aden_tools/tools/openmeteo_tool/openmeteo_tool.py, tools/src/aden_tools/tools/web_search_tool/web_search_tool.py, tools/src/aden_tools/tools/wikipedia_tool/wikipedia_tool.py
Narrowed exception handling to catch only specific httpx errors (timeout and request failures); removed broad catch-all handlers to let unexpected exceptions propagate rather than masking them as generic error responses.
Test Coverage
tools/tests/tools/test_hackernews_tool.py
Comprehensive pytest fixtures and test cases for the Hacker News tool, including mocked API responses to validate successful story retrieval, timeout handling, comment inclusion, and error scenarios.
Configuration
.gitignore
Added progress/ directory to version control exclusions.

Poem

🐰 A tool hops in from Hacker News so grand,
Fetching tales with API calls so planned!
Exception handlers now precise and tight,
No more broad catches—just httpx right!
Testing hopped forward, complete and aware,
Quality code blooms everywhere! 🌿

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Feature/hackernews tool' is vague and uses a branch-naming convention rather than clearly describing the actual changes made. Rephrase the title to be more descriptive, such as 'Add HackerNews tool integration' or 'Introduce HackerNews API tool with story and comment fetching'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

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

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

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 (2)
tools/src/aden_tools/tools/hackernews_tool/README.md (1)

17-30: Document full parameter bounds and error shape for callers.

Please add that limit/comment_limit are clamped to a minimum of 1, and include the {"error": ...} response contract for failure cases.

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

In `@tools/src/aden_tools/tools/hackernews_tool/README.md` around lines 17 - 30,
Update the README documentation for get_top_hn_stories and get_hn_story_details
to explicitly state that the numeric parameters limit and comment_limit are
clamped to a minimum value of 1 (i.e., values below 1 are treated as 1) and
document any upper bounds if applicable; also add the failure response contract
showing that callers will receive a JSON object shaped like {"error": "..."} on
errors (include examples mentioning both parameter validation errors and
network/fetch failures) so callers know to check for an error field when parsing
responses.
tools/tests/tools/test_hackernews_tool.py (1)

40-119: Good baseline tests; add edge-case coverage for bounds and malformed payloads.

Consider adding cases for limit/comment_limit clamping and unexpected JSON shapes (e.g., non-list topstories, non-list kids) to lock in robustness behavior.

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

In `@tools/tests/tools/test_hackernews_tool.py` around lines 40 - 119, Add tests
that exercise bounds and malformed payload handling for top_stories_tool and
story_details_tool: create new test cases that (1) pass an excessively large and
zero/negative limit to top_stories_tool and verify the returned "stories" count
is clamped to expected min/max behavior, (2) mock the topstories endpoint to
return a non-list (e.g., dict or None) and assert the tool returns an error or
empty result per current behavior, (3) pass large and zero/negative
comment_limit to story_details_tool and verify comments are clamped, and (4)
mock story JSON where "kids" is non-list or missing and assert comments handling
doesn’t crash and returns appropriate empty/comments error; use the same
patch("httpx.Client.get") pattern and the existing MagicMock response setup as
in test_get_top_stories_success and test_get_story_details_success to construct
these edge-case responses while referencing top_stories_tool and
story_details_tool in your new tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tools/src/aden_tools/tools/hackernews_tool/hackernews_tool.py`:
- Around line 47-55: Validate API payload shapes before slicing or dict access:
check resp.status_code/resp.ok and ensure resp.json() returns a list before
doing story_ids = resp.json()[:limit] (guard story_ids variable), and for each
item request check s_resp.ok and that s_resp.json() returns a dict before using
data = s_resp.json() and data.get("type"). Update the logic around the
variables/identifiers story_ids, resp, s_resp, data and uses of HN_API_BASE to
safely handle non-list or non-dict JSON (return or log a graceful error when the
shape is wrong) so malformed upstream responses don't raise.

---

Nitpick comments:
In `@tools/src/aden_tools/tools/hackernews_tool/README.md`:
- Around line 17-30: Update the README documentation for get_top_hn_stories and
get_hn_story_details to explicitly state that the numeric parameters limit and
comment_limit are clamped to a minimum value of 1 (i.e., values below 1 are
treated as 1) and document any upper bounds if applicable; also add the failure
response contract showing that callers will receive a JSON object shaped like
{"error": "..."} on errors (include examples mentioning both parameter
validation errors and network/fetch failures) so callers know to check for an
error field when parsing responses.

In `@tools/tests/tools/test_hackernews_tool.py`:
- Around line 40-119: Add tests that exercise bounds and malformed payload
handling for top_stories_tool and story_details_tool: create new test cases that
(1) pass an excessively large and zero/negative limit to top_stories_tool and
verify the returned "stories" count is clamped to expected min/max behavior, (2)
mock the topstories endpoint to return a non-list (e.g., dict or None) and
assert the tool returns an error or empty result per current behavior, (3) pass
large and zero/negative comment_limit to story_details_tool and verify comments
are clamped, and (4) mock story JSON where "kids" is non-list or missing and
assert comments handling doesn’t crash and returns appropriate empty/comments
error; use the same patch("httpx.Client.get") pattern and the existing MagicMock
response setup as in test_get_top_stories_success and
test_get_story_details_success to construct these edge-case responses while
referencing top_stories_tool and story_details_tool in your new tests.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: cdfc4eba-9d8f-4708-899d-554e0f6ba60c

📥 Commits

Reviewing files that changed from the base of the PR and between c3c3075 and 70a63fa.

📒 Files selected for processing (10)
  • .gitignore
  • tools/src/aden_tools/tools/__init__.py
  • tools/src/aden_tools/tools/hackernews_tool/README.md
  • tools/src/aden_tools/tools/hackernews_tool/__init__.py
  • tools/src/aden_tools/tools/hackernews_tool/hackernews_tool.py
  • tools/src/aden_tools/tools/news_tool/news_tool.py
  • tools/src/aden_tools/tools/openmeteo_tool/openmeteo_tool.py
  • tools/src/aden_tools/tools/web_search_tool/web_search_tool.py
  • tools/src/aden_tools/tools/wikipedia_tool/wikipedia_tool.py
  • tools/tests/tools/test_hackernews_tool.py
💤 Files with no reviewable changes (2)
  • tools/src/aden_tools/tools/wikipedia_tool/wikipedia_tool.py
  • tools/src/aden_tools/tools/web_search_tool/web_search_tool.py

Comment on lines +47 to +55
story_ids = resp.json()[:limit]

stories = []
for sid in story_ids:
s_resp = client.get(f"{HN_API_BASE}/item/{sid}.json")
if s_resp.status_code == 200:
data = s_resp.json()
if data and data.get("type") == "story":
stories.append({
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Guard against unexpected API payload shapes before slicing or .get() access.

Current logic assumes top stories is always a list and item/comment payloads are always dicts. If upstream returns malformed/partial JSON, this can raise and bypass the graceful error responses.

🛠️ Proposed hardening patch
@@
-                story_ids = resp.json()[:limit]
+                topstories_payload = resp.json()
+                if not isinstance(topstories_payload, list):
+                    return {"error": "Unexpected HackerNews API response format for top stories."}
+                story_ids = topstories_payload[:limit]
@@
-                        data = s_resp.json()
-                        if data and data.get("type") == "story":
+                        data = s_resp.json()
+                        if isinstance(data, dict) and data.get("type") == "story":
@@
-                data = resp.json()
-
-                if not data or data.get("type") != "story":
+                data = resp.json()
+                if not isinstance(data, dict) or data.get("type") != "story":
                     return {"error": f"Story {story_id} not found or is not a story type."}
@@
-                if include_comments and "kids" in data:
-                    kid_ids = data["kids"][:comment_limit]
+                if include_comments:
+                    kid_ids = data.get("kids", [])
+                    if not isinstance(kid_ids, list):
+                        kid_ids = []
+                    kid_ids = kid_ids[:comment_limit]
                     for kid_id in kid_ids:
@@
-                            if c_data and c_data.get("type") == "comment" and not c_data.get("deleted"):
+                            if (
+                                isinstance(c_data, dict)
+                                and c_data.get("type") == "comment"
+                                and not c_data.get("deleted")
+                            ):
                                 comments.append({

Also applies to: 95-99, 113-119

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

In `@tools/src/aden_tools/tools/hackernews_tool/hackernews_tool.py` around lines
47 - 55, Validate API payload shapes before slicing or dict access: check
resp.status_code/resp.ok and ensure resp.json() returns a list before doing
story_ids = resp.json()[:limit] (guard story_ids variable), and for each item
request check s_resp.ok and that s_resp.json() returns a dict before using data
= s_resp.json() and data.get("type"). Update the logic around the
variables/identifiers story_ids, resp, s_resp, data and uses of HN_API_BASE to
safely handle non-list or non-dict JSON (return or log a graceful error when the
shape is wrong) so malformed upstream responses don't raise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-requirements-warning PR doesn't follow contribution guidelines. Please fix or it will be auto-closed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant