Portal Community

Octopus_Episodes

Stores one row per completed conversation session (episodic memory):

CREATE TABLE Octopus_Episodes (
    EpisodeId        UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID(),
    TenantId         UNIQUEIDENTIFIER NOT NULL,
    AgentId          UNIQUEIDENTIFIER NOT NULL,
    UserId           NVARCHAR(256)    NOT NULL,
    StartedAt        DATETIME2        NOT NULL,
    EndedAt          DATETIME2        NULL,
    Summary          NVARCHAR(MAX)    NULL,
    KeyFactsJson     NVARCHAR(MAX)    NULL,   -- JSON array of strings
    Embedding        VARBINARY(MAX)   NULL,   -- float[] serialized as bytes
    IsDeleted        BIT              NOT NULL DEFAULT 0,
    DeletedAt        DATETIME2        NULL,
    CreatedAt        DATETIME2        NOT NULL DEFAULT SYSUTCDATETIME(),

    CONSTRAINT PK_Octopus_Episodes PRIMARY KEY (EpisodeId)
);

CREATE INDEX IX_Episodes_AgentUser    ON Octopus_Episodes (AgentId, UserId, TenantId) WHERE IsDeleted = 0;
CREATE INDEX IX_Episodes_EndedAt      ON Octopus_Episodes (EndedAt DESC)              WHERE IsDeleted = 0;
CREATE INDEX IX_Episodes_TenantDelete ON Octopus_Episodes (TenantId, IsDeleted, DeletedAt);

Octopus_EpisodeMessages

Stores individual messages within an episode (for full episode recall):

CREATE TABLE Octopus_EpisodeMessages (
    MessageId   UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID(),
    EpisodeId   UNIQUEIDENTIFIER NOT NULL,
    TenantId    UNIQUEIDENTIFIER NOT NULL,
    Role        NVARCHAR(20)     NOT NULL,  -- 'user' | 'assistant' | 'tool'
    Content     NVARCHAR(MAX)    NOT NULL,
    TokenCount  INT              NULL,
    CreatedAt   DATETIME2        NOT NULL DEFAULT SYSUTCDATETIME(),

    CONSTRAINT PK_Octopus_EpisodeMessages PRIMARY KEY (MessageId),
    CONSTRAINT FK_EpisodicMessages_Episode FOREIGN KEY (EpisodeId)
        REFERENCES Octopus_Episodes (EpisodeId) ON DELETE CASCADE
);

CREATE INDEX IX_EpisodeMessages_Episode ON Octopus_EpisodeMessages (EpisodeId, CreatedAt);

Octopus_Procedures

Stores procedural memory — admin-defined and agent-learned step sequences:

CREATE TABLE Octopus_Procedures (
    ProcedureId    UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID(),
    TenantId       UNIQUEIDENTIFIER NOT NULL,
    AgentId        UNIQUEIDENTIFIER NULL,      -- NULL = shared across tenant agents
    Name           NVARCHAR(200)    NOT NULL,
    Description    NVARCHAR(MAX)    NULL,
    TriggerPattern NVARCHAR(500)    NULL,      -- Regex trigger pattern
    StepsJson      NVARCHAR(MAX)    NOT NULL,  -- JSON array of ProcedureStep
    Embedding      VARBINARY(MAX)   NULL,      -- float[] for semantic matching
    IsActive       BIT              NOT NULL DEFAULT 1,
    IsApproved     BIT              NOT NULL DEFAULT 0,
    Version        INT              NOT NULL DEFAULT 1,
    CreatedAt      DATETIME2        NOT NULL DEFAULT SYSUTCDATETIME(),
    UpdatedAt      DATETIME2        NOT NULL DEFAULT SYSUTCDATETIME(),
    CreatedBy      NVARCHAR(256)    NULL,

    CONSTRAINT PK_Octopus_Procedures PRIMARY KEY (ProcedureId)
);

CREATE INDEX IX_Procedures_Agent   ON Octopus_Procedures (AgentId, TenantId) WHERE IsActive = 1 AND IsApproved = 1;
CREATE INDEX IX_Procedures_Shared  ON Octopus_Procedures (TenantId)          WHERE AgentId IS NULL AND IsActive = 1;

Octopus_Agents

Stores agent configuration (the AgentComposite data):

CREATE TABLE Octopus_Agents (
    AgentId      UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID(),
    TenantId     UNIQUEIDENTIFIER NOT NULL,
    Name         NVARCHAR(200)    NOT NULL,
    SystemPrompt NVARCHAR(MAX)    NOT NULL,
    LLMProvider  NVARCHAR(50)     NOT NULL,   -- 'Anthropic' | 'OpenAI' | 'AzureOpenAI' | 'Ollama'
    Model        NVARCHAR(100)    NOT NULL,
    LLMConfigJson   NVARCHAR(MAX) NULL,       -- Temperature, MaxTokens etc.
    MemoryConfigJson NVARCHAR(MAX) NULL,      -- AgentMemoryConfig as JSON
    IsActive     BIT              NOT NULL DEFAULT 1,
    CreatedAt    DATETIME2        NOT NULL DEFAULT SYSUTCDATETIME(),
    UpdatedAt    DATETIME2        NOT NULL DEFAULT SYSUTCDATETIME(),

    CONSTRAINT PK_Octopus_Agents PRIMARY KEY (AgentId)
);

CREATE UNIQUE INDEX UX_Agents_TenantName ON Octopus_Agents (TenantId, Name) WHERE IsActive = 1;
CREATE INDEX        IX_Agents_Tenant     ON Octopus_Agents (TenantId)        WHERE IsActive = 1;

Column Summary

Column PatternPurposePresent In
TenantIdMulti-tenant isolation — all queries filter by thisAll tables
IsDeleted + DeletedAtSoft delete — records hidden from queries before hard purgeEpisodes
IsActiveLogical enable/disable without deletionProcedures, Agents
EmbeddingSerialized float[] for semantic similarity matchingEpisodes, Procedures
*Json columnsSchemaless extension data stored as JSONProcedures (Steps), Agents (Config)
CreatedAt / UpdatedAtAudit trail timestamps (UTC)All tables
Migrations Are Automatic

All tables are created and updated by EF Core migrations included in the SqlServerPlugin assembly. You do not need to run DDL scripts manually — the plugin applies all pending migrations on startup via db.Database.MigrateAsync().