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

# Response Shapes

> Pydantic type definitions for every response object the SDK returns. Use as a single source of truth when wiring response data through your application.

Every SDK method returns a Pydantic model. This page lists them all in one place so you can grep for field names without hunting through individual method docs.

<Note>
  **Type-specific field names.** The Pydantic models below intentionally use type-specific field names (`Preference.strength`, not `confidence`, and `Episode.summary`, not `content`) because each memory type has different semantics. The SDK handles transport-level field mapping internally; you only work with these typed models in application code.
</Note>

All types live in `maximem_synap` and are importable from the top-level package:

```python theme={null}
from maximem_synap import (
    Fact, Preference, Episode, Emotion, TemporalEvent,
    ContextResponse, ConversationContextModel, ResponseMetadata,
    CreateMemoryResponse, MemoryStatusResponse, IngestStatus, IngestMode,
    CompactionResponse, CompactionTriggerResponse, CompactionStatusResponse,
    ContextForPromptResponse, RecentMessage,
    CompactionLevel,
)
```

***

## Memory item types

These are the atomic units of structured memory. A `ContextResponse` is a bag of these.

### Fact

```python theme={null}
class Fact(BaseModel):
    id: str                                    # opaque identifier
    content: str                               # natural-language fact
    confidence: float                          # 0.0 - 1.0
    source: str                                # memory ID this fact was extracted from
    extracted_at: datetime
    metadata: Dict[str, Any] = {}
    event_date: Optional[datetime] = None      # when the fact became true, if known
    valid_until: Optional[datetime] = None     # when the fact stopped being true, if known
    temporal_category: Optional[str] = None    # "perpetual" | "temporal_fact" | "episode"
    temporal_confidence: float = 0.0
    source_evidence: Optional[List[str]] = None
```

### Preference

```python theme={null}
class Preference(BaseModel):
    id: str
    category: str                              # e.g., "communication", "dietary", "ui"
    content: str
    strength: float                            # 0.0 - 1.0: NOT named `confidence`
    source: str = ""
    extracted_at: datetime
    metadata: Dict[str, Any] = {}
    event_date: Optional[datetime] = None
    valid_until: Optional[datetime] = None
    temporal_category: Optional[str] = None
    temporal_confidence: float = 0.0
    source_evidence: Optional[List[str]] = None
```

### Episode

```python theme={null}
class Episode(BaseModel):
    id: str
    summary: str                               # narrative description: NOT `content`
    occurred_at: datetime
    significance: float                        # 0.0 - 1.0
    participants: List[str] = []               # entity IDs involved
    metadata: Dict[str, Any] = {}
    event_date: Optional[datetime] = None
    valid_until: Optional[datetime] = None
    temporal_category: Optional[str] = None
    temporal_confidence: float = 0.0
    source_evidence: Optional[List[str]] = None
```

### Emotion

```python theme={null}
class Emotion(BaseModel):
    id: str
    emotion_type: str                          # "frustrated" | "satisfied" | "confused" | …
    intensity: float                           # 0.0 - 1.0
    detected_at: datetime
    context: str                               # what triggered the emotion
    metadata: Dict[str, Any] = {}
    event_date: Optional[datetime] = None
    valid_until: Optional[datetime] = None
    temporal_category: Optional[str] = None
    temporal_confidence: float = 0.0
    source_evidence: Optional[List[str]] = None
```

### TemporalEvent

```python theme={null}
class TemporalEvent(BaseModel):
    id: str
    content: str
    event_date: datetime                       # REQUIRED: when the event occurred
    valid_until: Optional[datetime] = None
    temporal_category: str                     # REQUIRED: "perpetual" | "temporal_fact" | "episode"
    temporal_confidence: float                 # REQUIRED: 0.0 - 1.0
    confidence: float = 0.0
    source: str = ""
    extracted_at: Optional[datetime] = None
    metadata: Dict[str, Any] = {}
    source_evidence: Optional[List[str]] = None
```

***

## Context responses

### ContextResponse

Returned by `conversation.context.fetch`, `user.context.fetch`, `customer.context.fetch`, `client.context.fetch`.

```python theme={null}
class ContextResponse(BaseModel):
    facts: List[Fact] = []
    preferences: List[Preference] = []
    episodes: List[Episode] = []
    emotions: List[Emotion] = []
    temporal_events: List[TemporalEvent] = []
    metadata: ResponseMetadata

    # Optional rolling conversation context window (recent messages, summary)
    conversation_context: Optional[ConversationContextModel] = None
```

Iterate over all items in priority order:

```python theme={null}
for item in ctx.facts + ctx.preferences + ctx.episodes + ctx.emotions + ctx.temporal_events:
    print(item)
```

The atomized lists above are the primary surface. The optional `conversation_context` carries the rolling session view (compacted summary plus recent turns) as a single coherent block rather than atomized items. It is `None` unless the conversation has a compaction available.

### ConversationContextModel

The current-session context attached to a `ContextResponse` as `conversation_context`. It bundles the compacted narrative summary, current state, key extractions, and the most recent raw turns together, instead of splitting them into the typed item lists. It is `None` when no compacted/session context exists for the conversation (e.g. a fresh conversation).

```python theme={null}
class ConversationContextModel(BaseModel):
    summary: Optional[str] = None                                   # compacted narrative summary
    current_state: Dict[str, Any] = {}                              # rolling "where things stand" state
    key_extractions: Dict[str, List[Dict[str, Any]]] = {}           # grouped facts/decisions/preferences
    recent_turns: List[Dict[str, Any]] = []                         # most recent raw conversation turns
    compaction_id: Optional[str] = None                             # source compaction, if any
    compacted_at: Optional[str] = None                              # when that compaction ran
    conversation_id: Optional[str] = None
```

<Note>
  `conversation_context` is the coherent-block view; `facts` / `preferences` / `episodes` / `emotions` / `temporal_events` are the atomized view of retrieval. Most integrations read the atomized lists; reach for `conversation_context` when you want the pre-assembled session narrative. For prompt-ready compacted text specifically, prefer `get_context_for_prompt()` (see [Context Compaction](/sdk/context-compaction)).
</Note>

### ResponseMetadata

```python theme={null}
class ResponseMetadata(BaseModel):
    correlation_id: str                                 # log this on errors
    ttl_seconds: int                                    # local-cache validity
    source: str                                         # "cache", "cloud", or "anticipation"
    compaction_applied: Optional[CompactionLevel] = None  # enum if compaction ran, else None
    retrieved_at: datetime
```

`compaction_applied` is **not** a bool. It's `None` when no compaction ran, or a `CompactionLevel` enum value when one did. Test with `if meta.compaction_applied is not None`.

***

## Ingestion responses

### CreateMemoryResponse

Returned by `memories.create`. Ingestion is async: this comes back immediately with an `ingestion_id` you can poll.

```python theme={null}
class CreateMemoryResponse(BaseModel):
    ingestion_id: UUID                         # poll status with sdk.memories.status(ingestion_id)
    document_id: str
    status: IngestStatus                       # see enum below
    queued_at: datetime
    error_message: Optional[str] = None        # populated when status == FAILED
```

### IngestStatus enum

```python theme={null}
class IngestStatus(str, Enum):
    QUEUED = "queued"
    PROCESSING = "processing"
    COMPLETED = "completed"
    FAILED = "failed"
    PARTIAL_SUCCESS = "partial_success"
```

### MemoryStatusResponse

Returned by `memories.status(ingestion_id)`.

```python theme={null}
class MemoryStatusResponse(BaseModel):
    ingestion_id: UUID
    document_id: str
    status: IngestStatus
    queued_at: datetime
    started_at: Optional[datetime] = None
    completed_at: Optional[datetime] = None
    memories_created: int = 0
    memory_ids: List[str] = []                 # IDs of memories produced by this ingestion
    error_message: Optional[str] = None
```

***

## Compaction responses

### CompactionTriggerResponse

Returned by `conversation.context.compact`. This call **kicks off** a compaction job asynchronously and returns this trigger confirmation, **not** the compacted content. To get the actual compacted text, call `get_compacted()` once the job completes (or poll `get_compaction_status()`).

```python theme={null}
class CompactionTriggerResponse(BaseModel):
    compaction_id: str                         # poll status with get_compaction_status
    conversation_id: str
    status: str                                # e.g. "queued" | "in_progress"
    trigger_type: str                          # "manual" | "scheduled" | "threshold" | …
    initiated_at: datetime
    estimated_completion_seconds: Optional[int] = None

    # Populated when a prior compaction already existed for this conversation
    previous_context: Optional[str] = None
    previous_context_age_seconds: Optional[int] = None
    previous_compaction_id: Optional[str] = None
```

### CompactionResponse

Returned by `conversation.context.get_compacted`. Carries the actual compacted text and typed extractions.

```python theme={null}
class CompactionResponse(BaseModel):
    compacted_context: str                     # the actual compacted text
    original_token_count: int
    compacted_token_count: int
    compression_ratio: float
    level_applied: CompactionLevel
    metadata: ResponseMetadata

    compaction_id: Optional[str] = None
    strategy_used: Optional[str] = None
    validation_score: Optional[float] = None
    validation_passed: Optional[bool] = None
    quality_warning: Optional[bool] = None     # True if quality below threshold

    # Typed extractions surfaced from the underlying conversation
    facts: List[Dict[str, Any]] = []
    decisions: List[Dict[str, Any]] = []
    preferences: List[Dict[str, Any]] = []
    current_state: Optional[Dict[str, Any]] = None
```

### CompactionStatusResponse

Returned by `get_compaction_status`. **This is a Pydantic model: access fields as attributes, not dict keys.**

```python theme={null}
class CompactionStatusResponse(BaseModel):
    conversation_id: str
    status: str                                # "completed" | "in_progress" | "failed" | "none"
    compaction_id: Optional[str] = None
    completed_at: Optional[datetime] = None
    compression_ratio: Optional[float] = None
    validation_score: Optional[float] = None
    estimated_completion_seconds: Optional[int] = None
    error_message: Optional[str] = None
    latest_version: Optional[int] = None
    latest_created_at: Optional[datetime] = None
```

### ContextForPromptResponse

Returned by `get_context_for_prompt`. Optimized for direct injection into an LLM system prompt.

```python theme={null}
class ContextForPromptResponse(BaseModel):
    formatted_context: Optional[str] = None    # ready to splice into a system prompt
    available: bool = False                    # is there compacted context yet?
    is_stale: bool = False                     # new messages since the last compaction?
    compression_ratio: Optional[float] = None
    validation_score: Optional[float] = None
    compaction_age_seconds: Optional[int] = None
    quality_warning: bool = False              # default False, never None

    recent_messages: List[RecentMessage] = []
    recent_message_count: int = 0
    compacted_message_count: int = 0
    total_message_count: int = 0
```

### CompactionLevel enum

```python theme={null}
class CompactionLevel(str, Enum):
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"
    CONSERVATIVE = "conservative"
    BALANCED = "balanced"
    AGGRESSIVE = "aggressive"
    ADAPTIVE = "adaptive"
```

All seven values are equally canonical members of the enum.

***

## Type-checking tips

* Only `ContextResponse` and `CompactionResponse` have `model_config = {"extra": "allow"}` and expose the raw cloud payload via a `.raw` property; other models silently drop unknown fields. When the cloud adds a new field on those two models, you can read it from `response.raw` until a typed attribute ships.
* Datetime fields are timezone-aware (UTC). When comparing, use `datetime.now(timezone.utc)`, not `datetime.utcnow()`.
* For runtime validation (e.g., in your application boundary), call `.model_validate(...)` rather than constructing manually: Pydantic enforces all constraints.
