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

# Context & Memory

> Learn how context and memory work in the Corti Agentic Framework

A **context** in the Corti Agentic Framework makes use of memory from previous text and data in the conversation so far—think of it as a thread that maintains conversation history. Understanding how context works is essential for building effective integrations that maintain continuity across multiple messages.

<Frame>
  <img src="https://mintcdn.com/corti/en_RPjQCFb1qJpbU/images/agent-memory.svg?fit=max&auto=format&n=en_RPjQCFb1qJpbU&q=85&s=12ac969a8c68ef0a1b0dc18a49ea93e2" alt="Diagram showing orchestration flow in the agentic framework" width="773" height="507" data-path="images/agent-memory.svg" />
</Frame>

## What is Context?

A `Context` (identified by a server-generated `contextId`) is a logical grouping of related `Messages`, `Tasks`, and `Artifacts`, providing context across a multi-turn "conversation". It enables you to associate multiple tasks and agents with a single patient encounter, call, or workflow, ensuring continuity and proper scoping of shared knowledge throughout.

When you send a message **without** a `contextId`, the server generates one automatically. You can also supply your own `contextId` to continue an existing conversation—pass the same `contextId` you received from a previous response to maintain continuity across messages.

### Data Isolation and Scoping

**Contexts provide data isolation across users**: Data can **never** leak across users. Each `contextId` creates a conversation scope where messages, tasks, and artifacts are isolated from other users' contexts. This ensures:

* **Privacy and security**: Patient data from one encounter cannot accidentally be exposed to another encounter
* **Data integrity**: Information from different workflows remains properly separated
* **Compliance**: You can confidently scope sensitive data to specific contexts without risk of cross-contamination

<Warning>
  Contexts are scoped **per user**, not per agent. Any agent belonging to the same authenticated user can read any of that user's contexts. Do not rely on agent-level context isolation—if you need to restrict which agents can access which contexts, enforce that in your application layer.
</Warning>

When you need to share information across contexts, you must explicitly pass it via `DataPart` objects in your messages—there is no automatic data sharing between contexts.

## Using Context for Automatic Memory Management

The simplest way to use context is to let the framework automatically manage conversation memory:

### Workflow Pattern

1. **First message**: Send your message **without** a `contextId`. The server will create a new context automatically.
2. **Response**: The server's response includes the newly created `contextId`.
3. **Subsequent messages**: Include that `contextId` in your requests. Memory from previous messages in that context is automatically managed and available to the agent.

When you include a `contextId` in your request, the agent has access to all previous messages, artifacts, and state within **that specific context only**. Data from other contexts is completely isolated and inaccessible. This enables natural, continuous conversations without manually passing history, while maintaining strict data boundaries between different encounters or workflows.

### Standalone Requests

If you don't want automatic memory management, always send messages **without** a `contextId`. Each message will then be treated as a standalone request without access to prior conversation history. This is useful for:

* One-off queries that don't depend on prior context
* Testing and debugging individual requests
* Scenarios where you want explicit control over what context is included

## Passing Additional Context with Each Request

In addition to automatic memory management via `contextId`, you can pass additional context in each request by including `DataPart` objects in your message. This is useful when you want to provide specific structured data, summaries, or other context that should be considered for that particular request.

<Accordion title="Example: Passing additional context as DataPart">
  <CodeGroup>
    ```json theme={null}
    {
      "message": {
        "role": "user",
        "parts": [
          {
            "kind": "text",
            "text": "Generate a summary of this patient encounter"
          },
          {
            "kind": "data",
            "data": {
              "patientId": "pat_12345",
              "encounterDate": "2025-12-15",
              "chiefComplaint": "Chest pain",
              "vitalSigns": {
                "bloodPressure": "120/80",
                "heartRate": 72,
                "temperature": 98.6
              }
            }
          }
        ],
        "messageId": "550e8400-e29b-41d4-a716-446655440000",
        "kind": "message",
        "contextId": "ctx_abc123"
      }
    }
    ```
  </CodeGroup>
</Accordion>

This approach allows you to:

* Provide structured data (patient records, clinical facts, etc.) alongside text
* Include summaries or distilled information from external sources
* Pass metadata or configuration that should be considered for this specific request
* Combine automatic memory (via `contextId`) with explicit context (via `DataPart`)

## How Memory Works

The Corti Agentic Framework provides an optional memory system that agents can use to search for relevant past content using semantic similarity.

<Warning>
  Memory is **not** an automatic RAG pipeline. There is no automatic indexing of all content, no automatic semantic search on every message, and no automatic injection of retrieved context into the agent's prompt. Memory retrieval requires a memory MCP connector to be attached to the agent, and the LLM must decide to call the `search_memory` tool.
</Warning>

### Background Embedding

When an embedding client is configured (a deployment dependency, not guaranteed), user messages are embedded in the background for potential future retrieval. Agent responses are not embedded. DataParts carrying internal metadata markers (such as `$memoryType` or `$targetExpert`) are skipped.

### Explicit Retrieval via MCP Tool

If a memory MCP connector is attached to an agent, the agent's tool list includes a `search_memory` tool. The LLM decides whether to call this tool during processing—it is not called automatically. When the LLM calls `search_memory`, it performs semantic search across the context's embedded content and receives the results as a tool response, which it can then incorporate into its reasoning.

### What This Means in Practice

* Memory retrieval is **opt-in**: you need a memory MCP connector and the LLM must choose to call the tool
* Not all content is indexed: only user messages are embedded (when an embedding client is configured)
* There is no automatic context injection: the LLM receives tool results and incorporates them into its reasoning
* If no embedding client is configured or no memory connector is attached, the memory system is inactive

## Context vs. Reference Task IDs

The framework provides two mechanisms for linking related work:

* **`contextId`** – Groups multiple related `Messages`, `Tasks`, and `Artifacts` together (think of it as the encounter/call/workflow bucket). This provides automatic memory management and is sufficient for most use cases.

* **`referenceTaskIds`** – An optional list of specific past `Task` IDs within the same context that should be treated as explicit inputs or background. Note that `referenceTaskIds` are scoped to a context—they reference tasks within the same `contextId`.

**In most situations, you can ignore `referenceTaskIds`** since the automatic memory provided by `contextId` is sufficient. Only use `referenceTaskIds` when you need to explicitly direct the agent to pay attention to specific tasks or artifacts within the context, such as in complex multi-step workflows where you want to ensure certain outputs are prioritized.

<Accordion title="Example: Using referenceTaskIds in a message:send request">
  ```json theme={null}
  {
    "message": {
      "role": "user",
      "parts": [{ "kind": "text", "text": "Summarize the findings from the previous tasks." }],
      "messageId": "550e8400-e29b-41d4-a716-446655440001",
      "kind": "message",
      "contextId": "ctx_abc123",
      "referenceTaskIds": ["task-uuid-1", "task-uuid-2"]
    }
  }
  ```
</Accordion>

## Message:send Configuration

The `message:send` endpoint accepts an optional `configuration` object alongside the `message` object. This controls blocking behavior, history length, output modes, and push notifications.

<Accordion title="Example: message:send with configuration">
  ```json theme={null}
  {
    "message": {
      "role": "user",
      "parts": [{ "kind": "text", "text": "What was the patient's chief complaint?" }],
      "messageId": "550e8400-e29b-41d4-a716-446655440002",
      "kind": "message",
      "contextId": "ctx_abc123"
    },
    "configuration": {
      "blocking": true,
      "historyLength": 10,
      "acceptedOutputModes": ["text/plain"]
    }
  }
  ```
</Accordion>

### `blocking`

Controls whether the server waits for the task to complete before returning a response.

* **`true`** (default): The server waits for the task to complete and returns the final result.
* **`false`**: The server returns immediately after the first task event (non-blocking mode). Use this for long-running tasks where you want to poll for results later via the get-task endpoint.

### `historyLength`

Controls how many previous messages are included in the response.

<Warning>
  The default `historyLength` is **0** — no history is returned in the response. If you want conversation history included in the response, you must explicitly set `historyLength` to a positive value.
</Warning>

### `acceptedOutputModes`

An array of strings specifying the output MIME types the client accepts (for example, `["text/plain"]`).

### `pushNotificationConfig`

Optional configuration for push notifications. The agent card advertises `pushNotifications: false`, so this feature may not be fully implemented in all deployments.

## Context Management Endpoints

The v1 API provides two endpoints for managing contexts programmatically:

### List tasks in a context

```
GET /agents/{id}/v1/contexts/{contextId}?limit=50&offset=0
```

Returns the tasks belonging to a context, with `limit` and `offset` pagination. The agent ID in the path is not used for scoping—any agent belonging to the same authenticated user can read any of that user's contexts.

### Delete a context

```
DELETE /agents/{id}/v1/contexts/{contextId}
```

Deletes a context and scrubs all associated data. Returns 204 on success.

## Context Retention

Contexts are retained for a limited time. The current time-to-live (TTL) is approximately **30 days**, though this may vary by deployment configuration. After the TTL expires, the context and its associated data are automatically cleaned up.

<Note>The exact TTL depends on deployment configuration and may change. Contact your Corti representative for the current value in your environment.</Note>

## Context and Interaction IDs

If you're using contexts alongside Corti's internal interaction representation (for example, when integrating with Corti Assistant or other Corti products that use `interactionId`), note that **these two concepts are currently not linked**.

* **`contextId`** (from the Agentic Framework) and **`interactionId`** (from Corti's internal systems) are separate concepts that you will need to map yourself in your application.
* There is no automatic association between a Corti `interactionId` and an Agentic Framework `contextId`.

**Recommended approach:**

* **Use a fresh context per interaction**: When working with a Corti interaction, create a new `contextId` for that interaction. This keeps data properly scoped and isolated per interaction.
* Store the mapping between your `interactionId` and `contextId`(s) in your own application state or metadata.
* If you need to share data across multiple contexts within the same interaction, explicitly pass it via `DataPart` objects.

We're looking into ways to make the relationship between interactions and contexts more ergonomic if this is relevant to your use case. For now, maintaining your own mapping and using one context per interaction is the recommended pattern.

<Tip>
  For more details on how context relates to other core concepts, see [Core Concepts](/agentic/v1/core-concepts).
</Tip>

<Note>Please [contact us](mailto:help@corti.ai) if you need more information about context and memory in the Corti Agentic Framework.</Note>
