> ## 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.

# WebSocket agents

> Traces, simulation, and production options for WebSocket-based agents.

## 1. Add traces

Call `init()` once at startup. Wrap each turn in the connection handler:

```python theme={null}
import eldros_sdk

eldros_sdk.init(traffic_type="prod")

async def ws_handler(websocket):
    await websocket.accept()
    session_id = websocket.query_params.get("session_id")

    while True:
        user_msg = await websocket.receive_text()

        with eldros_sdk.turn(user_msg, session_id=session_id) as t:
            reply = await agent.respond(user_msg)   # LLM call nests under the turn automatically
            await websocket.send_text(reply)
            t.reply(reply)                          # records the assistant turn
```

Pass the same `session_id` on every turn to group the whole conversation together.

## 2. Connect simulation

When Eldros runs a test scenario it opens a WebSocket connection with W3C `traceparent` +
`baggage` headers on the HTTP upgrade request. Continue them once at connection start —
they cover all turns on that connection:

```python theme={null}
async def ws_handler(websocket):
    await websocket.accept()
    session_id = websocket.query_params.get("session_id")

    with eldros_sdk.trace_context(dict(websocket.headers)):   # ← add this, once per connection
        while True:
            user_msg = await websocket.receive_text()

            with eldros_sdk.turn(user_msg, session_id=session_id) as t:
                reply = await agent.respond(user_msg)
                await websocket.send_text(reply)
                t.reply(reply)
```

On production connections (no Eldros headers) `trace_context` is a no-op — same handler for both.
When the headers are present, every span is stamped with:

* **`episode.id`** — links the trace to the specific test run
* **`traffic_type="simulation"`** — keeps test traffic out of your production views

<Note>
  For simulation, `t.reply()` is optional — Eldros already has the transcript from the
  platform side. `turn()` is still required so each LLM/tool span is linked to the correct
  turn, giving you a structured trace even without the client-side transcript.
</Note>

## 3. Integration modes

**Simulation + production observability (recommended)**\
Full transcript and traces for both production and eval runs:

```python theme={null}
eldros_sdk.init(traffic_type="prod")
# handler: trace_context + turn() + t.reply()
```

**Simulation only**\
Only export during Eldros-driven test runs. Production connections go through normally
but nothing is sent to the backend. `t.reply()` optional — platform has the transcript:

```python theme={null}
eldros_sdk.init(traffic_type="prod", simulation_only=True)
# handler: trace_context + turn() — t.reply() optional
```

**Production observability only**\
No simulation integration. Full transcript required since there is no platform-side record:

```python theme={null}
eldros_sdk.init(traffic_type="prod")
# handler: turn() + t.reply() — no trace_context needed
```

<Note>
  Traces without `turn()` — in any mode — cannot be correlated to specific conversation
  turns. The transcript is what gets judged; traces explain the verdict.
</Note>
