Search, read, answer
Search the web, open the top results in a sandboxed browser, and answer the question from those pages with their addresses as sources.
When to use it: A question needs a fresh answer from the web, with its sources.
| Uses | search with fetch: 3 (the top pages as Markdown), extract with several urls and a schema |
|---|---|
| Needs | a plan with web search (Free: 100 searches a month) and a model on the API |
| Site | whatever the search finds; the query goes to the search provider (Brave), so keep personal data out of it |
| Output | output/result.json: the results, the answer and its sources |
| Languages | Node and Python |
The code
The example as it is in its folder. Both versions do the same job and write the same output/, so one result check covers both.
/** * Search, read, answer: search the web, read the top results in a sandboxed browser, and answer with sources. * * npx tsx node/index.ts (BOXLINE_API_KEY; QUESTION for your own question) * * Writes output/result.json: the search results, the answer and the pages it came from. */import { mkdirSync, writeFileSync } from "node:fs";import { join } from "node:path";import { Boxline } from "@boxline/sdk";const out = process.env.OUTPUT_DIR ?? "output";const question = process.env.QUESTION ?? "In what year was the Python programming language first released?";const bx = new Boxline();// 1. Search, and open the top 3 results as Markdown (in a real browser inside a sandbox, never on this computer).// The query goes to the search provider: keep passwords and personal data out of it.const found = await bx.search({ query: question, limit: 5, fetch: 3 });console.log(`${found.results.length} results${found.cached ? " (from the cache)" : ""}:`);for (const r of found.results) console.log(` ${r.content ? "read" : " "} ${r.title} (${r.url})${r.error ? ` (${r.error.code})` : ""}`);// 2. Answer from the pages that loaded, with a schema so the answer and its sources come back as data.const read = found.results.filter((r) => r.content).map((r) => r.url);if (!read.length) throw new Error("none of the top results could be opened; try another question");const answer = await bx.extract<{ answer: string; sources: string[] }>({ urls: read, prompt: `Answer this question in one or two sentences, using only these pages: "${question}". In "sources", list the URLs of the pages the answer comes from.`, schema: { type: "object", properties: { answer: { type: "string" }, sources: { type: "array", items: { type: "string" } } }, required: ["answer", "sources"], },});console.log(`\n${answer.data.answer}\nSources:\n${answer.data.sources.map((s) => ` - ${s}`).join("\n")}`);mkdirSync(out, { recursive: true });writeFileSync( join(out, "result.json"), JSON.stringify( { question, results: found.results.map((r) => ({ title: r.title, url: r.url, read: Boolean(r.content) })), answer: answer.data.answer, sources: answer.data.sources, model: answer.model, usage: { modelUsd: answer.usage.costUsd, searches: found.cached ? 0 : 1 }, }, null, 2, ),);"""Search, read, answer: search the web, read the top results in a sandboxed browser, and answer with sources. python python/main.py (BOXLINE_API_KEY; QUESTION for your own question)Writes output/result.json: the search results, the answer and the pages it came from."""import jsonimport osfrom pathlib import Pathfrom boxline import Boxlineout = Path(os.environ.get("OUTPUT_DIR", "output"))question = os.environ.get("QUESTION", "In what year was the Python programming language first released?")bx = Boxline()# 1. Search, and open the top 3 results as Markdown (in a real browser inside a sandbox, never on this computer).# The query goes to the search provider: keep passwords and personal data out of it.found = bx.search(question, limit=5, fetch=3)print(f"{len(found['results'])} results{' (from the cache)' if found['cached'] else ''}:")for r in found["results"]: error = f" ({r['error']['code']})" if r.get("error") else "" print(f" {'read' if r.get('content') else ' '} {r['title']} ({r['url']}){error}")# 2. Answer from the pages that loaded, with a schema so the answer and its sources come back as data.read = [r["url"] for r in found["results"] if r.get("content")]if not read: raise SystemExit("none of the top results could be opened; try another question")answer = bx.extract( urls=read, prompt=f'Answer this question in one or two sentences, using only these pages: "{question}". ' 'In "sources", list the URLs of the pages the answer comes from.', schema={ "type": "object", "properties": {"answer": {"type": "string"}, "sources": {"type": "array", "items": {"type": "string"}}}, "required": ["answer", "sources"], },)data = answer["data"]print(f"\n{data['answer']}\nSources:")for s in data["sources"]: print(f" - {s}")out.mkdir(parents=True, exist_ok=True)result = { "question": question, "results": [{"title": r["title"], "url": r["url"], "read": bool(r.get("content"))} for r in found["results"]], "answer": data["answer"], "sources": data["sources"], "model": answer["model"], "usage": {"modelUsd": answer["usage"]["costUsd"], "searches": 0 if found["cached"] else 1},}(out / "result.json").write_text(json.dumps(result, indent=2, ensure_ascii=False))Inputs
Environment variables the example reads:
QUESTION: your question (defaultIn what year was the Python programming language first released?).
Run it
Get the examples with git clone https://github.com/Boxline-dev/examples.git and open this one: cd examples/search-read-answer. Put your API key in BOXLINE_API_KEY (and BOXLINE_API_URL for another API), then run either version from the example’s folder. Both write to output/ and stop their sessions when they finish.
# Node 18 or newer, in the example's folderexport BOXLINE_API_KEY=… # your API keynpm install @boxline/sdk tsxnpx tsx node/index.ts# Python 3.9 or newer, in the example's folderexport BOXLINE_API_KEY=… # your API keypip install boxline-sdkpython python/main.pyThen check the result, from the same folder: npx tsx check.ts output. It exits with 0 only when the result is right.
What its check proves
check.ts reads what the example wrote and passes only when the result is right, not merely when the example ran.
There are at least 3 results, the answer is there (for the default question: 1991), and every source is one of the pages that were read.
Source
github.com/Boxline-dev/examples/search-read-answer on GitHub, with its README.md, check.ts and .env.example. The examples are open source. See all examples.
These docs describe a beta API. Endpoints, fields and SDK methods may change before general availability; breaking changes will be listed in the changelog.