Deep Research
@leumas/researchThe ecosystem's web-research pipeline: an iterative query → web-search → summarize → reflect loop (ported from the legacy ollama-research tool; LangGraph dropped) that ANY surface can call.
Deep Research (@leumas/research)
The ecosystem's web-research pipeline: an iterative query → web-search → summarize → reflect loop (ported from the legacy ollama-research tool; LangGraph dropped) that ANY surface can call.
How agents call it
| Surface | How |
|---|---|
| Chatbot / Leviathan | attach the deep_research functioncall (stored doc, executor action:deep-research) |
| Automation rule | action deep-research (e.g. cron trigger → daily research) |
| MCP client | functioncalls server → deep_research tool; raw search via the websearch server |
| HTTP | POST /api/research/run (JSON) or POST /api/research/run/stream (SSE) |
| Studio | Intelligence → Research Lab |
| Code | runDeepResearch({ topic, loops, searchApi, provider, onEvent, signal, providerRegistry, adapters, connector }) from @leumas/research |
Args: topic (required) · loops 1–10 (default 3) · searchApi auto|duckduckgo|wikipedia|tavily|perplexity · fetchFullPage (scrape top results via the scraping adapter) · provider/model (any @leumas/providers brain).
Layering (do NOT duplicate)
- Search = the
websearchdomain adapter (shared/engines/adapters/domain/websearch): one
search verb, fallback chain requested → duckduckgo → wikipedia; Tavily/Perplexity need TAVILY_API_KEY/PERPLEXITY_API_KEY env on the API.
- Scrape = the existing
scrapingadapter (SSRF-guarded). websearch does no page fetching. - LLM = the injected provider registry — never a raw provider fetch.
- Persistence =
research_runsdynamic collection (auto-written when a connector is injected);
history in Studio → Intelligence → Run History.
SSE vocabulary
start · loop · query · sources · page · summary · reflection · final · done · error (+ : ping heartbeat every 15s; client disconnect aborts the run; read POST-SSE with the shared admin/_shared/sse.js streamPostSse — EventSource is GET-only).
Gating
requireAuth + requireMembership('intelligence') (admins bypass) + PassNode guard feature:research.run — author a passnode_rules doc with that resource id to meter/charge runs; no rule = free pass. External search keys cost real money: meter before white-labeling.