"""Track first-message idempotency and bounded, recoverable agent progress. Revision ID: 0004 Revises: 0003 """ from alembic import op import sqlalchemy as sa revision = "0004" down_revision = "0003" branch_labels = None depends_on = None def upgrade(): inspector = sa.inspect(op.get_bind()) if "first_request_id" not in {c["name"] for c in inspector.get_columns("conversations")}: op.add_column("conversations", sa.Column("first_request_id", sa.String(36), nullable=True)) if not any(item["column_names"] == ["first_request_id"] for item in sa.inspect(op.get_bind()).get_unique_constraints("conversations")): op.create_unique_constraint("uq_conversations_first_request_id", "conversations", ["first_request_id"]) columns = {c["name"] for c in inspector.get_columns("agent_runs")} if "tool_calls" not in columns: op.add_column("agent_runs", sa.Column("tool_calls", sa.JSON(), nullable=False, server_default="[]")) if "events" not in columns: op.add_column("agent_runs", sa.Column("events", sa.JSON(), nullable=False, server_default="[]")) def downgrade(): op.drop_column("agent_runs", "events") op.drop_column("agent_runs", "tool_calls") unique = next((item["name"] for item in sa.inspect(op.get_bind()).get_unique_constraints("conversations") if item["column_names"] == ["first_request_id"]), None) if unique: op.drop_constraint(unique, "conversations", type_="unique") op.drop_column("conversations", "first_request_id")