Skip to content

feat: add web_search and web_fetch tools - #2

Open
dpavlin wants to merge 19 commits into
citrolabs:mainfrom
dpavlin:web-fetch-search
Open

feat: add web_search and web_fetch tools#2
dpavlin wants to merge 19 commits into
citrolabs:mainfrom
dpavlin:web-fetch-search

Conversation

@dpavlin

@dpavlin dpavlin commented Jul 20, 2026

Copy link
Copy Markdown

Summary

Port web search and fetch functionality from ds4 WebFetch to CDP. Adds two new Pi agent tools registered through a dedicated extension.

New Tools

  • web_search: Google search via Chrome with consent dialog handling, up to 20 visible result links and text snapshot as markdown
  • web_fetch: URL page fetch with dynamic scrolling, semantic HTML extraction (headings, paragraphs, lists, code, blockquotes), up to 80 links, 900KB truncation

Both tools share Chrome profile for session continuity and use profileDir to reuse an existing Chrome session.

Files Changed

  • src/web-fetch.ts: core web fetch/search logic (418 lines)
  • extensions/browser-execute-web.ts: Pi extension adapter (142 lines)
  • test/web-fetch.test.ts: 20 unit tests
  • test/browser-execute-web.test.ts: 9 integration tests
  • README.md + README.zh-CN.md: documentation updates
  • package.json: extension registration
  • src/cdp/session.ts: minor type fix

Tests

  • 59/60 tests pass (1 pre-existing failure unrelated to this work)
  • Typecheck clean

dpavlin added 19 commits July 11, 2026 12:19
When DevToolsActivePort is absent (Chrome started with --remote-debugging-port=9333),
probe common fixed ports via /json/version to discover running instances.
This makes session.connect() auto-detect existing browsers without manual wsUrl.
Port web search and fetch functionality from ds4 WebFetch to CDP.
Adds two new Pi agent tools registered through a dedicated extension:

- web_search: Google search via Chrome with consent dialog handling,
  up to 20 visible result links and text snapshot as markdown
- web_fetch: URL page fetch with dynamic scrolling, semantic HTML
  extraction (headings, paragraphs, lists, code, blockquotes),
  up to 80 links, 900KB truncation

Both tools share Chrome profile for session continuity and use
profileDir to reuse an existing Chrome session.

Includes:
- src/web-fetch.ts: core web fetch/search logic (418 lines)
- extensions/browser-execute-web.ts: Pi extension adapter (142 lines)
- test/web-fetch.test.ts: 20 unit tests
- test/browser-execute-web.test.ts: 9 integration tests
- Updated README (EN + ZH), package.json, minor type fix in session.ts

59/60 tests pass (1 pre-existing failure: Chrome-on-port-9333)
… curl

Make tool descriptions explicitly tell the LLM to prefer these tools
over curl for web searches and page fetching. Add stronger guidance
in promptGuidelines to use web_search/web_fetch instead of curl.
Change Target.createTarget from background: true to background: false
so the user can see Chrome navigating during web search and fetch
operations, matching the 'visible Chrome' design goal.
The promptSnippet was changed from 'Chrome' to 'curl' to emphasize
the tool is a curl replacement. Update test accordingly.
Integration tests connect to Chrome on port 9333, navigate to pages,
extract content, and leave tabs visible for 15 seconds so the user
can visually verify tabs actually open during web_search/web_fetch.
The web_search and web_fetch tools now keep the Chrome tab visible for
15 seconds after extracting content, so the user can see what the
extension did. The default is 15 seconds but can be configured via the
keepTabVisibleMs option.

Unit tests pass keepTabVisibleMs: 0 to avoid artificial delays.
- Update ensureConnected() to call session.connect() when profileDir is
  not provided, allowing detectBrowsers to find Chrome on common ports.
- Fix whitespace-only query validation in webSearch.
- Update tests to mock Session.connect for error cases to avoid
  connecting to real Chrome during unit tests.

This ensures Chrome tabs open and stay visible for 15 seconds after
extraction, even when profileDir is not explicitly provided.
The pi extension loader requires explicit file extensions in the manifest.
Added .ts to browser-execute and browser-execute-web paths.
Add onProgress callback to web_search and web_fetch tools so the agent
session can display status updates (query URL, navigating, extracting)
to the user in real-time. This helps distinguish multiple concurrent
browser calls in the tool execution log.
Add custom renderCall functions to web_search and web_fetch tools so the
URL/query appears inline with the tool name in the agent UI, similar to
how bash shows '$ command' inline. This helps distinguish multiple
concurrent browser calls in the tool execution log.
Previously runPage() awaited a 15-second delay before closing the tab,
blocking the entire tool call and preventing the pi agent from continuing
to the next step. Now the tab closes in the background via setTimeout,
so the tool returns immediately after content extraction. The Chrome tab
stays visible for the full duration so the user can still see what
happened, but the agent can proceed without waiting.
@section9-lab

section9-lab commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Thank you again for the continued work here. I really appreciate the energy and the concrete implementation. The idea of making Chrome-backed fetch/search visible to the user is interesting, and several infrastructure pieces here could be valuable for the project.

I did a first pass review and also tested the branch in a temporary worktree.

Validation results:

  • npm run typecheck passes.
  • npm test currently fails because the new integration tests require Chrome to be running at 127.0.0.1:9333.
  • GitHub reports this PR as conflicting with current main, mostly because the project has since been renamed to pi-chrome-use and the release workflow/package metadata changed.

Main blockers before this can be merged:

  1. Please rebase on current main and keep the current package metadata: pi-chrome-use, citrolabs/pi-chrome-use, current image URL, and current release workflow.
  2. Please make real-Chrome integration tests opt-in, for example behind RUN_CHROME_INTEGRATION=1. The default npm test must pass on a clean machine and in CI without a local Chrome debug port.
  3. Please split the PR. The fixed-port/browser reuse work is much easier to review and likely fits the core package. The user-facing web_search / web_fetch tools are a larger product decision and should be separate.
  4. Please avoid changing browser_execute error semantics from thrown tool failures into successful text responses. That is a behavior change for existing users and needs a separate discussion.
  5. Please check resource lifecycle in web_search / web_fetch. They create new Session instances and should make sure WebSocket/browser resources are closed or intentionally reused.
  6. Please remove unused imports and local-only/debug files before resubmitting.

For the user-facing web_search / web_fetch feature direction: I want to be transparent that I personally will not have time over the next two weeks to take ownership of that feature work. I am still happy to help review, test, and merge smaller focused PRs, especially the CDP detection/reuse improvements. If you want to continue with this, the fastest path is probably:

  • PR A: fixed-port CDP detection only
  • PR B: optional Chrome auto-launch/reuse behavior
  • PR C: web_fetch/web_search as an optional extension, after the API shape is agreed

Thanks again. This is useful work; I just want to keep the merge path small and safe for existing users.

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