Verify a Model Answer Against Live Sources
Take a claim your model produced, check it against live sources with /research, and return a verdict plus the pages behind it. Shows how to read claim-level citations off the complete event.
A model states something with total confidence and no way for you to check it. This example takes that claim, researches it against live sources, and returns the answer alongside the pages that support it, so a person or a downstream step can judge it.
This example uses balanced mode, which requires a paid plan.
The pattern is deliberately narrow. Tabstack does not label a claim true or false. It gives you a current, sourced answer to compare against, and the claims each source was cited for.
import Tabstack from "@tabstack/sdk";
const client = new Tabstack();
type Evidence = { claim: string; finding: string; sources: { url: string; title: string | null; supports: string[] }[];};
async function gatherEvidence(claim: string): Promise<Evidence> { const stream = await client.agent.research({ // Ask for the current state of the world, not for a true/false verdict. query: `What do current sources say about this claim? Claim: "${claim}"`, // balanced populates each source's claims; fast returns them empty. mode: "balanced", // A claim worth checking is usually a claim about something that changed. nocache: true, });
for await (const event of stream) { if (event.event === "error") { throw new Error(event.data.error?.message ?? "Research failed"); }
if (event.event === "complete") { const cited = event.data.metadata.citedPages ?? [];
return { claim, finding: event.data.report, sources: cited.map((page) => ({ url: page.url, title: page.title ?? null, // The specific claims this source was cited for. supports: page.claims ?? [], })), }; } }
throw new Error("Stream ended before the complete event");}
const evidence = await gatherEvidence( "Node.js 24 is the current long-term support release.",);
console.log("Claim: ", evidence.claim);console.log("Finding: ", evidence.finding);
if (evidence.sources.length === 0) { // No citations is a result too: treat it as unverified, not as confirmation. console.log("Verdict: unverified, no sources cited");} else { console.log(`Verdict: ${evidence.sources.length} source(s) cited`); for (const source of evidence.sources) { console.log(`- ${source.title ?? "(untitled)"}: ${source.url}`); for (const supported of source.supports) { console.log(` supports: ${supported}`); } }}from tabstack import Tabstack
client = Tabstack()
def gather_evidence(claim: str) -> dict: stream = client.agent.research( # Ask for the current state of the world, not for a true/false verdict. query=f'What do current sources say about this claim? Claim: "{claim}"', # balanced populates each source's claims; fast returns them empty. mode="balanced", # A claim worth checking is usually a claim about something that changed. nocache=True, )
for event in stream: if event.event == "error": message = event.data.error.message if event.data.error else "Research failed" raise RuntimeError(message)
if event.event == "complete": cited = event.data.metadata.cited_pages or []
return { "claim": claim, "finding": event.data.report, "sources": [ { "url": page.url, "title": page.title, # The specific claims this source was cited for. "supports": page.claims or [], } for page in cited ], }
raise RuntimeError("Stream ended before the complete event")
evidence = gather_evidence("Node.js 24 is the current long-term support release.")
print("Claim: ", evidence["claim"])print("Finding: ", evidence["finding"])
if not evidence["sources"]: # No citations is a result too: treat it as unverified, not as confirmation. print("Verdict: unverified, no sources cited")else: print(f"Verdict: {len(evidence['sources'])} source(s) cited") for source in evidence["sources"]: print(f"- {source['title'] or '(untitled)'}: {source['url']}") for supported in source["supports"]: print(f" supports: {supported}")How it works
Section titled “How it works”- Ask what sources say, not whether the claim is true. Phrasing the query as a verdict request invites a confident yes or no. Phrasing it as “what do current sources say” returns something you can compare against, with pages attached.
claimsis the useful field, and it needsbalancedmode. Inbalancedmode each entry incitedPages(cited_pagesin Python) carries the claims that source was cited for, so you can show a reviewer the specific sentence a URL backs rather than a bare link list. Infastmodeclaimsis an empty array.balancedrequires a paid plan.- Treat an empty citation list as unverified.
citedPagesis optional and can be absent. That is not evidence the claim is right; it means you have no sources and should say so. Read the optional fields defensively, as Autonomous Research describes. nocache: trueis the right default here. Anything worth fact-checking is usually something that changed recently, and the content cache is keyed by URL, effort, and region rather than by account.
Where to use it
Section titled “Where to use it”- Before shipping model output to users, on the small set of claims that matter: prices, versions, dates, availability.
- In an evaluation harness, to sample answers and flag the ones with no supporting sources.
- In review workflows, where the output is a claim plus its sources for a human to sign off.
For a fuller research walkthrough, see the Technical Landscape Researcher. For the endpoint reference, see Autonomous Research.
Installation
Section titled “Installation”npm install @tabstack/sdkpip install tabstackSet your API key before running:
export TABSTACK_API_KEY=your_api_key