> ## Documentation Index
> Fetch the complete documentation index at: https://docs.starlight-search.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Deep Agents

> The context manager pattern: use reflect.trace() as a with-block to instrument multi-step tool-using agents.

## Pattern: Context Manager

The context manager pattern (`with reflect.trace(...)`) gives you full control over when the trace is submitted and lets you decide the review result after inspecting the agent's output. It fits naturally into multi-step workflows where a decorator would be too rigid.

```
with reflect.trace(task)  →  ctx.augmented_task  →  agent runs tools  →  ctx.set_output  →  trace auto-submitted on exit
```

This example pairs [Deep Agents](https://github.com/andysingal/deep_agents) with [Exa](https://exa.ai) for real-time web search and uses Reflect to build memory across research runs.

## Prerequisites

```bash theme={null}
export REFLECT_API_KEY=rf_live_...
export REFLECT_PROJECT_ID=your-project-id
export EXA_API_KEY=...
export OPENAI_API_KEY=sk-...      # or another provider key
```

Install dependencies:

```bash theme={null}
pip install reflect-sdk deepagents exa-py
```

Optional env vars:

```bash theme={null}
export REFLECT_API_URL=https://api.starlight-search.com  # defaults to localhost:8000
export DEEPAGENT_MODEL=openai:gpt-5.4-mini
export RESEARCH_QUERY="Latest breakthroughs in fusion energy"
```

## Full example

```python deepagents_exa_quickstart.py theme={null}
"""Deep Agents quickstart using Exa Search + Reflect memory loop.

Prerequisites:
- pip install deepagents exa-py
- Set EXA_API_KEY
- Set one model provider API key (for example OPENAI_API_KEY)
- Set REFLECT_PROJECT_ID and REFLECT_API_KEY

Optional env vars:
- REFLECT_API_URL (default: http://localhost:8000)
- DEEPAGENT_MODEL (default: openai:gpt-5.4-mini)
- RESEARCH_QUERY (default: What is the stock price of Apple and Nvidia?)
"""

from __future__ import annotations

import os

from deepagents import create_deep_agent
from exa_py import Exa
from reflect_sdk import ReflectClient
from reflect_sdk.converters import from_deepagents

BASE_URL = os.getenv("REFLECT_API_URL", "http://localhost:8000")
PROJECT_ID = os.getenv("REFLECT_PROJECT_ID") or "example"
REFLECT_API_KEY = os.getenv("REFLECT_API_KEY")
MODEL = os.getenv("DEEPAGENT_MODEL", "openai:gpt-5.4-mini")
TASK = os.getenv("RESEARCH_QUERY", "What is the stock price of Apple and Nvidia?")
MEMORY_LIMIT = 3
MEMORY_LAMBDA = 0.5
API_TIMEOUT = 180.0

research_instructions = """You are an expert researcher. Your job is to conduct thorough research and then write a polished report.

You have access to an internet search tool as your primary means of gathering information.

## `internet_search`

Use this to run an internet search for a given query. You can specify the max number of results to return and the topic.
Prefer high-quality primary sources and cite concrete facts from search results.
"""


def internet_search(query: str, max_results: int = 5):
    """Run an internet search using Exa."""
    exa = Exa(api_key=os.environ["EXA_API_KEY"])
    return exa.search(
        query,
        num_results=max_results,
        contents={"highlights": {"max_characters": 2000}},
    )


def main() -> None:
    if not os.getenv("EXA_API_KEY"):
        raise RuntimeError("Set EXA_API_KEY.")
    if not PROJECT_ID or not REFLECT_API_KEY:
        raise RuntimeError("Set REFLECT_PROJECT_ID and REFLECT_API_KEY.")

    reflect = ReflectClient(
        base_url=BASE_URL,
        api_key=REFLECT_API_KEY,
        project_id=PROJECT_ID,
        timeout=API_TIMEOUT,
    )

    with reflect.trace(TASK, limit=MEMORY_LIMIT, lambda_=MEMORY_LAMBDA) as ctx:
        agent = create_deep_agent(
            model=MODEL,
            tools=[internet_search],
            system_prompt=research_instructions,
        )
        result = agent.invoke({"messages": [{"role": "user", "content": ctx.augmented_task}]})
        print(result)
        trajectory = from_deepagents(result["messages"])
        ctx.set_output(
            trajectory=trajectory,
            model=MODEL,
            metadata={"source": "deepagents_exa_quickstart"},
        )


if __name__ == "__main__":
    main()
```

## Run it

```bash theme={null}
python deepagents_exa_quickstart.py
# or with a custom query:
RESEARCH_QUERY="Who founded Anthropic?" python deepagents_exa_quickstart.py
```

## How it works

<Steps>
  <Step title="Open a trace context">
    `reflect.trace(task)` retrieves relevant memories and opens a trace that will be submitted when the `with` block exits.

    ```python theme={null}
    with reflect.trace(TASK, limit=3, lambda_=0.5) as ctx:
        ...
    # trace is submitted here, on __exit__
    ```

    `limit` controls how many memories are retrieved. `lambda_` balances semantic similarity vs. utility when ranking them (0 = pure similarity, 1 = pure utility).
  </Step>

  <Step title="Pass the augmented task to the agent">
    `ctx.augmented_task` is the original task with relevant memories from past runs prepended. Passing this to the agent means it can draw on what worked before.

    ```python theme={null}
    result = agent.invoke({
        "messages": [{"role": "user", "content": ctx.augmented_task}]
    })
    ```
  </Step>

  <Step title="Define a tool the agent can call">
    The agent can call `internet_search` to retrieve live data. Exa returns highlights from matching pages, which the agent cites in its report.

    ```python theme={null}
    def internet_search(query: str, max_results: int = 5):
        exa = Exa(api_key=os.environ["EXA_API_KEY"])
        return exa.search(query, num_results=max_results,
                          contents={"highlights": {"max_characters": 2000}})
    ```
  </Step>

  <Step title="Convert messages and set output">
    `from_deepagents` maps the agent's message list into Reflect's trajectory format. Call `ctx.set_output` before the `with` block exits to attach the trajectory and metadata to the trace.

    ```python theme={null}
    from reflect_sdk.converters import from_deepagents

    trajectory = from_deepagents(result["messages"])
    ctx.set_output(
        trajectory=trajectory,
        model=MODEL,
        metadata={"source": "deepagents_exa_quickstart"},
    )
    ```
  </Step>
</Steps>

## Adding a review

Pass `result` to `ctx.set_output` to close the learning loop at submission time:

```python theme={null}
ctx.set_output(
    trajectory=trajectory,
    model=MODEL,
    result="pass",          # or "fail"
    feedback_text="...",    # only needed on fail
)
```

Without `result`, the trace is stored with a pending review and can be reviewed later from the dashboard.

## The `lambda_` parameter

When retrieving memories, Reflect ranks candidates by a blended score:

```
score = (1 - lambda_) × similarity + lambda_ × q_value
```

* **`lambda_ = 0`** - pure semantic similarity (most relevant to this query)
* **`lambda_ = 0.5`** - balanced (default)
* **`lambda_ = 1`** - pure utility - memories from the most successful past runs)

As more traces are reviewed, utility scores improve and memory retrieval becomes increasingly useful.
