Technical Landscape Researcher
Turn a single question into a cited, multi-source report with /research. Shows streaming progress, fast vs balanced mode, and how to read the cited sources off the complete event.
Ask a question, get back a synthesized report with citations. This example wraps /research into a small function that streams progress while the agent works, then prints the finished report and the list of sources it cited. It’s a focused demonstration of the endpoint itself: one question in, multi-source cited synthesis out, with no orchestration code of your own. For a larger agent that combines research with structured extraction, see the Competitor Briefing Agent.
import Tabstack from "@tabstack/sdk";
const client = new Tabstack();
type Source = { title: string; url: string };
async function researchTopic(query: string) { const stream = await client.agent.research({ query, mode: "fast", // "balanced" runs a deeper, multi-source pass (requires a paid plan) });
let report: string | null = null; const sources: Source[] = [];
for await (const event of stream) { switch (event.event) { case "iteration:start": // Show progress as the agent runs its search loop. process.stdout.write( `\r[researching: iteration ${event.data.iteration}/${event.data.maxIterations}]`, ); break; case "complete": report = event.data.report; for (const page of event.data.metadata.citedPages ?? []) { sources.push({ title: page.title ?? "(untitled)", url: page.url }); } break; case "error": // Task-level failures arrive inside the stream, not as an HTTP error. throw new Error(event.data.error?.message ?? "research failed"); } }
console.log("\n\n" + (report ?? "(no report returned)")); console.log(`\nCited ${sources.length} sources:`); for (const source of sources) { console.log(`- ${source.title}: ${source.url}`); }
return { report, sources };}
researchTopic( "What are the main approaches to cloud browser automation for AI agents, and how do they differ?",);import osfrom tabstack import Tabstack
client = Tabstack(api_key=os.environ["TABSTACK_API_KEY"])
def research_topic(query: str): report = None sources = []
for event in client.agent.research( query=query, mode="fast", # "balanced" runs a deeper, multi-source pass (requires a paid plan) ): if event.event == "iteration:start": # Show progress as the agent runs its search loop. print( f"[researching: iteration {event.data.iteration}/{event.data.max_iterations}]" ) elif event.event == "complete": report = event.data.report for page in event.data.metadata.cited_pages or []: sources.append( {"title": page.title or "(untitled)", "url": page.url} ) elif event.event == "error": # Task-level failures arrive inside the stream, not as an HTTP error. message = getattr(event.data.error, "message", None) or "research failed" raise RuntimeError(message)
print("\n" + (report or "(no report returned)")) print(f"\nCited {len(sources)} sources:") for source in sources: print(f"- {source['title']}: {source['url']}")
return {"report": report, "sources": sources}
research_topic( "What are the main approaches to cloud browser automation for AI agents, and how do they differ?")How it works
Section titled “How it works”- One call, full pipeline.
client.agent.research(...)handles source selection, fetching, reading, and synthesis. You pass a question and consume a stream; there is no search, ranking, or citation code to write. - Stream progress as it runs. A research run can take from seconds to minutes. Switching on
iteration:startgives you a live “iteration N of M” indicator. The full set of progress events (planning:*,searching:*,writing:*, and more on balanced mode) is documented in Autonomous Research. - The report and citations arrive on
complete.event.data.reportis the synthesized report as a markdown string, andevent.data.metadata.citedPages(cited_pagesin Python) lists every source the report drew on. Treat a missing value as an empty list. - Always handle
error. A failed run delivers anerrorevent inside the stream, not an HTTP error. If you only listen forcomplete, a failure produces no output.
Choosing a mode
Section titled “Choosing a mode”fast is the default and is right for most questions. balanced consults more sources and runs a deeper pass, at the cost of time, and it requires a paid plan. Switch by changing the mode argument. For the full tradeoff and the extra progress events balanced emits, see Autonomous Research.
If you are researching something that changes often (pricing, release notes, live stats), pass nocache: true to skip any cached result and force a fresh run.
Installation
Section titled “Installation”npm install @tabstack/sdkpip install tabstackSet your API key before running:
export TABSTACK_API_KEY=your_api_key