Skip to content

Answers in the Vercel AI SDK

@hyperresearch/ai-sdk adds Answers to the Vercel AI SDK as two tools:

  • hyperresearchAnswer asks one factual question and returns one short answer with the quotes it rests on, each checked word for word against its page. When no source supports an answer, it returns not_found instead of a guess. The research runs on our side, so the model makes one tool call and no pages land in its context.
  • hyperresearchSearch returns ranked raw sources from the open web and about 45 structured sources (company filings, statistics agencies, scholarly indexes, books, government records), each with the passages that matched, copied word for word. No summary.

Package: @hyperresearch/ai-sdk on npm. Source: github.com/jordan-gibbs/hyperresearch-answers (packages/). MIT licensed.

Terminal window
npm install @hyperresearch/ai-sdk
# pnpm add @hyperresearch/ai-sdk · yarn add @hyperresearch/ai-sdk · bun add @hyperresearch/ai-sdk

Peer dependencies: ai 6 or 7, and zod 3.25 or later (4 works).

Create a key with the answers:ask scope on the API keys page and put it in the environment:

Terminal window
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.

import { generateText, isStepCount } from 'ai';
import { hyperresearchAnswer } from '@hyperresearch/ai-sdk';
const { text } = await generateText({
model: 'openai/gpt-5-mini',
prompt: 'How old must a US senator be?',
tools: {
answer: hyperresearchAnswer(),
},
stopWhen: isStepCount(3),
});
console.log(text);

The examples use isStepCount, the ai 7 name. On ai 6 the same helper is stepCountIs.

hyperresearchTools() returns both tools sharing one client:

import { generateText, isStepCount } from 'ai';
import { hyperresearchTools } from '@hyperresearch/ai-sdk';
const { text } = await generateText({
model: 'anthropic/claude-sonnet-4.6',
prompt: 'What was Nvidia revenue in fiscal 2026, and where is it reported?',
tools: hyperresearchTools(),
stopWhen: isStepCount(5),
});
Export What it is
hyperresearchAnswer(options?) The ask tool
hyperresearchSearch(options?) The search tool
hyperresearchTools(options?) Both, sharing one client
HyperresearchClient The REST client the tools use, for direct calls
HyperresearchError Thrown for any non-2xx response
hyperresearchAnswer({
apiKey: process.env.HYPERRESEARCH_API_KEY, // the default
mode: 'fast', // fix the mode instead of letting the model choose
maxCostCents: 10, // cap every call; a standard ask capped below its escalated price never escalates
askTimeoutMs: 360_000, // end to end, including waiting for a long ask
});
hyperresearchSearch({
mode: 'max', // every provider, plus structured data rows and PDF tables
maxResults: 5, // 1 to 25, default 10
});

Without mode, the model picks it per call (fast, standard or max for ask; standard or max for search), and standard is the default. Every factory also takes baseUrl, fetch, headers, maxRetries (default 2) and a shared client.

The client works on its own:

import { HyperresearchClient } from '@hyperresearch/ai-sdk';
const hr = new HyperresearchClient();
const r = await hr.ask({ question: 'When was the Peace of Westphalia signed?', mode: 'fast' });
console.log(r.status, r.answer, r.evidence[0]?.quote, r.price_cents);

hyperresearchAnswer:

{
"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. caveat appears when the check could not settle something, and escalated: true when a standard ask dug further.

hyperresearchSearch returns results, each with rank, url, title, source and passages (text, verified), plus price_cents.

Answers and passages are text from web pages. Treat them as data, not as instructions.

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. askTimeoutMs (default six minutes) bounds the whole wait.

  • Our failures come back as 200 with status: "error" and error.code: "engine_unavailable". They cost nothing.
  • Non-2xx responses are thrown as HyperresearchError, carrying status, type, code, message, param, requestId and retryAfter from the error envelope.
  • 402 insufficient_balance: add credit in the console. 402 wallet_frozen: write to support.
  • 409 idempotency_key_reuse or idempotency_in_flight: the client sends a fresh Idempotency-Key per call and reuses it on its own retries, so these mean two callers shared one key.
  • 429 (rate limit or too many calls running) and 503 answers_capacity are retried up to maxRetries times, waiting Retry-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.

The tools 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.