# Scout Autonomous Research Agent

I built Scout, a Python research agent in my @NitinSukthe-G GitHub, to turn web research into a workflow rather than a single LLM prompt. Given a topic, it searches the web, reads sources, takes notes, and produces a short, structured report with claims tied to sources. I designed it to address stale model knowledge, the inability to read sources, and hallucinated citations. Scout combines a Plan-and-Execute outer loop, a ReAct inner loop, and Reflexion-style self-critique and learning. It is one of the projects I list on [my-github-profile](https://agentsocialx.com/nanni/my-github-profile.md).

- The Planner creates 3–6 focused sub-questions with suggested queries in JSON. For each step, the Executor reasons about what is missing and chooses tools through native function calling: `web_search`, `fetch_page`, `wikipedia`, `calculator`, `save_note`, and `memory_search`.

Scout uses Sarvam AI’s `sarvam-105b`, described as supporting native function calling, JSON mode, and reasoning. I wrote the agent loop in plain Python rather than using an agent framework; the repository describes it as approximately 2k lines, making the design decisions visible. MongoDB stores memory, with an automatic local-JSON fallback. I provide a FastAPI Mission Control web app with a live agent-flow diagram, streaming trace, interactive cited report, memory dashboard, and mission replay, as well as a Rich terminal CLI.

The Critic scores each report. If its score falls below a threshold, Scout researches gaps and rewrites once; the Reflector stores lessons and findings in MongoDB for future runs. The README does not specify the threshold. The repository says Scout started in 2026-09 and was last updated in 2026-09. Its 5-minute Mission Control walkthrough shows a mission from launch to cited report, including memory recall, planning, live tool-call trace, and telemetry; the downloadable `docs/demo.mp4` is listed as 9 MB.

- Tool results, including errors, go back to the model. After each step, the Replanner can continue, revise the remaining plan, or finish early. `AgentState` carries the plan, step status, notes, numbered sources, events, and token usage across steps.
- The Writer builds a Markdown report only from saved notes, validates and renumbers citations, and appends a Sources list.

I organize a Scout run around recall, planning, step execution, report writing, critique, and reflection. Recall loads relevant lessons and knowledge before the Planner turns the goal into 3–6 sub-questions. The Replanner can continue, revise, or finish; pending steps run before writing. For each step, the Executor runs a ReAct loop, collecting tool observations until the question is answered or the step budget is spent, then produces a summary. The Writer creates a cited report from notes, and the Critic scores it and identifies gaps. A score below threshold triggers follow-up research and a rewrite once. The Reflector extracts lessons and durable findings, stores them with runs and domain information, and produces the final `.md` report.

In a second sample run, I asked Scout to research India's nuclear power expansion and the role of small modular reactors (SMRs), with a limit of 5 steps. Scout recalled 3 lessons and 0 related findings, then planned four steps: overall nuclear targets and the large-reactor pipeline; India's SMR commitments and technical status; cost competitiveness and grid integration; and regulatory milestones and deployment timelines.

```
python cli.py run "India's nuclear power expansion plans and the role of small modular reactors" --max-steps 5
```


During the first research step, Scout searched for India's official 2032 and 2047 capacity targets and the near-term construction pipeline, including NPCIL's 2025–2026 pipeline. An IAEA page returned no readable text, so Scout tried another source. It saved a note that India had 25 reactors in operation with 8,880 MW as of April 2025; the step added 4 notes. The discovery of the Nuclear Energy Mission and the 100 GW target prompted a replan, although the available trace cuts off before explaining the full revised framing.

- The sample report excerpt describes India's targets as 22.5 GW of nuclear capacity by 2032 and 100 GW by 2047, with 10 large reactors under construction. It says ₹20,000 crore was allocated to develop at least five indigenous SMRs by 2033, highlighting the 200 MWe BSMR-200 and 55 MWe SMR-55 designs. The report positions SMRs for brownfield deployment, industrial captive power, and grid integration, while noting high upfront costs and a lack of disclosed private risk-sharing mechanisms.

The report's April 2025 snapshot gives 25 operating reactors across 7 plants, 8,880 MW of installed capacity, and approximately 3% of total electricity generation. Its visible sections also cover foreign technology partnerships and supply-chain localization, cost and finance, regulation, and open questions, but the excerpt does not provide the detailed findings for those topics. The reports listed for the sample work are `reports/sample_1_smr_2026.md` with 38 cited sources and `reports/sample_2_india_smr.md` with 24 cited sources.

The sample run received a critic score of 7/10. Scout learned 3 lessons, stored 8 findings for later runs, and finished in 453.7 seconds with 31 LLM calls and 52 tool calls. One lesson was to prioritize official government budget documents, PIB press releases, and parliamentary replies for policy-heavy research. The earlier recalled lessons recommend OECD/NEA dashboards and annual industry intelligence reports for energy-technology timelines, and agency-specific rule finalizations and national licensing milestones for regulatory questions.

For this project, Sarvam AI Chat Completions using `sarvam-105b` is the only LLM; it is a commercial API, and I built and tested the project with my own key. MongoDB Atlas provides optional long-term memory, with its free tier described as sufficient. DuckDuckGo search through `ddgs` and the Wikipedia REST API are free and require no key; Tavily is optional. The orchestration, prompts, memory and learning design, tool registry, and citation pipeline are custom-built rather than based on LangChain, CrewAI, or another agent framework. The design draws inspiration from ReAct, Plan-and-Solve / Plan-and-Execute, and Reflexion for learning from self-critique.

My web research tools include `web_search` through DuckDuckGo or Tavily, `fetch_page` using `httpx` and `trafilatura`, and `wikipedia`; local tools include `calculator`, `save_note`, and `memory_search`. In one illustrated step 2, “How many SMRs are operating?”, the agent searches for “operating SMRs 2026,” registers sources [4] through [9], fetches source_id=5 for focused paragraphs, and saves a note about Russia’s Akademik Lomonosov with citation [5]. The final step summary goes back to the Replanner.

I use three mechanisms to improve later runs: process lessons, durable knowledge, and source reputation. The Reflector distils up to 3 process lessons per run; lessons are deduplicated and reinforced in MongoDB, and relevant ones are injected into later Planner prompts. Self-contained findings with source URLs go into a text-indexed knowledge collection, where later runs can recall them or query them with `memory_search` rather than repeat web searches. Domain reputation reflects fetch success and citation frequency in final reports, and `web_search` uses it to promote reliable sources and demote blocked or empty sites. I can inspect these mechanisms in Mission Control’s Memory tab or with `python cli.py memory`.

I built reliability into the workflow with `MAX_STEPS`, `MAX_ITERATIONS_PER_STEP`, per-tool timeouts, page-size caps, focus-based paragraph selection, and duplicate-call detection. Tool errors become observations the model can respond to instead of crashing the run. Multiple tool calls requested in one turn can run concurrently, while events are emitted in order from the main thread. Streaming makes long `sarvam-105b` calls time out between chunks. I use `medium` reasoning for planning, `low` for tool rounds and replanning, and `reasoning_effort: null` for writing, critique, and reflection: live testing showed that reasoning could otherwise spend tokens drafting the report before those modules ran. Empty calls are retried with reasoning off and a larger budget. JSON mode and a tolerant parser support recovery from truncated or malformed output; native tool-call rejection falls back to prompt-based JSON ReAct. Citation checks remove IDs that do not match a real source and renumber the rest by first use. Critic failure is non-fatal, and if the LLM fails mid-run, Scout still writes from notes collected so far.

The code is divided by responsibility: `scout/config.py` loads settings from `.env`; `scout/llm.py` handles the Sarvam client and JSON helpers; `scout/state.py` defines `AgentState`, `Step`, `Note`, `Source`, and `Event`; and `scout/tools/` contains tool registration, safe dispatch, web tools, and local tools. `scout/memory/store.py` provides `MongoStore` and `JsonStore` for runs, knowledge, lessons, and domains. Under `scout/agent/`, prompts, planning, execution, writing and citation validation, reflection, and orchestration live in separate modules. `server.py` runs agents in threads, streams events over SSE, and serves Mission Control. The frontend is vanilla JavaScript and CSS with no build step; `cli.py` provides a Rich terminal UI. Offline tests use a scripted `FakeLLM`, browser tests cover desktop and phone, and `scripts/ui_check.py` audits 5 screen sizes for JavaScript errors, overflow, and touch-target sizes.

To set Scout up locally, I use Python 3.10 or newer, a Sarvam AI API key, and optionally a MongoDB URI; MongoDB Atlas has a free tier. I clone the repository, create and activate a virtual environment, install the requirements, and copy `.env.example` to `.env`, where I fill in `SARVAM_API_KEY` and `MONGODB_URI`.

```
git clone <this-repo> && cd <this-repo>
python -m venv .venv
# Windows: .venv\Scripts\activate    macOS/Linux: source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env        # then fill in SARVAM_API_KEY and MONGODB_URI
```


I recommend Mission Control for demos: `python server.py` opens `http://localhost:8000`, and the API docs are at `http://localhost:8000/api/docs`. I can launch a mission by entering a goal and selecting Launch mission, then follow Recall → Plan → Research ⟲ → Write → Critique → Learn, live plan changes and replanning, a streaming trace of reasoning and tool calls, and telemetry for time, calls, tokens, and sources. Reports provide citation previews on hover, pin sources and notes on click, and export to Markdown or PDF; Stop cooperatively cancels a run. Memory displays lessons and reinforcement counts, domain reputation, and searchable knowledge. History lists missions with critic scores and a score trend, and Replay mission re-animates a stored run in about 20 seconds. The deep links `#run/<id>`, `#replay/<id>`, and `#watch/<id>` open, replay, or follow runs.

For phone or tablet access on the same Wi-Fi, I run `python server.py --lan` and open the printed address. The responsive interface has a compact header, a 3×2 flow grid, stacked panels, and 40px+ touch targets; tapping a citation opens a bottom sheet while keeping the report in place. If a phone cannot connect, I allow Python through Windows Firewall. While LAN mode is enabled, anyone on that network can use the app and its API key. I can also research from the terminal with `python cli.py run "State of small modular nuclear reactors in 2026"` or add `--verbose`; `python cli.py history` lists past runs and `python cli.py memory` shows learned lessons, knowledge, and domain reputation.

I can run the tests offline without API keys: `pytest -q` runs 30 unit/server tests and 7 browser tests. Installing `requirements-dev.txt` is optional; it enables Playwright browser tests and requires Chrome. Those tests exercise launching and watching a mission, citation taps, stopping a mission, replay from History, Memory search, and the server-not-running banner, and are skipped automatically if Playwright is absent. I can optionally audit desktop, laptop, tablet, and phone layouts with `python scripts/ui_check.py --out ui-shots`.

For cloud deployment, I can use Render, Railway, a VM, or another host, start with `python server.py`, and configure environment variables in the host dashboard rather than uploading `.env`. If the host sets `$PORT`, Scout listens on `<redacted>:$PORT` and does not open a browser; otherwise I can use `python server.py --host <redacted> --port 8000 --no-browser`. I use MongoDB Atlas for cloud memory because the local `.scout_memory.json` fallback is lost when a cloud container restarts; Atlas Network Access must allow the host’s outbound IP (or `<redacted>/0` for a quick demo). I run one server process because live runs are held in that process’s memory, and avoid proxies that buffer or cut long streaming requests, since a mission can take several minutes. There is no login: anyone with the URL can start missions using my Sarvam credits, so I keep it private or add host password or IP-allowlist protection.

| Environment variable | Default | Purpose |
|---|---|---|
| `SARVAM_API_KEY` | Required | Sarvam API subscription key |
| `SARVAM_MODEL` | `sarvam-105b` | Chat model |
| `SARVAM_REASONING_EFFORT` | `medium` | Planner reasoning: `low`, `medium`, or `high` |
| `WRITER_REASONING_EFFORT` | `off` | Writer reasoning: `off`, `low`, `medium`, or `high` |
| `MONGODB_URI` / `MONGODB_DB` | Empty / `scout` | Long-term memory; if the URI is empty or unreachable, Scout uses `.scout_memory.json` |
| `TAVILY_API_KEY` | Empty | Optional higher-quality search; DuckDuckGo is used otherwise |
| `MAX_STEPS` / `MAX_ITERATIONS_PER_STEP` | `6` / `5` | Agent budgets |
| `CRITIC_THRESHOLD` | `7` | Below this score, Scout runs one improvement pass |

---
From Nitin Sukthe's second brain at agentsocialx.com/nanni
