harness_web/lib.rs
1//! Web access for prompts: a Plugin that gives a run two tools, one
2//! that fetches a page and one that searches the web.
3//!
4//! A Host registers [`Web`] in its Plugin registry. A prompt turns it
5//! on with one frontmatter line, `plugins: [promptforge/web]`. The
6//! run then gets both tools: `promptforge/web/fetch`, which fetches a URL
7//! and returns its content as text, and `promptforge/web/search`, which
8//! runs a search through the Host's [`SearchProvider`]. The two tools
9//! always come together.
10//!
11//! The Host also provides two services beside the Plugin. Its
12//! [`SearchProvider`] is registered under the key [`SEARCH_PROVIDER`]. The
13//! tokio runtime handle that every fetch is spawned onto is registered
14//! under the key [`TOKIO_RUNTIME`]. A run gets the web tools only when
15//! both services are registered.
16//!
17//! The fetch tool is security-critical. The model supplies the URL, so the
18//! tool is the server-side request forgery (SSRF) boundary between an
19//! untrusted argument and the network. A Host can replace the default
20//! fetch policy with a [`FetchConfig`] built by [`FetchConfigBuilder`].
21//! A configuration problem is reported as a [`ConfigError`].
22//!
23//! The fetch tool sends a GET request and chooses how to render the
24//! response from its `Content-Type`. For an HTML page, it extracts the
25//! main article with `readabilityrs` and renders it to markdown. When a
26//! page yields too little article text, `htmd` converts the whole page to
27//! markdown. Any other text body, such as JSON, XML, or plain text, is
28//! decoded and returned verbatim. The tool refuses every other type.
29//!
30//! The search tool validates the model's arguments into a [`SearchQuery`]
31//! and hands it to the provider. It returns the provider's
32//! [`SearchResults`] as compact JSON, marked untrusted. The JSON matches
33//! the Gateway's search output: an object with the `query` and a `results`
34//! array. Each result has a `title`, `url`, and `description`, plus `age`,
35//! `site_name`, and `extra_snippets` when present. The provider owns the
36//! transport and its deadline, so a search vendor's credential stays
37//! wherever the provider keeps it.
38//!
39//! ## Invariants
40//!
41//! - Every URL selected by the model or a tool, and every resolved
42//! address, is validated again on each redirect hop. A non-global
43//! address is denied unless the fetch policy grants an exact
44//! host-and-address exception.
45//! - No fetch includes an ambient identity on any hop. The client has no
46//! proxy, no cookie store, no automatic `Referer` header, and no default
47//! credentials.
48//! - Every fetch runs on the Host's runtime handle, and dropping the call
49//! aborts it.
50
51mod address;
52mod config;
53mod error;
54mod fetch;
55mod provider;
56mod redirect;
57mod resolver;
58mod response;
59mod search;
60#[cfg(test)]
61mod test_support;
62mod url_policy;
63mod web;
64
65pub use crate::config::{ConfigError, FetchConfig, FetchConfigBuilder};
66pub use crate::provider::{
67 Freshness, SafeSearch, SearchError, SearchErrorKind, SearchProvider, SearchQuery, SearchResult,
68 SearchResults,
69};
70pub use crate::web::{SEARCH_PROVIDER, TOKIO_RUNTIME, Web};