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

# Simulation & episodes

> How simulated conversations are identified — and how to attach your internal traces to a test run.

## Episodes

When Eldros tests your agent, it opens a conversation and plays a scenario
against it — through your normal protocol, exactly like a real user. One such
simulated conversation is an **episode**. Every episode has an id, and the
platform uses it to assemble the run's results: transcript, judgments, and any
traces that carry it.

```
episode (one simulated conversation / test run)
└── session (the conversation Eldros opened with your agent)
    └── turn / trace spans — stamped episode.id, traffic_type=simulation
```

**This requires no code on your side.** Eldros drives the conversation and
captures the transcript itself, and it records which conversation belongs to
which episode at the moment it connects. Your simulation results appear on the
platform either way.

## Joining your internal traces to an episode

If your agent runs the SDK, you can go one step further: tag the telemetry
*your* process produces — turn spans, LLM and tool calls — with the episode,
so the run's results include your agent's internal view.

Eldros sends standard W3C `traceparent` + `baggage` headers on every
connection it opens to your agent — an HTTP request, or the WebSocket
handshake (the upgrade request is a plain HTTP GET). Continue them with one
call, in any framework:

```python theme={null}
# HTTP: per request
with eldros_sdk.trace_context(request.headers):
    with eldros_sdk.turn(msg, session_id=conversation_id) as t:
        ...

# WebSocket: once after accept — one connection is one conversation
async def ws_handler(websocket):
    with eldros_sdk.trace_context(websocket.headers):
        while ...:
            with eldros_sdk.turn(msg, session_id=conversation_id) as t:
                ...
```

`trace_context` takes any header mapping — it is a plain context manager, so
it works in every server framework, ASGI or not. Inside the block, every span
gets:

* **`episode.id`** — on every span, so the platform can fetch the run's full
  telemetry with one filter.
* **`traffic_type="simulation"`** — simulated traffic never pollutes your
  production views.
* **Session grouping for free** — when no session id is present, spans group
  under the episode id automatically.

<Note>
  On production traffic these headers simply aren't there, and `trace_context`
  is a harmless no-op passthrough — you can keep the same handler code for both.
</Note>

## When the id arrives another way

If your protocol carries the episode id somewhere else — a query parameter, a
bootstrap message field — set it directly instead:

```python theme={null}
eldros_sdk.set_episode(episode_id)        # once, at connection start

# or scoped, when one process handles many episodes:
with eldros_sdk.episode(episode_id):
    ...
```

Set it **before** opening turns: identity is stamped when a span starts, so an
episode set mid-turn misses the turn span itself.
