# Deep Research Tools — Code Review Report

Last updated: 2026-03-05 15:12 CET

**Date:** 2026-03-05
**Commits reviewed:** `b72a018` (feat) + `0d285ff` (fixes)
**Files changed:** 20 files, +1166 lines
**Tests:** 717 passing (20 new), 0 regressions, clean lint

## Issues Found & Fixed

| # | Severity | Issue | Status |
|---|----------|-------|--------|
| 1 | Critical | Test mock patch targets wrong namespace — store mocks silently not firing | Fixed |
| 2 | High | `readOnlyHint=True` on write operation (`research_web_followup`) | Fixed |
| 3 | High | `_launch_times` dict unbounded — leaks on failed/cancelled tasks | Fixed |
| 4 | High | Weaviate `topic` field stored `report_text[:500]` instead of actual brief | Fixed |
| 5 | Medium | `@pytest.mark.asyncio` used against project convention (`asyncio_mode=auto`) | Fixed |
| 6 | Medium | `updated_at` not set on Weaviate insert | Fixed |
| 7 | Medium | `store_deep_research_followup` missing from `__all__` | False positive (already present) |
| 8 | Low | `researcher.md` uses `model: sonnet` vs project default of Opus | Pre-existing, by design |

## Recommendations for Future Improvement

### 1. Store follow-up responses in Weaviate (not just IDs)

`store_deep_research_followup` currently appends the follow-up interaction ID to the parent report's `follow_up_ids` list, but the follow-up response text is lost. It's not searchable via `knowledge_search`. Consider adding a `DeepResearchFollowups` collection or storing follow-up text as properties on the parent report.

### 2. Add `research_web_cancel` tool

The Interactions API exposes a `cancel()` method (`client.aio.interactions.cancel(id)`). Without a cancel tool, users can't abort a running $2-5 task. Simple implementation — one more tool on `research_server`.

### 3. Bounded `_launch_times` with TTL eviction

Current fix pops entries on terminal status, but entries for tasks that are never polled still accumulate. Options:
- Cap dict size (e.g., 100 entries, LRU eviction)
- Periodic TTL sweep (e.g., evict entries older than 2 hours)
- Use `session_store` / SQLite persistence for durability across restarts

### 4. Parallelize cross-reference queries

`_cross_reference()` in `weaviate_store/deep_research.py` runs two serial near-text queries (ResearchFindings, WebSearchResults) inside a single `asyncio.to_thread` call. For large collections, this adds latency. Consider `concurrent.futures.ThreadPoolExecutor` to run both queries in parallel within the same thread pool.

### 5. Add `DEEP_RESEARCH_AGENT` validator in `ServerConfig`

Unlike model name fields, an invalid agent string fails only at API call time. A `@field_validator` that checks for non-empty string would improve fail-fast behavior at config load.

### 6. Streaming support for follow-ups

`research_web_followup` currently waits for the full response. The Interactions API supports `stream=True` which could enable progressive delivery. MCP's dict-return pattern doesn't support streaming natively, but chunked follow-ups could be considered.

## Recent Commits

```
0d285ff fix(research): address code review findings on Deep Research tools
b72a018 feat(research): add Deep Research Agent tools via Interactions API
```
