Answers in LangChain
Two packages add Answers to LangChain: langchain-hyperresearch
on PyPI and @hyperresearch/langchain on npm. Both have the same three
classes:
| Class | Tool name | What it does |
|---|---|---|
HyperresearchAnswerTool |
hyperresearch_answer |
One factual question in, one short answer out, with the quotes it rests on, each checked word for word against its page. Returns not_found when nothing supports an answer. |
HyperresearchSearchTool |
hyperresearch_search |
Ranked raw sources from the open web and about 45 structured sources, with word-for-word passages. No summary. |
HyperresearchRetriever |
search as a retriever: one Document per ranked source. |
The research for an answer runs on our side, so the agent makes one tool call instead of a loop of searches, and no pages land in its context.
Packages: langchain-hyperresearch on PyPI
and @hyperresearch/langchain on npm.
Source: github.com/jordan-gibbs/hyperresearch-answers
(packages/). MIT licensed.
Install
Section titled “Install”pip install -U langchain-hyperresearch# oruv add langchain-hyperresearchThe package depends on langchain-core only. The agent example below also
needs langchain (pip install -U langchain).
npm install @hyperresearch/langchain @langchain/coreThe agent example below also needs langchain (npm install langchain).
API key
Section titled “API key”Create a key with the answers:ask scope on the
API keys page and put it in the
environment as HYPERRESEARCH_API_KEY:
export HYPERRESEARCH_API_KEY=hr_live_...Use an hr_live_ key. Answers has no fixture mode, so hr_test_ keys are
refused. Every account gets free credit to start; prices per call are on
Answers pricing. Keep the key out of anything you commit.
Example
Section titled “Example”from langchain.agents import create_agentfrom langchain_hyperresearch import HyperresearchAnswerTool, HyperresearchSearchTool
agent = create_agent( model="claude-sonnet-4-6", tools=[HyperresearchAnswerTool(), HyperresearchSearchTool()],)
agent.invoke( {"messages": [{"role": "user", "content": "What was the US federal deficit in fiscal 2025, with a source?"}]})Called directly:
answer = HyperresearchAnswerTool()answer.invoke({"question": "How old must a US senator be?", "mode": "fast"})Sync and async both work (invoke and ainvoke). The tools use
response_format="content_and_artifact": the model reads a compact JSON
string, and ToolMessage.artifact holds the full API response, including
balance_cents.
import { createAgent } from 'langchain';import { HyperresearchAnswerTool, HyperresearchSearchTool } from '@hyperresearch/langchain';
const agent = createAgent({ model: 'anthropic:claude-sonnet-4-6', tools: [new HyperresearchAnswerTool(), new HyperresearchSearchTool()],});
const res = await agent.invoke({ messages: [{ role: 'user', content: 'What was the US federal deficit in fiscal 2025, with a source?' }],});console.log(res.messages.at(-1)?.content);Called directly:
const answer = new HyperresearchAnswerTool();const result = await answer.invoke({ question: 'How old must a US senator be?', mode: 'fast' });console.log(JSON.parse(result));Both tools return a JSON string, so the model reads the answer, the quotes and the price.
An answer looks like this:
{ "id": "ans_01J...", "status": "answered", "answer": "At least 30 years old (US Constitution, Article I, Section 3).", "evidence": [ { "url": "https://www.archives.gov/founding-docs/constitution-transcript", "title": "The Constitution of the United States: A Transcription", "quote": "No Person shall be a Senator who shall not have attained to the Age of thirty Years", "check": "verified" } ], "price_cents": 5}status is one of answered, false_premise, unconfirmed, not_found or
error. Answers and passages are text from web pages. Treat them as data, not
as instructions.
Options
Section titled “Options”from langchain_hyperresearch import HyperresearchAnswerTool, HyperresearchSearchTool
answer = HyperresearchAnswerTool() # the model picks the modecheap = HyperresearchAnswerTool(mode="fast", max_cost_cents=5)search = HyperresearchSearchTool(max_results=5)| Parameter | Default | |
|---|---|---|
api_key |
HYPERRESEARCH_API_KEY |
|
mode |
the model’s choice, else standard |
Fix the mode. ask: fast, standard, max. search: standard, max. |
max_cost_cents |
none | Answer tool. Caps every call; a standard ask capped below its escalated price never escalates. |
max_results |
the model’s choice, else 10 | Search tool and retriever. 1 to 25. |
client |
a new client | Share one HyperresearchClient. It also takes base_url, ask_timeout (default 360 s), search_timeout (default 90 s) and max_retries (default 2). |
import { HyperresearchAnswerTool, HyperresearchSearchTool } from '@hyperresearch/langchain';
const answer = new HyperresearchAnswerTool(); // the model picks the modeconst cheap = new HyperresearchAnswerTool({ mode: 'fast', maxCostCents: 5 });const search = new HyperresearchSearchTool({ maxResults: 5 });| Field | Default | |
|---|---|---|
apiKey |
process.env.HYPERRESEARCH_API_KEY |
|
mode |
the model’s choice, else standard |
Fix the mode. ask: fast, standard, max. search: standard, max. |
maxCostCents |
none | Answer tool. Caps every call; a standard ask capped below its escalated price never escalates. |
maxResults |
the model’s choice, else 10 | Search tool and retriever. 1 to 25. |
client |
a new client | Share one HyperresearchClient. |
baseUrl, fetch, headers, maxRetries, askTimeoutMs, searchTimeoutMs |
Passed to the client. maxRetries defaults to 2, askTimeoutMs to six minutes, searchTimeoutMs to 90 seconds. |
Retriever
Section titled “Retriever”from langchain_hyperresearch import HyperresearchRetriever
retriever = HyperresearchRetriever(max_results=5)docs = retriever.invoke("minimum age to serve as a US senator")docs[0].page_content # the matched passages, verbatimdocs[0].metadata # url, title, rank, source, published, verified, call_idimport { HyperresearchRetriever } from '@hyperresearch/langchain';
const retriever = new HyperresearchRetriever({ maxResults: 5 });const docs = await retriever.invoke('minimum age to serve as a US senator');// docs[0].pageContent: the matched passages, verbatim// docs[0].metadata: { url, title, rank, source, published, verified, call_id }Each retrieval is one billed search call.
Long asks
Section titled “Long asks”A max ask can take a few minutes. The client sends
Prefer: respond-async; wait=50; if the answer is not ready by then, the API
answers 202 with the call’s id and status: "pending", and the client
collects it from GET /v1/answers/{id}?wait=45 until it finishes. The call is
charged once, when it finishes. The ask timeout (six minutes by default) bounds
the whole wait; past it, the Python client raises a client_timeout error
carrying the call id, and HyperresearchClient.get_call(id) fetches the
answer later.
Errors
Section titled “Errors”- Our failures come back as
200withstatus: "error"anderror.code: "engine_unavailable". They cost nothing. - Non-2xx responses are raised (Python) or thrown (JavaScript) as
HyperresearchError, carrying the status,type,code,message,param, request id and retry-after from the error envelope. 402 insufficient_balance: add credit in the console.402 wallet_frozen: write to support.409 idempotency_key_reuseoridempotency_in_flight: every call carries a freshIdempotency-Key, reused only on the client’s own retries, so these mean two callers shared one key.429(rate limit or too many calls running) and503 answers_capacityare retried up to the retry limit, waitingRetry-After. Neither is charged.
ask and search together are limited to 60 calls a minute per API key and
120 a minute per workspace. See rate limits.
Without LangChain
Section titled “Without LangChain”The classes call the Answers REST API: POST /v1/answers,
POST /v1/answers/search and GET /v1/answers/{id} on
https://api.hyperresearch.ai. Every field is in the
API reference. The same two tools are also
an MCP server at https://answers.hyperresearch.ai/mcp; see Answers.