Portal Community

What Is an Episode?

In Octopus terminology, an episode is a single unit of episodic memory — one conversational turn. When a user sends a message, that message is an episode. When the agent replies, that reply is another episode. When the agent makes a tool call, the tool call request and response are recorded as episodes.

This fine-grained recording enables the memory system to reconstruct any conversation in precise detail, perform semantic recall of specific past interactions, and provide an auditable log of every agent action.

Column Reference

ColumnTypeConstraintsDescription
EpisodeIduniqueidentifierPK, NOT NULLGUID primary key. Generated using NEWSEQUENTIALID() for clustered index efficiency.
SessionIduniqueidentifierFK, NOT NULLReferences the parent conversation in Octopus_Conversations.
TenantIdintNOT NULL, IXMulti-tenancy discriminator. Present on every episode for direct tenant-scoped queries without requiring a join to Conversations.
Rolenvarchar(50)NOT NULLThe speaker role for this episode: user, assistant, system, tool.
Messagesvarbinary(max)NOT NULLGZip-compressed JSON array of message content objects. Decompressed by the EF Core value converter on read.
ToolCallsvarbinary(max)NULLGZip-compressed JSON of tool/function call records. Only populated for tool role episodes.
EmbeddingRefnvarchar(500)NULLID in the vector store pointing to the embedding generated for this episode's content. Used for semantic recall lookup.
Timestampdatetime2NOT NULLUTC time when this episode was created. Used for chronological ordering and retention windowing.
TokenCountintNULLApproximate token count of this episode's content. Used by the context window manager to stay within model limits.

Messages JSON Structure

The Messages column (after decompression) contains a JSON array of message objects following the OpenAI/chat completion message format:

[
  {
    "role": "user",
    "content": "What is the status of my order #ORD-8821?",
    "name": null
  }
]

For multi-part messages (e.g., text + image), the content field is an array of content parts:

[
  {
    "role": "user",
    "content": [
      { "type": "text", "text": "Analyze this chart:" },
      { "type": "image_url", "image_url": { "url": "data:image/png;base64,..." } }
    ]
  }
]

ToolCalls JSON Structure

Tool call episodes record both the function call request (from the model) and the function result (returned to the model):

{
  "toolCallId": "call_abc123",
  "functionName": "get_order_status",
  "arguments": { "orderId": "ORD-8821" },
  "result": {
    "status": "shipped",
    "carrier": "FedEx",
    "trackingNumber": "1Z999AA1012345678",
    "estimatedDelivery": "2026-05-27"
  },
  "durationMs": 142,
  "isError": false
}

Role Values

RoleSourceHas ToolCallsDescription
userHumanNoThe human's message to the agent
assistantAI ModelSometimesThe agent's response — may include tool call requests inline
systemFrameworkNoSystem-injected context (e.g., memory summaries injected mid-conversation)
toolFrameworkYesThe result returned from a tool/function call execution

Embedding Reference and Semantic Recall

When an episode is stored, the Octopus memory system asynchronously generates a vector embedding of the episode content and stores it in the configured vector store (Qdrant or PGVector). The EmbeddingRef column records the vector store's internal ID for that embedding.

During semantic recall (when a new user message triggers a search for relevant past episodes), the flow is:

1

Query Embedding

The user's new message is embedded into a vector using the same model that embedded past episodes.

2

Vector Search

The vector store finds the top-K most semantically similar episode embeddings and returns their EmbeddingRef IDs.

3

SQL Lookup

The returned IDs are used to query Octopus_Episodes WHERE EmbeddingRef IN (@ids) AND TenantId = @tenantId to retrieve the full message text for injection into the context window.

EmbeddingRef Can Be Null

Short episodes (under a minimum token threshold), system injections, and tool result episodes may not have embeddings generated. The memory system skips semantic recall for episodes without an EmbeddingRef. This is by design — embedding every token would waste vector store capacity on low-value data.

Volume Considerations

Octopus_Episodes is by far the highest-volume table. In a production multi-tenant deployment with 100 active agents each handling 50 conversations per day averaging 20 turns per conversation, you get approximately 100,000 new episode rows per day. At an average compressed size of 2KB per row, that is 200MB of new data daily before archival kicks in.

The MemoryRetentionJob runs nightly and moves episodes older than the configured TTL to an archive table, keeping the active table query-fast. See the Maintenance page for details.