Repository navigation
feat(assistant): search the web and read pages, cited like excerpts - #472
Merged
Merged
Conversation
Importing app.domain.ai_tools on its own failed: it imported automations, which loads the actions, and the agent's action subclasses Toolbox before ai_tools had defined it. Running one test file (tests/api/test_chats.py) hit it. ai_tools now imports automations last. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXPWXcSCQb9hWPr7xkZu7B
An admin turns web search on in Settings > AI assistant > Web search (off by default). The assistant then gets web_search and web_read: it searches with DuckDuckGo (no key; the ddgs client is the optional `web` extra, fetched as a component when picked), the admin's SearXNG, Brave Search or Tavily, and reads pages and online PDFs through netguard, public addresses only. Results and pages are numbered and cited [n] like excerpts, with their site, and open in a new tab; conversations keep them. Each search and read is an activity ledger row (provider or host, never the query or page). Once an answer has read outside text, a search or page the person or a tool didn't give it waits for approval, and the approved call's result is reused. Docs, changelog and threat model updated; generated client regenerated. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXPWXcSCQb9hWPr7xkZu7B
The last check asked for 2026-10-17's note after the call without a date had made today's note, so on that day it found the note the deleted root had left behind. It now asks for a day no earlier call makes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXPWXcSCQb9hWPr7xkZu7B
…-r960xc-c5-web # Conflicts: # CHANGELOG.md # fastapi_backend/app/api/v1/routes/chats.py # nextjs-frontend/app/openapi-client/sdk.gen.ts # nextjs-frontend/openapi.json
# Conflicts: # CHANGELOG.md # threat-model.md # threat-model.yaml
adeelahmad
pushed a commit
that referenced
this pull request
Oct 17, 2026
C1 (#469), web search (#472) and the sandbox (#473) are in main. The routes keep C5's web pages in citations alongside the export, and the export test now checks a cited web page stays through access changes. The OpenAPI schema and client are regenerated with make openapi's two commands, and the threat model's prose_version is recomputed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXPWXcSCQb9hWPr7xkZu7B
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by Adeel · project thread
Description
Before: the assistant could only answer from what Lens holds. For anything else it had to say the archive doesn't cover it, or you had to capture a page into a namespace first (
import_urls).After: an admin turns on web search in Settings › AI assistant › Web search. It is off by default; one switch turns it on with DuckDuckGo, which needs no key. The assistant then gets two tools:
web_searchreturns titles, addresses, sites and snippets, with an optionaltime_rangeof day, week, month or year.web_readreads a page or an online PDF, withfindto keep only the paragraphs that matter.Results and pages are numbered and cited [n] like archive excerpts. A web chip shows the site (
example.org · Harbour news) and opens the page in a new tab, and the sources list shows a web card. A conversation keeps its web citations when it is opened again, and chat rooms list the page's address.Providers:
ddgs(MIT).Motivation and Context
Module C5 of the chat-gaps plan (web search tools in Adeel's list). The plan's contract section 3 covers it, mainly 3.4 (tools) and 3.5 (citations).
How it works:
documents.web_networks), on ports 80 and 443, and re-checks every redirect. A result's address or a redirect can't reach this machine's own services. Reads are capped at 10 MB and atweb.read_charsfor the model.web.renderon, a page that comes back nearly empty is loaded in Chromium and read again. Off by default, and only where Chromium is installed.web.search(provider, number of results) andweb.read(host) rows, never the query or the page. Brave and Tavily rows are marked as estimates.webextra in pyproject, about 11 MB of lxml and primp wheels, too heavy to be required. It is a component,web-search, fetched when an admin picks DuckDuckGo, like thesmbextra.uv.lockwas updated with uv.ci/validate_threat_model.pypasses.ai, web, decisions, voice), so there is no new section.get_chatkeeps both the conversation tree and web passages.Screenshots (if appropriate):
n/a (covered by the jest tests below)
Steps to reproduce (if appropriate):
Types of changes
!in the title)Checklist:
tests/api/test_web_search.pyhas 10 tests with a fake HTTP server and a fakeddgs, never the real internet;__tests__/chat-web-citations.test.tsx;__tests__/settings-web-search.test.tsx.docs/accordingly:docs/assistant.md: the new "Web search and reading pages" section, plus "Asks first";docs/configuration.md: theweb.*table;docs/activity.mdanddocs/components.md.## UnreleasedinCHANGELOG.md.Done questions (AGENTS.md)
PUT /api/v1/settings/webor through the setup chat'schange_settings, which always asks first forweb. MCP: n/a, because there is no MCP settings tool today..envedit and no prerequisite. DuckDuckGo's client is fetched as a component when it is picked.web.*settings are in the web app with defaults, and none is in the setup wizard.Passagefields are optional andrecording_idbecomes optional.mkdocs build --strictis clean.docs/assistant.md:Generated by Claude Code