Files
ai-video-fullstack/backend/migrations/versions/20261023_0027_task_backend_resources.py
T

85 lines
4.4 KiB
Python
Raw Normal View History

"""Move task tools into task backend resources without replaying existing tasks."""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
revision = "20261023_0027"
down_revision = "20261023_0026"
branch_labels = None
depends_on = None
def upgrade():
op.create_table(
"task_backend_resources",
sa.Column("id", sa.String(40), primary_key=True),
sa.Column("name", sa.String(128), nullable=False),
sa.Column("type", sa.String(16), nullable=False),
sa.Column("description", sa.String(2048), nullable=False),
sa.Column("config", postgresql.JSONB(), nullable=False),
sa.Column("secrets", postgresql.JSONB(), nullable=False),
sa.Column("enabled", sa.Boolean(), nullable=False),
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
sa.CheckConstraint("type IN ('reasoner', 'opencode')", name="ck_task_backend_type"),
)
op.add_column("assistants", sa.Column("task_backend", postgresql.JSONB(), nullable=True))
op.add_column("background_tasks", sa.Column("backend_id", sa.String(40), nullable=False, server_default=""))
op.add_column("background_tasks", sa.Column("backend_type", sa.String(16), nullable=False, server_default="opencode"))
# NULL preserves pre-migration observation-window semantics for historical tasks.
op.add_column("background_tasks", sa.Column("deadline_at", sa.String(40), nullable=True))
op.alter_column("background_tasks", "tool_id", server_default="")
op.execute("""
DO $$ BEGIN
IF EXISTS (
SELECT b.assistant_id FROM assistant_tool_bindings b JOIN tools t ON t.id=b.tool_id
WHERE t.type='task' GROUP BY b.assistant_id HAVING count(*) > 1
) THEN RAISE EXCEPTION 'Task backend migration: an assistant has multiple task bindings; resolve before retrying'; END IF;
IF EXISTS (
SELECT 1 FROM assistant_tool_bindings b JOIN tools t ON t.id=b.tool_id
JOIN assistants a ON a.id=b.assistant_id
WHERE t.type='task' AND (a.type != 'prompt' OR a.runtime_mode != 'pipeline')
) THEN RAISE EXCEPTION 'Task backend migration: task bindings require Prompt Pipeline'; END IF;
END $$
""")
# Resource IDs may retain the old tool prefix: IDs are local to each resource table.
op.execute("""
INSERT INTO task_backend_resources (id,name,type,description,config,secrets,enabled,created_at,updated_at)
SELECT id,name,'opencode',description,
jsonb_build_object(
'url',definition->'config'->'url',
'directory',definition->'config'->'directory',
'username',COALESCE(definition->'config'->'username','\"opencode\"'::jsonb),
'timeout_seconds',COALESCE(definition->'config'->'timeout_seconds',definition->'config'->'timeoutSeconds','600'::jsonb),
'max_concurrency',1,'instructions','','agent','','model_provider_id','','model_id','','skills_note',''
), secrets,status='active',created_at,updated_at
FROM tools WHERE type='task'
""")
op.execute("""
UPDATE assistants a SET task_backend=jsonb_build_object(
'backend_id', b.tool_id,
'instruction_source',COALESCE(
b.config->'argument_bindings'->'instruction',
b.config->'argumentBindings'->'instruction',
'{"source":"model"}'::jsonb
),
'instructions',''
)
FROM assistant_tool_bindings b JOIN tools t ON t.id=b.tool_id
WHERE a.id=b.assistant_id AND t.type='task'
""")
op.execute("UPDATE background_tasks SET backend_id=tool_id, backend_type='opencode'")
op.execute("DELETE FROM assistant_tool_bindings WHERE tool_id IN (SELECT id FROM tools WHERE type='task')")
op.execute("DELETE FROM tools WHERE type='task'")
op.drop_constraint("ck_tools_external_type", "tools", type_="check")
op.create_check_constraint("ck_tools_external_type", "tools", "type IN ('http', 'mcp', 'client')")
def downgrade():
raise RuntimeError(
"Task backend resources cannot be downgraded safely to task tools. "
"Restore a pre-migration database backup to roll back this resource migration."
)