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

# Session

> A group of inference results that make up a full conversation

## What is a Session?

A session groups the turns of a single conversation between a user and your AI product. It contains one or more [inference results](/concepts/product/version/session/inference-result) (input/output pairs) and can be evaluated as a whole using conversational metrics.

You create sessions explicitly with `sessions.create()` for full control over session lifecycle and grouping. If you give a session your own `custom_id`, you can then reference it by that id when [creating an inference result](/sdk/api/inference-result/create): pass it as `session_custom_id` (with a `version_id` or `product_id` anchor) and Galtea appends the turn to that existing session. Production sessions can also be created automatically by ingesting OpenTelemetry traces; see [Monitor Real User Traffic via OpenTelemetry](/sdk/tutorials/monitor-real-user-traffic-with-opentelemetry).

You can create, view, and manage sessions programmatically using the [Galtea SDK](/sdk/api/session/service).

## SDK Integration

<Card title="Session Service SDK" icon="clock-rotate-left" iconType="solid" href="/sdk/api/session/service">
  Manage sessions using the Python SDK
</Card>

## Session Properties

<ResponseField name="Custom ID" type="Text" required>
  The custom ID associated with the session.
  This is usually a client-side generated ID that identifies the conversation session between a user and a LLM app.
  It is unique per version: logging an inference result with a `session_custom_id` finds the existing session with that custom ID and appends to it (see [Create Inference Result](/sdk/api/inference-result/create)).
</ResponseField>

<ResponseField name="Version" type="Version" required>
  The version associated with the session.
</ResponseField>

<ResponseField name="Test Case" type="Test Case" optional>
  The test case associated with the session. This is typically used for non-production evaluations.
</ResponseField>

<ResponseField name="Is Production" type="Boolean" optional>
  Indicates whether the session represents real production traffic. Defaults to `True` when `test_case_id` is omitted at creation and `False` when a `test_case_id` is provided. Externally-ingested sessions (e.g. imported traces) may be classified as non-production without supplying a `test_case_id`. The only forbidden combination is `test_case_id` set together with `is_production=True`. When `test_case_id` is set, the session `context` is derived from the test case; otherwise the `context` from the request is used directly.
</ResponseField>

<ResponseField name="Context" type="Text" optional>
  The context provided to the AI product during the session or ground-truth related context. For production sessions, this value is taken from the request. For non-production sessions, it is derived from the linked test case.
</ResponseField>

<ResponseField name="Metadata" type="Object" optional>
  Additional custom metadata about the session. This can be used to store any relevant information that doesn't fit into the other fields.
</ResponseField>

<ResponseField name="Status" type="Enum">
  The lifecycle state of the session, and the single signal for whether it is open or closed.

  * `PENDING` (**open**): the session accepts new turns. Every session starts here.
  * `COMPLETED` (**closed**): the session finished successfully and accepts no new turns.
  * `FAILED` (**closed**): the session ended with an error and accepts no new turns.

  A session stays `PENDING` until it closes. It closes when you finish it explicitly with [`sessions.finish()`](/sdk/api/session/finish), or when the product's auto-close setting closes it after a window of inactivity. On a default-configured product, calling `finish()` is the normal way to complete a session. See [Session Lifecycle](#session-lifecycle) for the full open/closed model and what happens to a turn that arrives after the session closes.
</ResponseField>

<ResponseField name="Stopping Reason" type="Text" optional>
  Human-readable text describing why the conversation ended, for example "Automatically closed after 30 minutes of inactivity". It is a label for people to read: it does not lock the session or drive any behavior. The session `Status` alone decides whether the session is open or closed.
</ResponseField>

<ResponseField name="Error" type="Text" optional>
  Any error message associated with the session. This is useful for tracking failed sessions or sessions that encountered issues.
</ResponseField>

<ResponseField name="Recording URI" type="Text" optional>
  The canonical storage URI of the full-call recording for telephony sessions. This field is read-only and populated by the API after a phone-call session's recording is captured and processed. Null for non-telephony sessions or before the recording is available. Resolve to a playable URL via the storage endpoint.
</ResponseField>

## Session Lifecycle

A session is either **open** or **closed**, and its `Status` is the single source of truth for which one it is:

* **Open** (`PENDING`): the session accepts new turns. Every new session starts open by default.
* **Closed** (`COMPLETED` or `FAILED`): the session accepts no new turns.

### How a session closes

A session becomes closed in one of two ways:

* **Explicit finish.** You end the session on purpose, and it closes right away. Call [`sessions.finish()`](/sdk/api/session/finish) from the SDK: it records a `Stopping Reason` and sets the status to `COMPLETED`. The endpoint behind it (`PATCH /sessions/{id}/finish`) also accepts an `error` instead, which closes the session as `FAILED`.
* **Auto-close sweep.** Galtea runs a background job that closes quiet sessions for you. It closes an open session once its most recent inference result is older than the product's inactivity window, and writes a `Stopping Reason` such as "Automatically closed after 30 minutes of inactivity" so you can tell an auto-close from an explicit finish. The sweep only closes open sessions; it never changes one that is already closed.

You configure auto-close per product with three fields: **Auto Close Scope** (which sessions the sweep closes: `NONE`, `DEVELOPMENT`, `PRODUCTION`, or `ALL`), **Auto Close Inactivity Minutes** (the quiet window), and **Closed Session Inference Creation Policy** (what happens to a late turn, see below). See the [Product properties](/concepts/product#product-properties) for the exact fields and defaults; set them from the API or the dashboard. By default the scope is `PRODUCTION`, so production sessions auto-close after the window while development (test) sessions stay open until you finish them.

### Turns that arrive after a session closes

When a new inference result arrives for a closed session, the product's **Closed Session Inference Creation Policy** decides what happens:

* `IGNORE` (the default): the API accepts the call, returns success, and stores nothing. The late turn is silently dropped.
* `REJECT`: the API refuses the call and returns an error.

If your users sometimes reply after a long gap and you do not want those late turns dropped or rejected, raise the inactivity window or set the scope so those sessions are not auto-closed. The [Monitor Production Responses](/sdk/tutorials/monitor-production-responses-to-user-queries#late-turns-on-a-closed-session) tutorial walks through this trade-off.

## Related

<CardGroup cols={3}>
  <Card title="Concepts overview" icon="diagram-project" iconType="solid" href="/concepts/overview">
    How Galtea's concepts connect — diagram + per-entity quick reference.
  </Card>

  <Card title="Evaluation" icon="clipboard-check" href="/concepts/product/version/session/evaluation">
    Learn how evaluations score inference results within a session.
  </Card>

  <Card title="Inference Result" icon="message-bot" href="/concepts/product/version/session/inference-result">
    Understand the input/output pairs that make up a session.
  </Card>

  <Card title="Simulating Conversations" icon="comments" href="/sdk/tutorials/simulating-conversations">
    Tutorial on running multi-turn conversation simulations.
  </Card>
</CardGroup>
