Skip to content

feat: search.open page reading via Jina Reader + top-10 search default - #112

Open
faresobeid wants to merge 2 commits into
mainfrom
feat/batched-search-open-webpage
Open

feat: search.open page reading via Jina Reader + top-10 search default#112
faresobeid wants to merge 2 commits into
mainfrom
feat/batched-search-open-webpage

Conversation

@faresobeid

@faresobeid faresobeid commented Jul 8, 2026

Copy link
Copy Markdown

Summary

Upgrades the built-in search skill for deep-research runs:

search: top-10 default

  • num is now sent explicitly in the Serper payload and the default is 10 results (was 5, sliced client-side from Serper's default page).

search.open: page reading on the same skill

  • The search skill now also exposes await search.open(url="..."), which fetches a URL and returns its text. When JINA_API_KEY is set, pages go through the Jina Reader API (markdown output, handles JS-rendered pages), falling back to a direct fetch on failure. Without a key it's a plain direct fetch: HTML parsed with BeautifulSoup/lxml (already in the base toolkit), PDFs with pdfminer.six (added to dependencies).
  • No new skill name: RLM_SKILLS=search enables both, so existing verifiers v1 configs need no changes — just export JINA_API_KEY (optional) alongside SERPER_API_KEY.

Mechanism

  • Built-in skill stubs now re-export the skill module's __all__ (from rlm.skills.search import *) instead of just run, so extra public functions ride along on the wrapped callable module (search.run, search.openawait search(...) shorthand unchanged).
  • The kernel's skill wrapper logs every public async function call (not just run) to programmatic_tool_calls.jsonl, so search.open calls count in tool-call metrics under the skill's name.
  • Prompt hint updated: fan out over angles with asyncio.gather(search(...), search(...)), read a promising result in full with search.open.

Validation

  • uv run pytest tests/ — 88 passed (includes the real-kernel skill tests exercising the wrapper change); ruff check + format clean.
  • Simulated the exact kernel wrap path (stub import *_CallableModule → logged functions): await search(...), await search.run(...), and await search.open(...) all work and all log under tool name search.
  • Live-tested search.open: HTML page, a real arXiv PDF (39.7k chars extracted), and the Jina→direct fallback with an invalid key.
  • Not live-tested (no API keys on the dev box): an authenticated Jina fetch and a real Serper response with num=10 — worth one real rollout before relying on them at scale.

🤖 Generated with Claude Code

…with Jina Reader

- search: accept a single query or a list batched into one Serper call;
  send num explicitly; default 10 results per query (was 5)
- new open_webpage built-in skill: Jina Reader API when JINA_API_KEY is
  set (markdown, JS-rendered pages), direct fetch with local HTML/PDF
  parsing (bs4/pdfminer) otherwise
- prompt hints for batched search and open_webpage; README + env table

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@faresobeid
faresobeid marked this pull request as ready for review July 8, 2026 02:46
Comment thread src/rlm/skills/open_webpage.py Outdated
headers={"Authorization": f"Bearer {api_key}", "X-Timeout": str(int(timeout))},
)
response.raise_for_status()
return response.text.strip()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Jina request drops URL query

Medium Severity

When JINA_API_KEY is set, _fetch_jina builds the Reader request as https://r.jina.ai/ plus the raw target URL. If the target includes a ? query string, HTTP parsing treats everything after the first ? as query parameters on r.jina.ai, not as part of the embedded page URL, so Jina may fetch the wrong resource or apply unintended Reader options while still returning 200.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit bbb518e. Configure here.

- search.run is single-query again (top-10 default kept, num sent explicitly)
- page reading is search.open on the same skill instead of a separate
  open_webpage built-in: Jina Reader when JINA_API_KEY is set, direct
  fetch (bs4 HTML / pdfminer PDF) otherwise
- built-in stubs re-export the skill module's __all__ so extra public
  functions ride along; kernel logs every public async function call
- prompt hint restores the asyncio.gather fan-out and teaches search.open

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@faresobeid faresobeid changed the title feat: batched search queries, top-10 default, and open_webpage skill with Jina Reader feat: search.open page reading via Jina Reader + top-10 search default Jul 8, 2026

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 2a25b0d. Configure here.

Comment thread src/rlm/skills/search.py
def _fetch_jina(url: str, api_key: str, timeout: float) -> str:
response = httpx.get(
f"{JINA_READER_URL}/{url}",
timeout=timeout,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Jina URL query mangling

Medium Severity

_fetch_jina builds the Reader GET URL by interpolating the target URL after https://r.jina.ai/. Characters such as ? and & in typical result links are treated as the Reader request’s own query string, so the page Jina fetches may omit query parameters. With JINA_API_KEY set, agents can get wrong or incomplete text without falling back to direct fetch.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 2a25b0d. Configure here.

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