Vectrum
Sign In
62 lines · 3.5 KB

Web search

The agent's knowledge of a library ends where its training did, and the two questions it cannot otherwise answer — what does this error message mean, and what is this API called now — are the ones a search box answers in seconds. The wizard's fourth question decides whether it gets one, and the honest default is no: every other capability here stays inside the working tree, and a search query is written by the model out of whatever the model has read.

web_searchWhat it doesWhat it costs you
nonenothing; the tools are not registered and the model is never told they exist—
claudedeclares Anthropic's hosted web_search_20250305 tool, which runs on their side of the wirebilled per search by Anthropic; needs an endpoint that offers it
customregisters web_search and web_fetch, which run herea search command on your PATH

claude is a line in the request's tool array and nothing else — no install, no key, no HTML parsing. The searches come back as server_tool_use and web_search_tool_result blocks, which the loop turns into ordinary WebSearch(...) transcript entries so a search is something you can watch rather than a pause you have to guess at. A hosted search cannot be refused at the prompt, because it happens inside a request you already approved; the setting itself is the consent. It also needs the endpoint to implement it, so a gateway or a local server speaking the Messages API will generally refuse the whole request — if that happens, switch to custom.

custom runs a command. The default is

ddgs text -q {{query}} -m {{count}} -nc

which needs the DuckDuckGo CLI (pipx install ddgs) and no account at all. {{query}} and {{count}} are substituted as whole argv elements and the command is run without a shell, so a query containing ; or backticks is a query rather than a second command.

Note the absence of -o json, which is the flag you would reach for and the wrong one: it does not print JSON, it writes a file — into whatever directory the agent happens to be working in, once per search. The plain listing goes to stdout and is parsed, and -nc keeps the colour codes out of the titles.

Any tool will do, as long as it prints to stdout: a JSON array, one JSON object per line, a {"results": […]} wrapper, or ddgs's own aligned listing are all read. Titles may be title; links href, url or link; snippets body, snippet, description or abstract. Edit the command in the wizard, or set search_command in the config.

web_fetch is the other half, because a snippet is enough to choose a link and never enough to write code against. It resolves the host and refuses loopback, private, link-local and unique-local addresses, on the original URL and on every redirect hop — the model invents these URLs, and 169.254.169.254 is a cloud metadata endpoint. Pages come back as text, capped head and tail like bash output, wrapped in markers that say to treat what is between them as data rather than instructions. That does not make prompt injection impossible; it makes it visible in the transcript, which is the most a fetch tool can honestly offer.

Both tools prompt, and neither is in the read-only set: they read nothing local and send the model's words off the machine, which is the opposite of what that set is for. The query and the URL are the detail on the prompt, so what is leaving is on screen before it leaves. "Always this tool" is the answer most people give once.