# Session ID

Every session has a unique `session_id` (UUID v4) automatically generated and attached to the metadata of every event in that session. No configuration is required.

## When a new `session_id` is generated

| Trigger | Description |
| --- | --- |
| Brand new conversation | First event on a tracker |
| `action_session_start` / `SessionStarted` | A new session starts |
| `ConversationResumed` | Explicit resumption after inactivity |
| `UserUttered` on an inactive tracker | User reactivates an inactive conversation |

## `session_id` in event metadata

All events within the same session share the same `session_id`. A new session carries a new UUID.

```json
{
  "event": "user",
  "text": "Hello",
  "metadata": {
    "session_id": "4b3c1e2a-91f0-4d8e-b123-abc123def456"
  }
}
```

## `current_session_id` on the tracker

The tracker also exposes a `current_session_id` field, so you can read the active session ID at any point during the conversation:

```json
{
  "sender_id": "conversation_12345",
  "current_session_id": "4b3c1e2a-91f0-4d8e-b123-abc123def456",
  "events": [...] 
}
```

# Conversation Lifecycle Events

## `ConversationInactive`

`ConversationInactive` marks a conversation as **inactive but resumable**. It is emitted automatically by the session timer when the inactivity timeout elapses.

**Tracker effects:**

- `inactive = true` is set on the tracker.
- The conversation continues to accept new events.
- The inactive state is cleared when a `UserUttered` or `ConversationResumed` event is received.

## `SessionEnded`

`SessionEnded` marks a conversation as **permanently terminated**. No further events can be appended after this point.

**Tracker effects:**

- `terminated = true` is set on the tracker.
- All subsequent attempts to append events are rejected.
- The session timer is cancelled immediately.

### How to trigger `SessionEnded`

**Via a custom action:**

```python
from rasa_sdk import Action, Tracker
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk.events import SessionEnded

class ActionEndSession(Action):
    def name(self):
        return "action_end_session"

async def run(self, dispatcher, tracker: Tracker, domain):
        return [SessionEnded()]
```

When a custom action returns `SessionEnded`, Rasa stops the prediction loop and flow executor immediately. No further actions are predicted or executed.

**Via the REST API:**

```bash
curl -X POST http://localhost:5005/conversations/{conversation_id}/tracker/events \
-H "Content-Type: application/json" \
-d '{"event": "session_ended"}'
```

When `SessionEnded` is posted via the API, the session timer is cancelled unconditionally, regardless of whether `execute_side_effects` is set. If an A2A sub agent task is running in the background, it is also cancelled.

Likewise, posting a `ConversationInactive` event through the same endpoint cancels in-flight background A2A processing for that conversation.

## Comparison

| Event | Tracker state | Resumable | Triggered by | Further events |
| --- | --- | --- | --- | --- |
| `ConversationInactive` | `inactive = true` | Yes | Inactivity timer | Accepted |
| `SessionEnded` | `terminated = true` | No | Custom action or REST API | Rejected.
