forked from HAL9000/cleveragents-core
127 lines
4.1 KiB
Python
127 lines
4.1 KiB
Python
"""Add sessions and session_messages tables.
|
|
|
|
This migration creates the two session persistence tables needed for
|
|
the Session service:
|
|
|
|
- ``sessions``: Persistent conversation threads tied to orchestrator actors.
|
|
- ``session_messages``: Ordered messages within a session conversation.
|
|
|
|
Revision ID: a7_001_session_persistence
|
|
Revises: c1_001_tool_registry
|
|
Create Date: 2026-02-14 12:00:00
|
|
|
|
"""
|
|
|
|
from collections.abc import Sequence
|
|
|
|
import sqlalchemy as sa
|
|
from alembic import op
|
|
|
|
# revision identifiers, used by Alembic.
|
|
revision: str = "a7_001_session_persistence"
|
|
down_revision: str | Sequence[str] | None = "c1_001_tool_registry"
|
|
branch_labels: str | Sequence[str] | None = None
|
|
depends_on: str | Sequence[str] | None = None
|
|
|
|
|
|
def upgrade() -> None:
|
|
"""Create sessions and session_messages tables."""
|
|
# --- sessions table ---
|
|
op.create_table(
|
|
"sessions",
|
|
# PK: ULID (26-char string)
|
|
sa.Column("session_id", sa.String(26), nullable=False),
|
|
# Optional actor binding
|
|
sa.Column("actor_name", sa.String(255), nullable=True),
|
|
# Namespace for session ownership
|
|
sa.Column(
|
|
"namespace",
|
|
sa.String(100),
|
|
nullable=False,
|
|
server_default="local",
|
|
),
|
|
# Session-level automation override
|
|
sa.Column("automation_level", sa.String(30), nullable=True),
|
|
# JSON: list of linked plan ULIDs
|
|
sa.Column("linked_plan_ids_json", sa.Text(), nullable=True),
|
|
# JSON: token usage tracking
|
|
sa.Column("token_usage_json", sa.Text(), nullable=True),
|
|
# JSON: arbitrary session metadata
|
|
sa.Column("metadata_json", sa.Text(), nullable=True),
|
|
# Timestamps (ISO-8601 strings)
|
|
sa.Column("created_at", sa.String(30), nullable=False),
|
|
sa.Column("updated_at", sa.String(30), nullable=False),
|
|
# Constraints
|
|
sa.PrimaryKeyConstraint("session_id"),
|
|
)
|
|
|
|
op.create_index(
|
|
"ix_sessions_created_at",
|
|
"sessions",
|
|
["created_at"],
|
|
unique=False,
|
|
)
|
|
op.create_index(
|
|
"ix_sessions_actor_name",
|
|
"sessions",
|
|
["actor_name"],
|
|
unique=False,
|
|
)
|
|
|
|
# --- session_messages table ---
|
|
op.create_table(
|
|
"session_messages",
|
|
# PK: ULID (26-char string)
|
|
sa.Column("message_id", sa.String(26), nullable=False),
|
|
# FK to sessions
|
|
sa.Column(
|
|
"session_id",
|
|
sa.String(26),
|
|
sa.ForeignKey(
|
|
"sessions.session_id",
|
|
ondelete="CASCADE",
|
|
name="fk_session_messages_session",
|
|
),
|
|
nullable=False,
|
|
),
|
|
# Message role: user | assistant | system | tool
|
|
sa.Column("role", sa.String(20), nullable=False),
|
|
# Message content (full text)
|
|
sa.Column("content", sa.Text(), nullable=False),
|
|
# Ordering index within the session
|
|
sa.Column("sequence", sa.Integer(), nullable=False),
|
|
# Message creation timestamp (ISO-8601 string)
|
|
sa.Column("timestamp", sa.String(30), nullable=False),
|
|
# JSON: optional message metadata
|
|
sa.Column("metadata_json", sa.Text(), nullable=True),
|
|
# Tool call identifier (required when role is 'tool')
|
|
sa.Column("tool_call_id", sa.String(255), nullable=True),
|
|
# Constraints
|
|
sa.PrimaryKeyConstraint("message_id"),
|
|
)
|
|
|
|
op.create_index(
|
|
"ix_session_messages_session_id",
|
|
"session_messages",
|
|
["session_id"],
|
|
unique=False,
|
|
)
|
|
op.create_index(
|
|
"ix_session_messages_sequence",
|
|
"session_messages",
|
|
["session_id", "sequence"],
|
|
unique=False,
|
|
)
|
|
|
|
|
|
def downgrade() -> None:
|
|
"""Drop sessions and session_messages tables."""
|
|
# Drop in reverse FK order: messages -> sessions
|
|
op.drop_index("ix_session_messages_sequence", table_name="session_messages")
|
|
op.drop_index("ix_session_messages_session_id", table_name="session_messages")
|
|
op.drop_table("session_messages")
|
|
|
|
op.drop_index("ix_sessions_actor_name", table_name="sessions")
|
|
op.drop_index("ix_sessions_created_at", table_name="sessions")
|
|
op.drop_table("sessions")
|