DEEP_RESEARCH.md
Rama main · réplica de lectura del repositorio original.
### 9.1 Persisted Worker Declaration
The persisted worker assistant declares logical platform capabilities:
```python
tools = [
{"type": "web_search"},
{"type": "scratchpad"},
]
```
The assistant subscribes to capabilities rather than persisting the
individual concrete runtime functions.
Infrastructure identity such as `scratchpad_id`, `thread_id`, `owner_id`,
and `user_id` is therefore not part of the model-facing tool schema.
### 9.2 Runtime Tool Expansion
During input-context construction, `ContextMixin` resolves these capability
placeholders through `PLATFORM_TOOL_MAP`.
Conceptually:
```text
{"type": "web_search"}
|
+--> perform_web_search
+--> read_web_page
+--> search_web_page
+--> scroll_web_page
{"type": "scratchpad"}
|
+--> read_scratchpad
+--> update_scratchpad
+--> append_scratchpad
```
Core owns the concrete runtime tool definitions while the assistant stores
only the logical capability subscriptions.
Project David Deep Research is a bounded, multi-agent research execution architecture designed around two primary failure modes of long-horizon LLM work:
1. **Context pollution** — allowing every search result, page read, failed lead, tool response, retry, and intermediate reasoning step to accumulate in the supervisor conversation.
2. **Unbounded chaotic execution** — allowing autonomous research loops to recurse indefinitely, lose protocol state, or report partial work as successful.
The architecture separates **research execution**, **shared research state**, and **supervisor synthesis** so that workers can perform messy, multi-step research without transferring their entire working history into the parent context.
The result is not simply a collection of cooperating agents. It is a small probabilistic execution system with explicit boundaries for state, protocol correlation, failure, and termination.
---
## 1. Design Goals
Deep Research is intended to provide the following properties:
- keep the supervisor context compact;
- allow workers to perform multi-turn autonomous research;
- allow multiple workers to share verified findings;
- preserve strict tool-call / tool-result correlation;
- prevent worker-local protocol traffic from leaking to the client;
- bound worker execution;
- distinguish worker failure from worker success;
- preserve deterministic conversation chronology;
- make research progress observable while execution is in flight;
- allow the supervisor to synthesize results from durable research state rather than worker transcript exhaust.
The core design principle is:
> **Workers may have noisy execution histories. Shared research state should contain only information deliberately promoted into it.**
---
## 2. High-Level Architecture
```mermaid
flowchart TD
U[Client] --> S[Supervisor]
S -->|delegate research task| D[Delegation Layer]
D --> WA[Worker A]
D --> WB[Worker B]
D --> WC[Worker C]
WA --> TA[Worker Tool Loop]
WB --> TB[Worker Tool Loop]
WC --> TC[Worker Tool Loop]
TA --> SP[(Shared Scratchpad)]
TB --> SP
TC --> SP
SP --> WA
SP --> WB
SP --> WC
SP --> S
WA -->|correlated delegation result| D
WB -->|correlated delegation result| D
WC -->|correlated delegation result| D
D --> S
S --> U
```
The supervisor plans and synthesizes.
Workers research.
The scratchpad carries durable cross-worker findings.
The worker conversation remains worker-local.
---
## 3. The Two Execution Planes
Deep Research deliberately separates two different forms of state.
### 3.1 Conversation Plane
The **conversation plane** is the worker's actual inference history.
It contains protocol-sensitive messages such as:
- assistant messages;
- tool calls;
- tool results;
- model reasoning;
- worker-local context;
- retries and intermediate execution state.
Each delegated worker operates on its own conversation thread.
This is where provider protocol integrity matters.
```text
worker thread
│
├── assistant
│ └── tool_calls
│
├── tool result
│
├── tool result
│
├── assistant
│
└── ...
```
The conversation plane is **not** the shared research memory.
### 3.2 Shared Research Plane
The **shared research plane** is the scratchpad.
It exists to carry deliberately promoted research state between:
- supervisor → worker;
- worker → worker;
- worker → supervisor.
Typical contents include:
- task seed information;
- verified facts;
- citations or source notes;
- compact findings;
- coordination markers;
- state required by a later worker.
```text
Shared Scratchpad
[seed from supervisor]
[Worker A verified finding]
[Worker A marker]
[Worker B acknowledgement]
[Worker B verified finding]
[supervisor synthesis notes]
```
The scratchpad is intentionally much smaller and cleaner than worker execution history.
---
## 4. Why the Scratchpad Exists
Without the scratchpad boundary, long-running research tends toward:
```text
search query
↓
search result
↓
page content
↓
tool response
↓
reasoning
↓
failed lead
↓
retry
↓
more page content
↓
more reasoning
↓
parent context
↓
context pollution
```
Deep Research instead promotes only selected information:
```text
Internet / external sources
↓
Worker
↓
research + verification
↓
deliberate scratchpad write
↓
Shared Scratchpad
↓
Supervisor
```
The supervisor therefore consumes **research state**, not the complete history of how that state was produced.
This is the primary context-pollution control mechanism.
---
## 5. Scratchpad Thread Semantics
A worker has two thread identities that must never be conflated.
```text
conversation_thread_id
= worker's own inference conversation
scratchpad_thread_id
= shared parent research state
```
Conceptually:
```python
conversation_thread_id = thread_id
scratchpad_thread_id = scratch_pad_thread or thread_id
```
Scratchpad operations use:
```text
scratchpad_thread_id
```
Correlated tool-result submission uses:
```text
conversation_thread_id
```
This distinction is fundamental.
If a worker tool result is written into the shared scratchpad thread instead of the worker conversation thread, the provider sees a broken tool protocol.
The architecture therefore treats:
> **conversation state and shared research state as different data planes.**
---
## 6. Supervisor Responsibilities
The supervisor owns research orchestration rather than detailed execution.
Its responsibilities include:
- decomposing the research problem;
- deciding when delegation is required;
- seeding shared state;
- issuing bounded worker tasks;
- observing worker progress;
- re-reading the scratchpad after worker completion;
- deciding whether further delegation is needed;
- synthesizing the final answer.
The supervisor does **not** need the complete worker transcript.
A typical supervisor lifecycle is:
```mermaid
sequenceDiagram
participant S as Supervisor
participant SP as Shared Scratchpad
participant W1 as Worker A
participant W2 as Worker B
S->>SP: seed task state
S->>W1: delegate task A
W1->>SP: read seed
W1->>W1: search / browse / verify
W1->>SP: append verified finding A
W1-->>S: delegation result
S->>SP: re-read shared state
S->>W2: delegate task B
W2->>SP: read seed + finding A
W2->>W2: search / browse / verify
W2->>SP: append verified finding B
W2-->>S: delegation result
S->>SP: final read
S->>S: synthesize
```
---
## 7. Worker Responsibilities
A research worker is an ephemeral autonomous executor.
A worker may:
- read the shared scratchpad;
- perform web search;
- read web pages;
- search within pages;
- scroll pages;
- verify information;
- append findings to the scratchpad.
Its working context is disposable.
Its promoted findings are durable.
A worker lifecycle is approximately:
```text
delegate
↓
create ephemeral worker context
↓
read shared scratchpad
↓
search
↓
browse
↓
reason
↓
verify
↓
append promoted result
↓
return correlated delegation result
↓
terminate
```
---
## 8. Bounded Autonomous Execution
Research workers are autonomous, but not unbounded.
The current research worker turn budget is:
```text
RESEARCH_WORKER_MAX_TURNS = 8
```
The purpose of the turn budget is not to force all research into one model call.
It exists to provide enough space for a realistic sequence such as:
```text
read state
→ search
→ inspect
→ refine
→ inspect
→ verify
→ write result
```
while still providing a hard execution ceiling.
The design therefore rejects both extremes:
```text
max_turns = 1
```
is too restrictive for meaningful research.
Unlimited recursion is operationally unsafe.
Deep Research uses **bounded autonomy**.
---
## 9. Worker Tool Registry
There is a distinction between the worker assistant's persisted tool declaration and the runtime-expanded tool implementation.
### 9.1 Persisted Worker Declaration
The persisted worker assistant exposes the logical research capabilities:
```python
platform capability placeholders = [
{"type": "web_search"},
read_scratchpad,
append_scratchpad,
]
```
This keeps persisted assistant configuration within the supported tool namespace.
### 9.2 Runtime Tool Expansion
At runtime, the worker can use the concrete execution functions:
```python
WORKER_TOOLS = [
perform_web_search,
read_web_page,
search_web_page,
scroll_web_page,
read_scratchpad,
append_scratchpad,
]
```
This separation prevents internal platform implementation functions from being persisted as if they were ordinary externally declared assistant functions.
The reserved function namespace remains protected.
---
## 10. Delegation Is a Protocol Boundary
Delegation is not merely a Python function call.
From the supervisor's perspective, delegation behaves like a tool execution with a strict lifecycle:
```text
supervisor tool call
↓
DelegationMixin
↓
ephemeral worker run
↓
worker execution
↓
correlated delegation tool result
↓
supervisor continuation
```
The parent supervisor must always receive a correlated result for the delegation call.
That result may represent:
```text
success
```
or:
```text
error
```
but the protocol must be closed honestly.
---
## 11. Failure Semantics
A worker is not successful merely because it emitted some prose.
Provider failure must propagate through the worker lifecycle.
The required failure chain is:
```text
provider exception
↓
worker stream raises
↓
OrchestratorCore catches
↓
worker run receives failure state
↓
DelegationMixin observes failed execution
↓
partial worker prose is discarded
↓
correlated delegation result is returned with is_error=True
↓
delegation action fails
↓
supervisor receives an honest failed tool result
```
This avoids a dangerous failure mode:
```text
worker produces partial text
↓
provider crashes
↓
exception converted into text
↓
delegation layer sees some content
↓
false DELEGATE_SUCCESS
```
The architecture explicitly rejects that behaviour.
---
## 12. Provider Exception Ownership
Provider workers must not swallow inference exceptions and convert them into ordinary streamed content.
For the Qwen/Together path, provider exceptions are allowed to propagate:
```python
except Exception:
raise
```
The higher orchestration layer owns run failure lifecycle.
This is important because only the orchestration layer has enough context to correctly update:
- run status;
- `last_error`;
- failure timestamps;
- emitted failure events;
- delegation result state.
---
## 13. Partial Output Is Not Success
A delegated worker may emit useful-looking text before an inference failure.
That text is not sufficient evidence of completed execution.
Delegation therefore maintains explicit failure state.
Conceptually:
```text
execution_had_error = True
```
causes partial worker output to be discarded as the final delegation result.
The supervisor instead receives a correlated error result.
This protects synthesis from accidentally consuming incomplete research as verified work.
---
## 14. Tool-Call Correlation
Research frequently requires parallel tool use.
For example, a worker may simultaneously:
```text
read_scratchpad
perform_web_search
```
Each tool invocation has an independent `tool_call_id`.
The provider protocol requires a corresponding result for every call.
```text
assistant
tool_calls:
call_read
call_web
tool
tool_call_id = call_read
tool
tool_call_id = call_web
```
Those messages must remain independent.
---
## 15. Protocol Messages Are Atomic
The conversation truncation/normalization layer must not merge structured protocol messages.
The following are atomic:
- any `role="tool"` message;
- any message containing `tool_calls`;
- any message containing `tool_call_id`.
Only ordinary adjacent conversational messages may be merged.
Why:
```text
tool result A
tool result B
```
cannot safely become:
```text
merged tool result
tool_call_id = A
content = A + B
```
because the provider will correctly conclude that tool call B was never answered.
This invariant protects parallel tool execution.
---
## 16. Conversation Truncation Must Respect Protocol Structure
Context reduction is allowed to compress ordinary conversational content.
It must not destroy tool-call groups.
Conceptually, this sequence is one protocol unit:
```text
assistant(tool_calls=[A, B])
tool(A)
tool(B)
```
Removing or merging individual members can make the remaining history invalid.
The current architecture already prevents protocol-message merging.
A further hardening area is token-budget truncation: protocol groups should eventually be removed or retained atomically rather than as unrelated individual messages.
---
## 17. Deterministic Message Ordering
Tool protocol also depends on deterministic chronology.
Wall-clock timestamps are insufficient when multiple messages can be persisted within the same second.
Deep Research therefore relies on a canonical monotonic persistence order:
```text
Message.sequence_no
```
The database provides:
```text
BIGINT
NOT NULL
AUTO_INCREMENT
UNIQUE
```
Conversation reads use `sequence_no` as the authoritative ordering mechanism.
This prevents a tool result from being reordered relative to the assistant tool call that created it.
The distinction is:
```text
created_at
= event time
sequence_no
= canonical persistence order
```
For provider conversation reconstruction, `sequence_no` is the stronger ordering primitive.
---
## 18. Worker Isolation
Workers are deliberately ephemeral.
They should not become permanent participants in the supervisor's context.
Isolation provides several benefits:
- tool chatter remains local;
- failed search paths remain local;
- temporary assumptions remain local;
- provider-specific reasoning remains local;
- token pressure remains local;
- one worker cannot accidentally rewrite another worker's conversation history.
Cross-worker communication happens through the scratchpad rather than transcript sharing.
---
## 19. Cross-Worker Collaboration
Two workers do not need direct conversation with each other.
They collaborate through durable state.
Example:
```text
Supervisor:
writes seed
Worker A:
reads seed
performs research
writes finding A
writes marker A
Supervisor:
confirms marker A exists
Worker B:
reads seed
reads finding A
reads marker A
performs independent research
writes finding B
acknowledges marker A
Supervisor:
reads complete shared state
```
This pattern gives workers indirect coordination without requiring context inheritance.
---
## 20. Client Boundary
Internal Deep Research tools are platform-controlled.
They are not intended to surface as client-side tool execution requests.
During a successful Deep Research run:
```text
CLIENT_TOOL_REQUEST_SURFACED = NO
LOCAL_TOOL_EXECUTOR_USED = NO
```
The supervisor and workers use Core's internal tool handling path.
This is important because delegation, scratchpad access, and internal research tooling are implementation details of the orchestration runtime rather than requests for the SDK consumer to execute locally.
---
## 21. Observability
Long-running research must be observable while still hiding internal protocol noise from the client.
The architecture emits structured events such as:
- `ResearchStatusEvent`;
- `ScratchpadEvent`;
- `ReasoningEvent`;
- `ContentEvent`.
This allows a consumer to observe:
```text
research started
worker delegated
worker researching
scratchpad updated
worker completed
supervisor synthesizing
```
without exposing internal worker tool protocol as consumer tool requests.
The desired split is:
```text
internal execution protocol
≠
external progress signalling
```
---
## 22. Successful End-to-End Contract
The current integration test proves the following sequence:
```text
Supervisor
↓
seed shared scratchpad
↓
delegate Worker A
↓
Worker A reads seed independently
↓
Worker A researches first fact
↓
Worker A appends verified finding + unique marker
↓
Supervisor re-reads scratchpad and observes marker
↓
delegate distinct Worker B
↓
Worker B reads seed + Worker A marker
↓
Worker B performs independent research
↓
Worker B appends second finding + matching acknowledgement
↓
Supervisor re-reads complete shared state
↓
parent run completes
```
Acceptance requires:
```text
INFERENCE_STREAM=PASS
CORE_TOOL_BOUNDARY=PASS
SHARED_SCRATCHPAD=PASS
DEEP_RESEARCH_INTEGRATION=PASS
WORKER_FAILURE_LIFECYCLE=PASS
```
It also requires that no client tool request escape the internal orchestration boundary.
---
## 23. Core Implementation Seams
The Deep Research architecture spans several Core components.
### `DelegationMixin`
Owns delegated worker execution.
Responsibilities include:
- launching delegated research;
- observing worker status;
- collecting output;
- handling worker failure;
- producing the correlated supervisor tool result;
- preventing partial failed output from becoming success.
### `ScratchpadMixin`
Owns shared research-state access.
Its central invariant is the separation between:
```text
conversation_thread_id
```
and:
```text
scratchpad_thread_id
```
Scratchpad reads/writes operate on the latter.
Tool protocol responses remain on the former.
### `AssistantManager`
Creates/configures the research worker assistant and applies its bounded turn budget.
### `research_worker.py`
Defines the research worker's logical and runtime tool capabilities.
Key concepts:
```text
platform capability placeholders
WORKER_TOOLS
RESEARCH_WORKER_MAX_TURNS
```
### `ConversationTruncator`
Controls conversation compaction while preserving structured protocol messages as atomic records.
### `MessageService`
Reconstructs persisted conversation chronology using deterministic `sequence_no` ordering.
### `QwenBaseWorker`
For the Together/Kimi research path, provider exceptions propagate upward so that OrchestratorCore can own the failure lifecycle.
---
## 24. Architectural Invariants
The following invariants define the system.
### State
```text
worker conversation != shared scratchpad
```
### Correlation
```text
every tool_call_id must receive its own correlated result
```
### Ordering
```text
provider history is reconstructed by canonical persistence order
```
### Delegation
```text
partial output + failed execution != success
```
### Failure
```text
provider failure must reach orchestration lifecycle
```
### Context
```text
worker transcript is local
promoted research state is shared
```
### Autonomy
```text
workers may loop
workers may not loop without a hard bound
```
### Client boundary
```text
internal research tools do not become consumer tool requests
```
---
## 25. Failure Modes This Architecture Prevents
### Context flooding
**Failure:** every worker observation enters the supervisor context.
**Protection:** shared scratchpad promotion boundary.
### Worker protocol corruption
**Failure:** scratchpad thread identity replaces worker conversation identity.
**Protection:** separate conversation and scratchpad thread IDs.
### Lost parallel tool result
**Failure:** adjacent tool messages are merged.
**Protection:** protocol messages are atomic.
### Tool-call reordering
**Failure:** multiple same-second messages sort unpredictably.
**Protection:** monotonic `sequence_no`.
### False delegation success
**Failure:** provider fails after producing partial text.
**Protection:** exception propagation + explicit worker failure state + correlated error result.
### Infinite worker execution
**Failure:** research agent loops indefinitely.
**Protection:** bounded worker turn budget.
### Internal tool leakage
**Failure:** research tooling is surfaced to the SDK consumer for execution.
**Protection:** Core-owned internal tool routing.
---
## 26. Conceptual Model
The architecture can be understood as four layers.
```text
┌───────────────────────────────────────────────┐
│ SUPERVISOR │
│ planning · delegation · synthesis │
└──────────────────────┬────────────────────────┘
│
┌──────────────────────▼────────────────────────┐
│ DELEGATION CONTROL │
│ lifecycle · correlation · failure · bounds │
└──────────────────────┬────────────────────────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Worker A│ │Worker B│ │Worker C│
│tool loop│ │tool loop│ │tool loop│
└────┬───┘ └────┬───┘ └────┬───┘
│ │ │
└────────────┼────────────┘
▼
┌──────────────────┐
│ SHARED SCRATCHPAD│
│ promoted research│
│ durable findings │
└──────────────────┘
```
The supervisor operates on distilled shared state.
Workers operate on noisy local state.
Delegation controls execution.
The scratchpad is the information membrane between them.
---
## 27. Deep Research as a Systems Problem
The architecture treats LLM research as more than model prompting.
Once a model can:
- call tools;
- perform multiple turns;
- delegate work;
- operate concurrently;
- share state;
- fail independently;
the runtime acquires properties normally associated with distributed execution systems.
The important engineering concerns become:
```text
state isolation
message ordering
correlation
bounded execution
failure propagation
durable shared state
observability
protocol integrity
```
The model is probabilistic.
The orchestration contract should not be.
---
## 28. Summary
Project David Deep Research is built around one central idea:
> **Do not make the supervisor carry the complete execution history of research.**
Instead:
```text
Supervisor
plans
Workers
explore
Tools
produce noisy observations
Scratchpad
carries promoted research state
Delegation
enforces lifecycle and failure semantics
Message ordering
preserves protocol chronology
Truncation
preserves structured tool boundaries
Supervisor
synthesizes from durable findings
```
This allows research to be long-running and autonomous without allowing execution history to become unbounded parent context.
The architecture therefore solves the two original design problems directly:
```text
context pollution
→ isolated worker conversations + promoted shared scratchpad state
chaotic long-running loops
→ bounded workers + explicit delegation lifecycle + strict failure semantics
```
That is the Deep Research execution model in Project David.