# 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.


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 `websearch` domain 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 `scraping` adapter (SSRF-guarded). websearch does no page fetching.
- **LLM** = the injected provider registry — never a raw provider fetch.
- **Persistence** = `research_runs` dynamic 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.


---
Source: shared/services/knowledge/build-knowledge/deep-research.md
Canonical: https://docs.leumas.tech/p/how-to/deep-research
