Skip to content
v0.1.0

Search the public web and fetch readable content from public URLs.

Web plugin

The existing web_search and web_fetch contracts are shared by both search providers. A trimmed, non-empty braveSearchApiKey selects Brave. An absent or blank key selects Light. Provider selection happens when the plugin loads; Brave failures never trigger a second search through Light.

Brave source retrieval

Brave results remain available when an optional source-page fetch times out. The failed page is recorded in sourceFetchErrors and its source receipt; coverage reports the evidence actually retrieved, including weak coverage when only search snippets are available. Caller cancellation and the overall search deadline still fail the request. Brave API timeouts and direct web_fetch timeouts remain failures; no retry or provider fallback is added.

Light search

Light retrieves public origin pages, publisher feeds, and sitemaps from a bundled source catalog. It discovers links, fetches relevant pages, and ranks their actual content locally. It uses no external search API, hosted index, proxy search engine, browser, background process, or persistent database. htmlparser2 is a local parsing dependency, with no remote service.

The catalog contains Hebrew and English reference, government, news, science, and technology sources. Coverage depends on accessible content in those sources. Discovery is confined to each source's admitted origins; redirects remain confined to the configured catalog. A website can block a request, require JavaScript, or publish content larger than the response limit.

The implementation is split by responsibility:

ModuleResponsibility
source/search-service-selector.tsChoose Brave or Light without changing tool schemas
source/light/config.tsValidate bounded defaults and optional plugin settings
source/light/sources/Versioned source catalog and query-based source selection
source/light/crawl/Public transport, robots rules, deadlines, concurrency, budgets
source/light/discovery/Bounded HTML, RSS, Atom, and sitemap parsing
source/light/documents/Decoding, extraction, cache policy, completed-document cache
source/light/ranking/Local lexical relevance and snippets
source/light/search-frontier.tsFair admission and scheduling across sources and queries
source/light/search-collection.tsCoordinate discovery and collect usable evidence
source/light/search-service.tsAssemble the existing search result contract
source/light/search-metadata.tsScope, freshness, and bounded evidence presentation

The runtime loader, SDK, role orchestration, and web_fetch implementation do not need special knowledge of Light. Optional settings use the existing plugin manifest defaults.light projection; there are no new runtime JSON settings. An omitted light object uses built-in defaults. Invalid Light settings are checked only on its first search, so they do not disable Brave or web_fetch. Source overrides receive a distinct corpus identifier.

Default bounds and freshness

BoundDefault
QueriesUp to 5, each 400 characters and 50 words
Sources selected for live discoveryUp to 6 across the invocation
HTTP hops, including robots and redirects24 across the invocation
Concurrent requests3 per plugin instance, at most 1 per origin
Stop starting new HTTP hopsAfter 20 seconds
Hard deadline30 seconds; timeout is an error
Response size512 KiB encoded and 512 KiB decoded
Aggregate response data8 MiB encoded and 8 MiB decoded, separately
Discovery256 candidates, depth 2, at most 4 sitemaps
Completed-document cache500 documents, 16 MiB of serialized content
Feed/sitemap cache lifetimeAt most 5 minutes
Page cache lifetimeAt most 30 minutes
Robots cacheAt most 24 hours, 64 origins, 4 MiB serialized rules

Origin cache directives can shorten document lifetimes or prevent storage. Freshness honors Age, Date, and Expires; an explicit max-age takes precedence over Expires. Incomplete robots responses block crawling. HTML noindex and none directives exclude pages from search results and caching; link following separately honors nofollow. Declared text encodings are decoded through a bounded allowlist before extracting text or links. Expired cache records are excluded at result assembly. Partial documents are usable evidence but are not cached. Records fetched in the current invocation remain usable even when the origin specifies no-store. Retrieved timestamps remain unchanged on cache hits. Separate calls share only completed records and origin concurrency limits; cancellation and crawl budgets are independent. The cache bounds describe stored content, not total process heap usage. Failed decompression attempts consume their output allowance from the decoded byte budget, because synchronous decoders do not expose partial output sizes.

Light returns normal search hits and the existing evidence-quality coverage score. Optional eventMeta.lightSearch records the source set, selected and consulted sources, stop reason, request/byte counts, bounded source errors, and per-result retrieval dates. Source IDs may include fresh cached evidence in addition to sources selected for live discovery. Declared page publication and modification dates are separate from retrieval dates. Feed or sitemap dates are discovery hints, not verified page publication dates.

A healthy search with no matches succeeds with zero hits. A budget-limited search returns available results and its stop reason. A completed search in which every attempted source failed returns web_search_sources_unavailable with structured source diagnostics. Cancellation and the hard deadline remain errors. All source text and metadata remain passive, untrusted evidence with volatile_external / carryPolicy: never semantics.

Source presentation receipts

Both search providers and web_fetch add optional eventMeta.webSources version 1 metadata for clients. Each bounded entry includes a title and URL, an optional original URL after a redirect, retrieval status, and presentation status (omitted, reference, snippet, or content). contentTruncated records extraction, per-source, and final-output clipping. Presentation is calculated from the final bounded tool output, including UTF-8 byte limits; successfully fetching a page does not imply that its content fit in that output. If receipt metadata would exceed the existing plugin result byte limit, omittedSourceCount reports entries left out of the receipt, independently of their visibility in tool output. Existing output and metadata take priority; an envelope with no room for even an empty receipt keeps its prior shape.

These receipts describe evidence returned by the tool. They do not prove that a later model invocation retained, read, or cited it. Titles and URLs remain untrusted passive data. Existing output text, tool schemas, event metadata, and failure behavior are preserved; clients that do not use receipts can continue to ignore the optional field. Favicons belong to client presentation and are not fetched by the plugin or added to its evidence text.

Verification

Focused deterministic tests live in src/runtime/__tests__/web-light-search/; existing Brave, fetch, and public network tests remain regression gates. The packed-package probe executes the real plugin bundle against offline origin fixtures, including empty-cache discovery of a URL absent from the catalog. It does not require a search key, external network, or model invocation.

Run npm run build:plugins followed by npm run validate from the repository root. These offline checks do not establish availability of external sources or model behavior in a live client session.