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

# Multi-turn Conversation

To send multiple user messages within the same session, use `QoderSDKClient` — it maintains a long-lived connection and lets you decide the next message based on the model's reply. For one-shot, stateless queries, use `query()` (see [Quick Start](/en/cli/sdk/python/quick-start)).

<div id="multi-message-session" />

<div id="multimessagesession" />

## Multi-message session

Each call to `client.query(...)` appends one turn of input; consume the reply to its end with `client.receive_response()`:

```python theme={null}
import anyio

from qoder_agent_sdk import (
    AssistantMessage,
    QoderAgentOptions,
    QoderSDKClient,
    ResultMessage,
    TextBlock,
    access_token_from_env,
)


async def main():
    options = QoderAgentOptions(auth=access_token_from_env())

    async with QoderSDKClient(options=options) as client:
        await client.query("What's the capital of France?")
        async for msg in client.receive_response():
            if isinstance(msg, AssistantMessage):
                for block in msg.content:
                    if isinstance(block, TextBlock):
                        print(f"Assistant: {block.text}")

        # Decide the next message from the previous reply
        await client.query("What's the population of that city?")
        async for msg in client.receive_response():
            if isinstance(msg, ResultMessage):
                print(f"Done: {msg.subtype}")


anyio.run(main)
```

<div id="managing-the-session-lifecycle" />

<div id="managingthesessionlifecycle" />

## Managing the session lifecycle

The connection lifecycle of `QoderSDKClient` is owned by the caller. Two ways to manage it:

<div id="automatic-management-recommended" />

<div id="automaticmanagementrecommended" />

### Automatic management (recommended)

Use this when the session's lifetime is bound to a function or block scope:

```python theme={null}
async with QoderSDKClient(options=options) as client:
    await client.query("Hello")
    async for msg in client.receive_response():
        ...
# Disconnects automatically when leaving the async with scope
```

<div id="manual-management" />

<div id="manualmanagement" />

### Manual management

Use this when the client is held by a long-lived object, or when closure must be triggered by an external condition (timeout, user cancellation, etc.):

```python theme={null}
client = QoderSDKClient(options=options)
await client.connect()

try:
    await client.query("Hello")
    async for msg in client.receive_response():
        ...
finally:
    await client.disconnect()
```
