"""init_sqlite_agent_v0.1.2

Revision ID: f458c7fb17a5
Revises: 
Create Date: 2026-01-26 20:22:31.634254

"""
from typing import Sequence, Union

from alembic import op
from openjiuwen_studio.core.database.migration_utils import table_exists, column_exists, index_exists

import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision: str = 'f458c7fb17a5'
down_revision: Union[str, Sequence[str], None] = None
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
    """Upgrade schema."""
    # ### commands auto generated by Alembic - please adjust! ###
    if not table_exists('agent'):
        op.create_table('agent',
        sa.Column('agent_id', sa.String(length=100), nullable=False),
        sa.Column('agent_version', sa.String(length=100), nullable=True),
        sa.Column('latest_publish_time', sa.BigInteger(), nullable=True),
        sa.Column('latest_publish_version', sa.String(length=100), nullable=True),
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
        sa.Column('space_id', sa.String(length=100), nullable=False),
        sa.Column('agent_name', sa.String(length=255), nullable=True),
        sa.Column('description', sa.String(length=2000), nullable=True),
        sa.Column('agent_type', sa.String(length=100), nullable=True),
        sa.Column('icon', sa.String(length=100), nullable=True),
        sa.Column('edit_mode', sa.String(length=100), nullable=True),
        sa.Column('prompt_template_name', sa.String(length=100), nullable=True),
        sa.Column('auto_generated_prompt', sa.String(length=2000), nullable=True),
        sa.Column('opening_remarks', sa.String(length=2000), nullable=True),
        sa.Column('default_response', sa.String(length=2000), nullable=True),
        sa.Column('configs', sa.JSON(), nullable=True),
        sa.Column('plugins', sa.JSON(), nullable=True),
        sa.Column('workflows', sa.JSON(), nullable=True),
        sa.Column('model', sa.JSON(), nullable=True),
        sa.Column('prompt_template', sa.JSON(), nullable=True),
        sa.Column('constraint', sa.JSON(), nullable=True),
        sa.Column('prompt_tuning', sa.JSON(), nullable=True),
        sa.Column('triggers', sa.JSON(), nullable=True),
        sa.Column('knowledge', sa.JSON(), nullable=True),
        sa.Column('memory', sa.JSON(), nullable=True),
        sa.Column('_rest_', sa.JSON(), nullable=True),
        sa.Column('create_time', sa.BigInteger(), nullable=True),
        sa.Column('update_time', sa.BigInteger(), nullable=True),
        sa.PrimaryKeyConstraint('id'),
        sa.UniqueConstraint('agent_id', 'agent_version', name='uix_agent_id_version')
        )
    with op.batch_alter_table('agent', schema=None) as batch_op:
        if not index_exists('agent', 'ix_agent_agent_id_agent'):
            batch_op.create_index('ix_agent_agent_id_agent', ['agent_id'], unique=True)

    if not table_exists('agent_execution'):
        op.create_table('agent_execution',
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
        sa.Column('space_id', sa.String(length=100), nullable=False),
        sa.Column('agent_id', sa.String(length=100), nullable=False),
        sa.Column('agent_version', sa.String(length=100), nullable=True, comment='agent version. empty if is draft'),
        sa.Column('trace_id', sa.String(length=100), nullable=False, comment='the trace id of this execution'),
        sa.Column('status', sa.String(length=16), nullable=True,
                   comment='finish/start/error/running/interrupted/unknown'),
        sa.Column('mode', sa.Integer(), nullable=True, comment='the execution mode: 0. debug run 1. release run'),
        sa.Column('call_type', sa.String(length=100), nullable=True,
                   comment='The caller type that initiated this execution'),
        sa.Column('duration', sa.Integer(), nullable=True, comment='execution duration in millisecond'),
        sa.Column('inputs', sa.JSON(), nullable=True, comment='inputs of this execution'),
        sa.Column('outputs', sa.JSON(), nullable=True, comment='outputs of this execution'),
        sa.Column('error_code', sa.Integer(), nullable=True, comment='error code'),
        sa.Column('fail_reason', sa.Text(), nullable=True, comment='the reason for failure'),
        sa.Column('input_tokens', sa.Integer(), nullable=True, comment='number of input tokens'),
        sa.Column('output_tokens', sa.Integer(), nullable=True, comment='number of output tokens'),
        sa.Column('execute_info_list', sa.JSON(), nullable=True, comment="agent's components' execute info"),
        sa.Column('create_time', sa.DateTime(), nullable=True, comment='创建时间'),
        sa.Column('update_time', sa.DateTime(), server_default=sa.text('(CURRENT_TIMESTAMP)'),
                   nullable=True, comment='更新时间'),
        sa.PrimaryKeyConstraint('id'),
        comment='某次agent执行的总结信息'
        )
    with op.batch_alter_table('agent_execution', schema=None) as batch_op:
        if not index_exists('agent_execution', 'agent_id_version_agent_execution'):
            batch_op.create_index('agent_id_version_agent_execution', ['agent_id', 'agent_version'], unique=False)
        if not index_exists('agent_execution', 'idx_agent_agent_execution'):
            batch_op.create_index(
            'idx_agent_agent_execution', ['space_id', 'agent_id', 'agent_version'],
            unique=False
            )
        if not index_exists('agent_execution', 'ix_agent_execution_trace_id_agent_execution'):
            batch_op.create_index(
            'ix_agent_execution_trace_id_agent_execution', ['trace_id'], unique=True
            )

    if not table_exists('agent_workflow_relation'):
        op.create_table('agent_workflow_relation',
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
        sa.Column('space_id', sa.String(length=100), nullable=False),
        sa.Column('agent_id', sa.String(length=100), nullable=False),
        sa.Column('agent_version', sa.String(length=100), nullable=False),
        sa.Column('workflow_id', sa.String(length=100), nullable=False),
        sa.Column('workflow_version', sa.String(length=100), nullable=False),
        sa.Column('create_time', sa.BigInteger(), nullable=True),
        sa.Column('update_time', sa.BigInteger(), nullable=True),
        sa.PrimaryKeyConstraint('id'),
        sa.UniqueConstraint('space_id', 'agent_id', 'agent_version', 'workflow_id',
                           'workflow_version', name='uix_agent_workflow_relation')
        )
    with op.batch_alter_table('agent_workflow_relation', schema=None) as batch_op:
        if not index_exists('agent_workflow_relation', 'idx_agent_agent_workflow_relation'):
            batch_op.create_index(
            'idx_agent_agent_workflow_relation', ['space_id', 'agent_id', 'agent_version'],
            unique=False
            )
        if not index_exists('agent_workflow_relation', 'idx_workflow_agent_workflow_relation'):
            batch_op.create_index(
            'idx_workflow_agent_workflow_relation', ['space_id', 'workflow_id',
            'workflow_version'], unique=False
            )

    if not table_exists('embedding_model_configs'):
        op.create_table('embedding_model_configs',
        sa.Column('id', sa.Integer(), nullable=False),
        sa.Column('model_name', sa.String(length=100), nullable=False),
        sa.Column('space_id', sa.String(length=50), nullable=False),
        sa.Column('protocol', sa.String(length=50), nullable=False),
        sa.Column('model_id', sa.String(length=100), nullable=False),
        sa.Column('api_key', sa.Text(), nullable=True),
        sa.Column('api_base', sa.String(length=500), nullable=False),
        sa.Column('max_batch_size', sa.Integer(), nullable=False),
        sa.Column('is_active', sa.Boolean(), nullable=True),
        sa.Column('created_at', sa.DateTime(timezone=True),
                   server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=True),
        sa.Column('updated_at', sa.DateTime(timezone=True),
                   server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=True),
        sa.PrimaryKeyConstraint('id')
        )
    with op.batch_alter_table('embedding_model_configs', schema=None) as batch_op:
        if not index_exists('embedding_model_configs', 'ix_embedding_model_configs_id_embedding_model_configs'):
            batch_op.create_index(
            'ix_embedding_model_configs_id_embedding_model_configs', ['id'],
            unique=False
            )
        if not index_exists('embedding_model_configs', 'ix_embedding_model_configs_is_active_embedding_model_configs'):
            batch_op.create_index(
            'ix_embedding_model_configs_is_active_embedding_model_configs', ['is_active'],
            unique=False
            )
        if not index_exists('embedding_model_configs', 'ix_embedding_model_configs_model_name_embedding_model_configs'):
            batch_op.create_index(
            'ix_embedding_model_configs_model_name_embedding_model_configs',
            ['model_name'], unique=False
            )
        if not index_exists('embedding_model_configs', 'ix_embedding_model_configs_protocol_embedding_model_configs'):
            batch_op.create_index(
            'ix_embedding_model_configs_protocol_embedding_model_configs', ['protocol'],
            unique=False
            )
        if not index_exists('embedding_model_configs', 'ix_embedding_model_configs_space_id_embedding_model_configs'):
            batch_op.create_index(
            'ix_embedding_model_configs_space_id_embedding_model_configs', ['space_id'],
            unique=False
            )

    if not table_exists('knowledge_base'):
        op.create_table('knowledge_base',
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
        sa.Column('space_id', sa.String(length=100), nullable=False, comment='空间ID，用于多租户隔离'),
        sa.Column('kb_id', sa.String(length=100), nullable=False, comment='知识库ID，唯一标识'),
        sa.Column('name', sa.String(length=100), nullable=False, comment='知识库名称'),
        sa.Column('description', sa.Text(), nullable=True, comment='知识库描述'),
        sa.Column('embedding_model_config_id', sa.Integer(), nullable=True,
                   comment='Embedding 模型配置ID，知识库创建时选择，后续不可更改'),
        sa.Column('config', sa.JSON(), nullable=True, comment='知识库配置信息'),
        sa.Column('_rest_', sa.JSON(), nullable=True, comment='扩展字段，存储其他未定义的数据'),
        sa.Column('create_time', sa.BigInteger(), nullable=True, comment='创建时间'),
        sa.Column('update_time', sa.BigInteger(), nullable=True, comment='更新时间'),
        sa.PrimaryKeyConstraint('id'),
        sa.UniqueConstraint('kb_id', name='uix_kb_id'),
        comment='知识库表，存储知识库基本信息'
        )
    with op.batch_alter_table('knowledge_base', schema=None) as batch_op:
        if not index_exists('knowledge_base', 'idx_space_id_knowledge_base'):
            batch_op.create_index('idx_space_id_knowledge_base', ['space_id'], unique=False)
        if not index_exists('knowledge_base', 'idx_space_kb_knowledge_base'):
            batch_op.create_index('idx_space_kb_knowledge_base', ['space_id', 'kb_id'], unique=False)
        if not index_exists('knowledge_base', 'ix_knowledge_base_embedding_model_config_id_knowledge_base'):
            batch_op.create_index(
            'ix_knowledge_base_embedding_model_config_id_knowledge_base',
            ['embedding_model_config_id'], unique=False
            )
        if not index_exists('knowledge_base', 'ix_knowledge_base_kb_id_knowledge_base'):
            batch_op.create_index('ix_knowledge_base_kb_id_knowledge_base', ['kb_id'], unique=False)

    if not table_exists('knowledge_base_document'):
        op.create_table('knowledge_base_document',
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
        sa.Column('space_id', sa.String(length=100), nullable=False, comment='空间ID，用于多租户隔离'),
        sa.Column('kb_id', sa.String(length=100), nullable=False, comment='知识库ID'),
        sa.Column('doc_id', sa.String(length=100), nullable=False, comment='文档ID，唯一标识'),
        sa.Column('name', sa.String(length=500), nullable=False, comment='文档名称（文件名）'),
        sa.Column('file_path', sa.String(length=1000), nullable=False, comment='文档在服务器上的存储路径'),
        sa.Column('file_size', sa.BigInteger(), nullable=True, comment='文件大小（字节）'),
        sa.Column('file_type', sa.String(length=50), nullable=True, comment='文件类型（如：pdf, docx, txt等）'),
        sa.Column('mime_type', sa.String(length=100), nullable=True, comment='MIME类型'),
        sa.Column('status', sa.String(length=50), nullable=False, comment='文档状态'),
        sa.Column('es_index_id', sa.String(length=200), nullable=True, comment='ES中的索引ID'),
        sa.Column('es_index_name', sa.String(length=200), nullable=True, comment='ES索引名称'),
        sa.Column('chunk_count', sa.BigInteger(), nullable=True, comment='文档分块数量'),
        sa.Column('process_info', sa.JSON(), nullable=True, comment='处理信息（错误信息、处理进度等）'),
        sa.Column('metadata', sa.JSON(), nullable=True, comment='文档元数据（作者、标签、自定义字段等）'),
        sa.Column('_rest_', sa.JSON(), nullable=True, comment='扩展字段'),
        sa.Column('create_time', sa.BigInteger(), nullable=True, comment='创建时间'),
        sa.Column('update_time', sa.BigInteger(), nullable=True, comment='更新时间'),
        sa.Column('indexed_time', sa.BigInteger(), nullable=True, comment='索引完成时间'),
        sa.PrimaryKeyConstraint('id'),
        sa.UniqueConstraint('doc_id', name='uix_doc_id'),
        comment='知识库文档表，存储文档元数据信息'
        )
    with op.batch_alter_table('knowledge_base_document', schema=None) as batch_op:
        if not index_exists('knowledge_base_document', 'idx_kb_id_knowledge_base_document'):
            batch_op.create_index('idx_kb_id_knowledge_base_document', ['kb_id'], unique=False)
        if not index_exists('knowledge_base_document', 'idx_space_id_knowledge_base_document'):
            batch_op.create_index('idx_space_id_knowledge_base_document', ['space_id'], unique=False)
        if not index_exists('knowledge_base_document', 'idx_space_kb_doc_knowledge_base_document'):
            batch_op.create_index(
            'idx_space_kb_doc_knowledge_base_document', ['space_id', 'kb_id', 'doc_id'],
            unique=False
            )
        if not index_exists('knowledge_base_document', 'idx_space_kb_knowledge_base_document'):
            batch_op.create_index('idx_space_kb_knowledge_base_document', ['space_id', 'kb_id'], unique=False)
        if not index_exists('knowledge_base_document', 'idx_status_knowledge_base_document'):
            batch_op.create_index('idx_status_knowledge_base_document', ['status'], unique=False)
        if not index_exists('knowledge_base_document', 'ix_knowledge_base_document_doc_id_knowledge_base_document'):
            batch_op.create_index(
            'ix_knowledge_base_document_doc_id_knowledge_base_document', ['doc_id'],
            unique=False
            )
        if not index_exists('knowledge_base_document', 'ix_knowledge_base_document_kb_id_knowledge_base_document'):
            batch_op.create_index(
            'ix_knowledge_base_document_kb_id_knowledge_base_document', ['kb_id'],
            unique=False
            )

    if not table_exists('model_configs'):
        op.create_table('model_configs',
        sa.Column('id', sa.Integer(), nullable=False),
        sa.Column('name', sa.String(length=100), nullable=False),
        sa.Column('space_id', sa.String(length=50), nullable=False),
        sa.Column('provider', sa.String(length=50), nullable=False),
        sa.Column('model_type', sa.String(length=100), nullable=False),
        sa.Column('description', sa.Text(), nullable=True),
        sa.Column('tags', sa.JSON(), nullable=True),
        sa.Column('api_key', sa.Text(), nullable=True),
        sa.Column('base_url', sa.String(length=500), nullable=True),
        sa.Column('is_active', sa.Boolean(), nullable=True),
        sa.Column('parameters', sa.JSON(), nullable=True),
        sa.Column('timeout', sa.Integer(), nullable=True),
        sa.Column('retry_count', sa.Integer(), nullable=True),
        sa.Column('enable_streaming', sa.Boolean(), nullable=True),
        sa.Column('enable_function_calling', sa.Boolean(), nullable=True),
        sa.Column('total_requests', sa.Integer(), nullable=True),
        sa.Column('total_tokens', sa.Integer(), nullable=True),
        sa.Column('total_cost', sa.Float(), nullable=True),
        sa.Column('success_rate', sa.Float(), nullable=True),
        sa.Column('avg_response_time', sa.Float(), nullable=True),
        sa.Column('last_used', sa.DateTime(timezone=True), nullable=True),
        sa.Column('daily_requests', sa.Integer(), nullable=True),
        sa.Column('daily_tokens', sa.Integer(), nullable=True),
        sa.Column('daily_cost', sa.Float(), nullable=True),
        sa.Column('monthly_requests', sa.Integer(), nullable=True),
        sa.Column('monthly_tokens', sa.Integer(), nullable=True),
        sa.Column('monthly_cost', sa.Float(), nullable=True),
        sa.Column('created_at', sa.DateTime(timezone=True),
                   server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=True),
        sa.Column('updated_at', sa.DateTime(timezone=True),
                   server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=True),
        sa.PrimaryKeyConstraint('id')
        )
    with op.batch_alter_table('model_configs', schema=None) as batch_op:
        if not index_exists('model_configs', 'ix_model_configs_id_model_configs'):
            batch_op.create_index(
            'ix_model_configs_id_model_configs', ['id'], unique=False
            )
        if not index_exists('model_configs', 'ix_model_configs_is_active_model_configs'):
            batch_op.create_index(
            'ix_model_configs_is_active_model_configs', ['is_active'], unique=False
            )
        if not index_exists('model_configs', 'ix_model_configs_name_model_configs'):
            batch_op.create_index(
            'ix_model_configs_name_model_configs', ['name'], unique=False
            )
        if not index_exists('model_configs', 'ix_model_configs_provider_model_configs'):
            batch_op.create_index(
            'ix_model_configs_provider_model_configs', ['provider'], unique=False
            )
        if not index_exists('model_configs', 'ix_model_configs_space_id_model_configs'):
            batch_op.create_index(
            'ix_model_configs_space_id_model_configs', ['space_id'], unique=False
            )

    if not table_exists('plugin'):
        op.create_table('plugin',
        sa.Column('plugin_id', sa.String(length=100), nullable=False),
        sa.Column('plugin_version', sa.String(length=100), nullable=True),
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
        sa.Column('plugin_name', sa.String(length=255), nullable=True),
        sa.Column('desc', sa.String(length=512), nullable=True),
        sa.Column('url', sa.String(length=512), nullable=True),
        sa.Column('space_id', sa.String(length=100), nullable=True),
        sa.Column('icon_uri', sa.String(length=512), nullable=True),
        sa.Column('plugin_type', sa.Integer(), nullable=False),
        sa.Column('tools', sa.JSON(), nullable=True),
        sa.Column('_rest_', sa.JSON(), nullable=True),
        sa.Column('create_time', sa.BigInteger(), nullable=True),
        sa.Column('update_time', sa.BigInteger(), nullable=True),
        sa.PrimaryKeyConstraint('id'),
        sa.UniqueConstraint('plugin_id', 'plugin_version', name='unique_plugin_id_version')
        )
    with op.batch_alter_table('plugin', schema=None) as batch_op:
        if not index_exists('plugin', 'idx_space_id_plugin'):
            batch_op.create_index('idx_space_id_plugin', ['space_id'], unique=False)
        if not index_exists('plugin', 'ix_plugin_plugin_id_plugin'):
            batch_op.create_index(
            'ix_plugin_plugin_id_plugin', ['plugin_id'], unique=True
            )

    if not table_exists('prompt_relation'):
        op.create_table('prompt_relation',
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False, comment='Primary Key ID'),
        sa.Column('space_id', sa.String(length=100), nullable=True),
        sa.Column('prompt_id', sa.String(length=100), nullable=True),
        sa.Column('prompt_version', sa.String(length=100), nullable=True),
        sa.Column('prompt_name', sa.String(length=255), nullable=True),
        sa.Column('aw_id', sa.String(length=100), nullable=True, comment='workflow/agent的id, 与prompt关联'),
        sa.Column('aw_version', sa.String(length=100), nullable=True, comment='workflow/agentir的version'),
        sa.Column('aw_name', sa.String(length=255), nullable=True, comment='workflow/agentir的name'),
        sa.Column('type', sa.String(length=100), nullable=True, comment='AW Type: AGENT/WORKFLOW/PROMPT'),
        sa.Column('is_active', sa.Boolean(), nullable=False),
        sa.Column('create_time', sa.BigInteger(), nullable=True),
        sa.Column('update_time', sa.BigInteger(), nullable=True),
        sa.PrimaryKeyConstraint('id'),
        sa.UniqueConstraint('prompt_id', 'prompt_version', 'aw_id', 'aw_version',
                           name='unique_prompt_id_version_aw_id_version')
        )
    with op.batch_alter_table('prompt_relation', schema=None) as batch_op:
        if not index_exists('prompt_relation', 'idx_space_id_prompt_relation'):
            batch_op.create_index('idx_space_id_prompt_relation', ['space_id'], unique=False)

    if not table_exists('reference'):
        op.create_table('reference',
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
        sa.Column('space_id', sa.String(length=100), nullable=False),
        sa.Column('referenced_type', sa.String(length=20), nullable=False),
        sa.Column('referenced_id', sa.String(length=100), nullable=False),
        sa.Column('referenced_version', sa.String(length=100), nullable=False),
        sa.Column('referer_type', sa.String(length=20), nullable=False),
        sa.Column('referer_id', sa.String(length=100), nullable=False),
        sa.Column('referer_version', sa.String(length=100), nullable=False),
        sa.Column('create_time', sa.BigInteger(), nullable=True),
        sa.Column('update_time', sa.BigInteger(), nullable=True),
        sa.PrimaryKeyConstraint('id'),
        sa.UniqueConstraint('space_id', 'referenced_type', 'referenced_id',
                           'referenced_version', 'referer_type', 'referer_id',
                           'referer_version', name='uix_reference')
        )
    if not table_exists('space'):
        op.create_table('space',
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False, comment='Primary Key ID'),
        sa.Column('space_id', sa.String(length=100), nullable=False),
        sa.Column('owner_id', sa.String(length=100), nullable=False),
        sa.Column('space_name', sa.String(length=200), nullable=True),
        sa.Column('icon_uri', sa.String(length=200), nullable=True),
        sa.Column('creator_id', sa.String(length=100), nullable=True),
        sa.Column('description', sa.String(length=2000), nullable=True),
        sa.Column('_rest_', sa.JSON(), nullable=True),
        sa.Column('create_time', sa.BigInteger(), nullable=True),
        sa.Column('update_time', sa.BigInteger(), nullable=True),
        sa.Column('delete_time', sa.BigInteger(), nullable=True),
        sa.PrimaryKeyConstraint('id'),
        sa.UniqueConstraint('space_id', name='uniq_space_id')
        )
    with op.batch_alter_table('space', schema=None) as batch_op:
        if not index_exists('space', 'idx_creator_id_space'):
            batch_op.create_index('idx_creator_id_space', ['creator_id'], unique=False)
        if not index_exists('space', 'idx_owner_id_space'):
            batch_op.create_index('idx_owner_id_space', ['owner_id'], unique=False)

    if not table_exists('space_user'):
        op.create_table('space_user',
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False, comment='Primary Key ID'),
        sa.Column('space_id', sa.String(length=100), nullable=False, comment='Space ID'),
        sa.Column('user_id', sa.String(length=100), nullable=False, comment='User ID'),
        sa.Column('created_time', sa.BigInteger(), nullable=True),
        sa.Column('update_time', sa.BigInteger(), nullable=True),
        sa.PrimaryKeyConstraint('id'),
        sa.UniqueConstraint('space_id', 'user_id', name='uniq_space_user')
        )
    with op.batch_alter_table('space_user', schema=None) as batch_op:
        if not index_exists('space_user', 'idx_user_id_space_user'):
            batch_op.create_index('idx_user_id_space_user', ['user_id'], unique=False)

    if not table_exists('tag'):
        op.create_table('tag',
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
        sa.Column('space_id', sa.String(length=100), nullable=False),
        sa.Column('tag_name', sa.String(length=100), nullable=False),
        sa.Column('tag_color', sa.String(length=20), nullable=True),
        sa.Column('is_active', sa.Boolean(), nullable=False),
        sa.Column('usage_count', sa.Integer(), nullable=False),
        sa.Column('create_time', sa.BigInteger(), nullable=True),
        sa.Column('update_time', sa.BigInteger(), nullable=True),
        sa.Column('create_user', sa.String(length=100), nullable=True),
        sa.Column('update_user', sa.String(length=100), nullable=True),
        sa.PrimaryKeyConstraint('id'),
        sa.UniqueConstraint('space_id', 'tag_name', name='uix_space_tag_name')
        )
    with op.batch_alter_table('tag', schema=None) as batch_op:
        if not index_exists('tag', 'idx_tag_active_tag'):
            batch_op.create_index('idx_tag_active_tag', ['is_active'], unique=False)
        if not index_exists('tag', 'idx_tag_space_tag'):
            batch_op.create_index('idx_tag_space_tag', ['space_id'], unique=False)

    if not table_exists('trace_detail'):
        op.create_table('trace_detail',
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False, comment='主键ID'),
        sa.Column('space_id', sa.String(length=100), nullable=False, comment='空间ID'),
        sa.Column('business_id', sa.String(length=100), nullable=False, comment='业务ID（workflow_id/agent_id）'),
        sa.Column('business_type', sa.String(length=20), nullable=False, comment='业务类型（WORKFLOW/AGENT）'),
        sa.Column('trace_id', sa.String(length=100), nullable=False, comment='追踪ID，单次执行唯一标识'),
        sa.Column('span_id', sa.String(length=100), nullable=False, comment='Span ID，执行单元唯一标识'),
        sa.Column('span_type', sa.String(length=512), nullable=False, comment='Span类型 (如: prompt_executor)'),
        sa.Column('span_name', sa.String(length=255), nullable=False, comment='Span名称 (如: llm_completion)'),
        sa.Column('parent_span_id', sa.String(length=100), nullable=True, comment='父Span ID，支持嵌套调用'),
        sa.Column('method', sa.String(length=10), nullable=True, comment='HTTP方法 (如: POST)'),
        sa.Column('psm', sa.String(length=100), nullable=True, comment='服务实例信息 (如: IP地址)'),
        sa.Column('logid', sa.String(length=100), nullable=True, comment='日志ID'),
        sa.Column('platform_type', sa.String(length=50), nullable=True, comment='平台类型 (如: prompt)'),
        sa.Column('start_time_micros', sa.BigInteger(), nullable=True, comment='开始时间微秒戳'),
        sa.Column('end_time_micros', sa.BigInteger(), nullable=True, comment='结束时间微秒戳'),
        sa.Column('status_code', sa.String(length=20), nullable=True, comment="状态码 (如: '0'表示成功)"),
        sa.Column('input', sa.Text(), nullable=True, comment='输入数据'),
        sa.Column('output', sa.Text(), nullable=True, comment='输出数据'),
        sa.Column('attributes', sa.JSON(), nullable=True, comment='扩展属性对象'),
        sa.PrimaryKeyConstraint('id'),
        comment='统一执行追踪表'
        )
    if not table_exists('user'):
        op.create_table('user',
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False, comment='Primary Key ID'),
        sa.Column('user_id', sa.String(length=100), nullable=False, comment='USER ID'),
        sa.Column('email', sa.String(length=128), nullable=False),
        sa.Column('user_unique_name', sa.String(length=128), nullable=False),
        sa.Column('user_name', sa.String(length=128), nullable=False),
        sa.Column('password', sa.String(length=128), nullable=False),
        sa.Column('session_key', sa.String(length=256), nullable=False),
        sa.Column('role_type', sa.Integer(), nullable=False),
        sa.Column('user_verified', sa.Boolean(), nullable=False),
        sa.Column('is_active', sa.Boolean(), nullable=False),
        sa.Column('description', sa.String(length=512), nullable=True),
        sa.Column('icon_uri', sa.String(length=512), nullable=True),
        sa.Column('locale', sa.String(length=128), nullable=True),
        sa.Column('first_name', sa.String(length=128), nullable=True),
        sa.Column('last_name', sa.String(length=128), nullable=True),
        sa.Column('phone_number', sa.String(length=128), nullable=True),
        sa.Column('company', sa.String(length=128), nullable=True),
        sa.Column('occupation', sa.String(length=512), nullable=True),
        sa.Column('skills', sa.JSON(), nullable=True),
        sa.Column('_rest_', sa.JSON(), nullable=True),
        sa.Column('create_time', sa.BigInteger(), nullable=True),
        sa.Column('update_time', sa.BigInteger(), nullable=True),
        sa.Column('delete_time', sa.BigInteger(), nullable=True),
        sa.PrimaryKeyConstraint('id'),
        sa.UniqueConstraint('email', name='uniq_email'),
        sa.UniqueConstraint('session_key', name='idx_session_key'),
        sa.UniqueConstraint('user_id', name='uniq_user_id'),
        sa.UniqueConstraint('user_unique_name', name='uniq_user_unique_name')
        )
    if not table_exists('workflow'):
        op.create_table('workflow',
        sa.Column('workflow_id', sa.String(length=100), nullable=False),
        sa.Column('workflow_version', sa.String(length=100), nullable=True),
        sa.Column('latest_publish_time', sa.BigInteger(), nullable=True),
        sa.Column('latest_publish_version', sa.String(length=100), nullable=True),
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
        sa.Column('workflow_name', sa.String(length=255), nullable=True),
        sa.Column('description', sa.String(length=512), nullable=True),
        sa.Column('space_id', sa.String(length=100), nullable=True),
        sa.Column('url', sa.String(length=512), nullable=True),
        sa.Column('icon_uri', sa.String(length=255), nullable=True),
        sa.Column('schema', sa.Text(), nullable=True),
        sa.Column('input_parameters', sa.JSON(), nullable=True),
        sa.Column('output_parameters', sa.JSON(), nullable=True),
        sa.Column('_rest_', sa.JSON(), nullable=True),
        sa.Column('create_time', sa.BigInteger(), nullable=True),
        sa.Column('update_time', sa.BigInteger(), nullable=True),
        sa.PrimaryKeyConstraint('id'),
        sa.UniqueConstraint('workflow_id', 'workflow_version', name='unique_workflow_id_version')
        )
    with op.batch_alter_table('workflow', schema=None) as batch_op:
        if not index_exists('workflow', 'idx_space_id_workflow'):
            batch_op.create_index('idx_space_id_workflow', ['space_id'], unique=False)
        if not index_exists('workflow', 'ix_workflow_workflow_id_workflow'):
            batch_op.create_index('ix_workflow_workflow_id_workflow', ['workflow_id'], unique=True)

    if not table_exists('workflow_tag_association'):
        op.create_table('workflow_tag_association',
        sa.Column('workflow_id', sa.String(length=100), nullable=False),
        sa.Column('workflow_version', sa.String(length=100), nullable=False),
        sa.Column('tag_id', sa.BigInteger(), nullable=False),
        sa.Column('space_id', sa.String(length=100), nullable=False),
        sa.Column('create_time', sa.BigInteger(), nullable=True),
        sa.UniqueConstraint('workflow_id', 'workflow_version', 'tag_id', name='uix_workflow_tag')
        )
    with op.batch_alter_table('workflow_tag_association', schema=None) as batch_op:
        if not index_exists('workflow_tag_association', 'idx_workflow_tag_space_workflow_tag_association'):
            batch_op.create_index(
            'idx_workflow_tag_space_workflow_tag_association', ['space_id'], unique=False
            )
        if not index_exists('workflow_tag_association', 'idx_workflow_tag_tag_workflow_tag_association'):
            batch_op.create_index(
            'idx_workflow_tag_tag_workflow_tag_association', ['tag_id'], unique=False
            )
        if not index_exists('workflow_tag_association', 'idx_workflow_tag_workflow_workflow_tag_association'):
            batch_op.create_index(
            'idx_workflow_tag_workflow_workflow_tag_association',
            ['workflow_id', 'workflow_version'], unique=False
            )

    if not table_exists('agent_execution_details'):
        op.create_table('agent_execution_details',
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
        sa.Column('trace_id', sa.String(length=100), nullable=False),
        sa.Column('invoke_id', sa.String(length=100), nullable=False),
        sa.Column('start_time', sa.DateTime(timezone=True), nullable=True),
        sa.Column('end_time', sa.DateTime(timezone=True), nullable=True),
        sa.Column('inputs', sa.JSON(), nullable=True),
        sa.Column('outputs', sa.JSON(), nullable=True),
        sa.Column('input_tokens', sa.Integer(), nullable=True, comment='number of input tokens'),
        sa.Column('output_tokens', sa.Integer(), nullable=True, comment='number of output tokens'),
        sa.Column('error', sa.JSON(), nullable=False),
        sa.Column('parent_invoke_id', sa.String(length=100), nullable=True),
        sa.Column('child_invokes_id', sa.JSON(), nullable=True),
        sa.Column('invoke_type', sa.String(length=100), nullable=True,
                   comment='the invoke type of this agent execution'),
        sa.Column('name', sa.String(length=255), nullable=True, comment='the name of this agent execution'),
        sa.Column('elapsed_time', sa.String(length=100), nullable=True, comment='the elapsed time of this execution'),
        sa.Column('meta_data', sa.JSON(), nullable=True, comment='include llm function tools and token infos'),
        sa.Column('agent_parent_invoke_id', sa.String(length=100), nullable=True,
                   comment='Reserved field: nested agents for future adaptation of agent nodes'),
        sa.Column('_rest_', sa.JSON(), nullable=True),
        sa.ForeignKeyConstraint(['trace_id'], ['agent_execution.trace_id'], ),
        sa.PrimaryKeyConstraint('id'),
        comment='某次agent执行每个步骤的详细信息'
        )
    with op.batch_alter_table('agent_execution_details', schema=None) as batch_op:
        if not index_exists('agent_execution_details', 'ix_agent_execution_details_trace_id_agent_execution_details'):
            batch_op.create_index(
            'ix_agent_execution_details_trace_id_agent_execution_details', ['trace_id'],
            unique=False
            )

    if not table_exists('agent_publish'):
        op.create_table('agent_publish',
        sa.Column('agent_id', sa.String(length=100), nullable=False),
        sa.Column('agent_version', sa.String(length=100), nullable=False),
        sa.Column('version_description', sa.String(length=255), nullable=True),
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
        sa.Column('space_id', sa.String(length=100), nullable=False),
        sa.Column('agent_name', sa.String(length=255), nullable=True),
        sa.Column('description', sa.String(length=2000), nullable=True),
        sa.Column('agent_type', sa.String(length=100), nullable=True),
        sa.Column('icon', sa.String(length=100), nullable=True),
        sa.Column('edit_mode', sa.String(length=100), nullable=True),
        sa.Column('prompt_template_name', sa.String(length=100), nullable=True),
        sa.Column('auto_generated_prompt', sa.String(length=2000), nullable=True),
        sa.Column('opening_remarks', sa.String(length=2000), nullable=True),
        sa.Column('default_response', sa.String(length=2000), nullable=True),
        sa.Column('configs', sa.JSON(), nullable=True),
        sa.Column('plugins', sa.JSON(), nullable=True),
        sa.Column('workflows', sa.JSON(), nullable=True),
        sa.Column('model', sa.JSON(), nullable=True),
        sa.Column('prompt_template', sa.JSON(), nullable=True),
        sa.Column('constraint', sa.JSON(), nullable=True),
        sa.Column('prompt_tuning', sa.JSON(), nullable=True),
        sa.Column('triggers', sa.JSON(), nullable=True),
        sa.Column('knowledge', sa.JSON(), nullable=True),
        sa.Column('memory', sa.JSON(), nullable=True),
        sa.Column('_rest_', sa.JSON(), nullable=True),
        sa.Column('create_time', sa.BigInteger(), nullable=True),
        sa.Column('update_time', sa.BigInteger(), nullable=True),
        sa.ForeignKeyConstraint(['agent_id'], ['agent.agent_id'], ),
        sa.PrimaryKeyConstraint('id'),
        sa.UniqueConstraint('agent_id', 'agent_version', name='uix_agent_id_version')
        )
    with op.batch_alter_table('agent_publish', schema=None) as batch_op:
        if not index_exists('agent_publish', 'ix_agent_publish_agent_id_agent_publish'):
            batch_op.create_index('ix_agent_publish_agent_id_agent_publish', ['agent_id'], unique=False)

    if not table_exists('model_usage_logs'):
        op.create_table('model_usage_logs',
        sa.Column('id', sa.Integer(), nullable=False),
        sa.Column('model_config_id', sa.Integer(), nullable=False),
        sa.Column('prompt_tokens', sa.Integer(), nullable=True),
        sa.Column('completion_tokens', sa.Integer(), nullable=True),
        sa.Column('total_tokens', sa.Integer(), nullable=True),
        sa.Column('cost', sa.Float(), nullable=True),
        sa.Column('response_time', sa.Float(), nullable=True),
        sa.Column('success', sa.Boolean(), nullable=True),
        sa.Column('error_message', sa.Text(), nullable=True),
        sa.Column('ip_address', sa.String(length=45), nullable=True),
        sa.Column('user_agent', sa.Text(), nullable=True),
        sa.Column('request_id', sa.String(length=100), nullable=True),
        sa.Column('created_at', sa.DateTime(timezone=True),
                   server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=True),
        sa.ForeignKeyConstraint(['model_config_id'], ['model_configs.id'], ),
        sa.PrimaryKeyConstraint('id')
        )
    with op.batch_alter_table('model_usage_logs', schema=None) as batch_op:
        if not index_exists('model_usage_logs', 'ix_model_usage_logs_created_at_model_usage_logs'):
            batch_op.create_index(
            'ix_model_usage_logs_created_at_model_usage_logs', ['created_at'],
            unique=False
            )
        if not index_exists('model_usage_logs', 'ix_model_usage_logs_id_model_usage_logs'):
            batch_op.create_index(
            'ix_model_usage_logs_id_model_usage_logs', ['id'], unique=False
            )
        if not index_exists('model_usage_logs', 'ix_model_usage_logs_model_config_id_model_usage_logs'):
            batch_op.create_index(
            'ix_model_usage_logs_model_config_id_model_usage_logs', ['model_config_id'],
            unique=False
            )
        if not index_exists('model_usage_logs', 'ix_model_usage_logs_request_id_model_usage_logs'):
            batch_op.create_index(
            'ix_model_usage_logs_request_id_model_usage_logs', ['request_id'],
            unique=False
            )

    if not table_exists('plugin_publish'):
        op.create_table('plugin_publish',
        sa.Column('plugin_id', sa.String(length=100), nullable=False),
        sa.Column('plugin_version', sa.String(length=100), nullable=False),
        sa.Column('version_desc', sa.String(length=512), nullable=True),
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
        sa.Column('plugin_name', sa.String(length=255), nullable=True),
        sa.Column('desc', sa.String(length=512), nullable=True),
        sa.Column('url', sa.String(length=512), nullable=True),
        sa.Column('space_id', sa.String(length=100), nullable=True),
        sa.Column('icon_uri', sa.String(length=512), nullable=True),
        sa.Column('plugin_type', sa.Integer(), nullable=False),
        sa.Column('tools', sa.JSON(), nullable=True),
        sa.Column('_rest_', sa.JSON(), nullable=True),
        sa.Column('create_time', sa.BigInteger(), nullable=True),
        sa.Column('update_time', sa.BigInteger(), nullable=True),
        sa.ForeignKeyConstraint(['plugin_id'], ['plugin.plugin_id'], ondelete='CASCADE'),
        sa.ForeignKeyConstraint(['plugin_id'], ['plugin.plugin_id'], ondelete='CASCADE'),
        sa.PrimaryKeyConstraint('id'),
        sa.UniqueConstraint('plugin_id', 'plugin_version', name='unique_plugin_id_version')
        )
    with op.batch_alter_table('plugin_publish', schema=None) as batch_op:
        if not index_exists('plugin_publish', 'idx_space_id_plugin_publish'):
            batch_op.create_index('idx_space_id_plugin_publish', ['space_id'], unique=False)
        if not index_exists('plugin_publish', 'ix_plugin_publish_plugin_id_plugin_publish'):
            batch_op.create_index(
            'ix_plugin_publish_plugin_id_plugin_publish', ['plugin_id'], unique=False
            )

    if not table_exists('tool'):
        op.create_table('tool',
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
        sa.Column('tool_id', sa.String(length=100), nullable=False),
        sa.Column('tool_name', sa.String(length=255), nullable=True),
        sa.Column('desc', sa.String(length=512), nullable=True),
        sa.Column('space_id', sa.String(length=100), nullable=True),
        sa.Column('plugin_id', sa.String(length=100), nullable=False),
        sa.Column('plugin_type', sa.Integer(), nullable=False),
        sa.Column('plugin_version', sa.String(length=100), nullable=True),
        sa.Column('input_parameters', sa.JSON(), nullable=True),
        sa.Column('output_parameters', sa.JSON(), nullable=True),
        sa.Column('_rest_', sa.JSON(), nullable=True),
        sa.Column('create_time', sa.BigInteger(), nullable=True),
        sa.Column('update_time', sa.BigInteger(), nullable=True),
        sa.ForeignKeyConstraint(['plugin_id', 'plugin_version'],
                           ['plugin.plugin_id', 'plugin.plugin_version'],
                           ondelete='CASCADE'),
        sa.PrimaryKeyConstraint('id'),
        sa.UniqueConstraint('tool_id', 'plugin_version', name='unique_tool_id_version')
        )
    with op.batch_alter_table('tool', schema=None) as batch_op:
        if not index_exists('tool', 'idx_space_id_tool'):
            batch_op.create_index('idx_space_id_tool', ['space_id'], unique=False)

    if not table_exists('workflow_publish'):
        op.create_table('workflow_publish',
        sa.Column('workflow_id', sa.String(length=100), nullable=False),
        sa.Column('workflow_version', sa.String(length=100), nullable=False),
        sa.Column('version_description', sa.String(length=255), nullable=True),
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
        sa.Column('workflow_name', sa.String(length=255), nullable=True),
        sa.Column('description', sa.String(length=512), nullable=True),
        sa.Column('space_id', sa.String(length=100), nullable=True),
        sa.Column('url', sa.String(length=512), nullable=True),
        sa.Column('icon_uri', sa.String(length=255), nullable=True),
        sa.Column('schema', sa.Text(), nullable=True),
        sa.Column('input_parameters', sa.JSON(), nullable=True),
        sa.Column('output_parameters', sa.JSON(), nullable=True),
        sa.Column('_rest_', sa.JSON(), nullable=True),
        sa.Column('create_time', sa.BigInteger(), nullable=True),
        sa.Column('update_time', sa.BigInteger(), nullable=True),
        sa.ForeignKeyConstraint(['workflow_id'], ['workflow.workflow_id'], ),
        sa.PrimaryKeyConstraint('id'),
        sa.UniqueConstraint('workflow_id', 'workflow_version', name='unique_workflow_id_version')
        )
    with op.batch_alter_table('workflow_publish', schema=None) as batch_op:
        if not index_exists('workflow_publish', 'idx_space_id_workflow_publish'):
            batch_op.create_index('idx_space_id_workflow_publish', ['space_id'], unique=False)
        if not index_exists('workflow_publish', 'ix_workflow_publish_workflow_id_workflow_publish'):
            batch_op.create_index(
            'ix_workflow_publish_workflow_id_workflow_publish', ['workflow_id'],
            unique=False
            )

    if not table_exists('workflow_execution'):
        op.create_table('workflow_execution',
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
        sa.Column('space_id', sa.String(length=100), nullable=False),
        sa.Column('workflow_id', sa.String(length=100), nullable=False),
        sa.Column('workflow_version', sa.String(length=100), nullable=True,
                   comment='workflow version. empty if is draft'),
        sa.Column('trace_id', sa.String(length=100), nullable=False, comment='the trace id of this execution'),
        sa.Column('status', sa.String(length=16), nullable=True,
                   comment='finish/start/error/running/interrupted/unknown'),
        sa.Column('mode', sa.Integer(), nullable=False,
                   comment='the execution mode: 0. debug run 1. release run 2. node debug'),
        sa.Column('call_type', sa.String(length=100), nullable=True,
                   comment='The caller type that initiated this execution'),
        sa.Column('execution_id', sa.String(length=100), nullable=True, comment='the user id that runs this workflow'),
        sa.Column('duration', sa.Integer(), nullable=True, comment='execution duration in millisecond'),
        sa.Column('inputs', sa.JSON(), nullable=True, comment='inputs of this execution'),
        sa.Column('outputs', sa.JSON(), nullable=True, comment='outputs of this execution'),
        sa.Column('error_code', sa.Integer(), nullable=True, comment='error code'),
        sa.Column('fail_reason', sa.Text(), nullable=True, comment='the reason for failure'),
        sa.Column('input_tokens', sa.Integer(), nullable=True, comment='number of input tokens'),
        sa.Column('output_tokens', sa.Integer(), nullable=True, comment='number of output tokens'),
        sa.Column('execute_info_list', sa.JSON(), nullable=True, comment="workflows' components' execute info"),
        sa.Column('agent_execution_detail_id', sa.BigInteger(), nullable=True,
                   comment='link to agent_execution_details.id'),
        sa.Column('create_time', sa.DateTime(), nullable=True, comment='创建时间'),
        sa.Column('update_time', sa.DateTime(), server_default=sa.text('(CURRENT_TIMESTAMP)'),
                   nullable=True, comment='更新时间'),
        sa.ForeignKeyConstraint(['agent_execution_detail_id'], ['agent_execution_details.id'], ),
        sa.PrimaryKeyConstraint('id'),
        sa.UniqueConstraint('agent_execution_detail_id'),
        comment='某次workflow执行的总结信息'
        )
    with op.batch_alter_table('workflow_execution', schema=None) as batch_op:
        if not index_exists('workflow_execution', 'idx_workflow_workflow_execution'):
            batch_op.create_index(
            'idx_workflow_workflow_execution', ['space_id', 'workflow_id', 'workflow_version'],
            unique=False
            )
        if not index_exists('workflow_execution', 'ix_workflow_execution_trace_id_workflow_execution'):
            batch_op.create_index(
            'ix_workflow_execution_trace_id_workflow_execution', ['trace_id'],
            unique=False
            )
        if not index_exists('workflow_execution', 'workflow_id_version_workflow_execution'):
            batch_op.create_index(
            'workflow_id_version_workflow_execution', ['workflow_id', 'workflow_version'],
            unique=False
            )

    if not table_exists('workflow_execution_details'):
        op.create_table('workflow_execution_details',
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
        sa.Column('workflow_execution_id', sa.BigInteger(), nullable=False),
        sa.Column('invoke_id', sa.String(length=100), nullable=False),
        sa.Column('start_time', sa.DateTime(timezone=True), nullable=True),
        sa.Column('end_time', sa.DateTime(timezone=True), nullable=True),
        sa.Column('inputs', sa.JSON(), nullable=True),
        sa.Column('outputs', sa.JSON(), nullable=True),
        sa.Column('input_tokens', sa.Integer(), nullable=True, comment='number of input tokens'),
        sa.Column('output_tokens', sa.Integer(), nullable=True, comment='number of output tokens'),
        sa.Column('error', sa.JSON(), nullable=False),
        sa.Column('parent_invoke_id', sa.String(length=100), nullable=True),
        sa.Column('child_invokes_id', sa.JSON(), nullable=True),
        sa.Column('on_invoke_data', sa.JSON(), nullable=False,
                   comment='Intermediate process information used to record'
                   ' execution time of current component'),
        sa.Column('component_id', sa.String(length=100), nullable=False),
        sa.Column('component_name', sa.String(length=255), nullable=False),
        sa.Column('component_type', sa.String(length=100), nullable=False),
        sa.Column('agent_parent_invoke_id', sa.String(length=100), nullable=False,
                   comment='Reserved field: nested workflows for future adaptation of workflow nodes'),
        sa.Column('meta_data', sa.Text(), nullable=True),
        sa.Column('loop_node_id', sa.String(length=100), nullable=True),
        sa.Column('loop_index', sa.Integer(), nullable=True),
        sa.Column('status', sa.String(length=16), nullable=True,
                   comment='finish/start/error/running/interrupted/unknown'),
        sa.Column('llm_invoke_data', sa.JSON(), nullable=False),
        sa.Column('parent_node_id', sa.String(length=100), nullable=False),
        sa.Column('_rest_', sa.JSON(), nullable=True),
        sa.ForeignKeyConstraint(['workflow_execution_id'], ['workflow_execution.id'], ),
        sa.PrimaryKeyConstraint('id'),
        comment='某次workflow执行每个步骤的详细信息'
        )
    with op.batch_alter_table('workflow_execution_details', schema=None) as batch_op:
        if not index_exists('workflow_execution_details',
                          'ix_workflow_execution_details_workflow_execution_id_'
                          'workflow_execution_details'):
            batch_op.create_index(
            'ix_workflow_execution_details_workflow_execution_id_workflow_execution_details',
            ['workflow_execution_id'], unique=False
            )

    # ### end Alembic commands ###


def downgrade() -> None:
    """Downgrade schema."""
    # ### commands auto generated by Alembic - please adjust! ###
    with op.batch_alter_table('workflow_execution_details', schema=None) as batch_op:
        if index_exists('workflow_execution_details',
                       'ix_workflow_execution_details_workflow_execution_id_'
                       'workflow_execution_details'):
            batch_op.drop_index(
            'ix_workflow_execution_details_workflow_execution_id_workflow_execution_details'
            )

    if table_exists('workflow_execution_details'):
        op.drop_table('workflow_execution_details')
    with op.batch_alter_table('workflow_execution', schema=None) as batch_op:
        if index_exists('workflow_execution', 'workflow_id_version_workflow_execution'):
            batch_op.drop_index(
            'workflow_id_version_workflow_execution'
            )
        if index_exists('workflow_execution', 'ix_workflow_execution_trace_id_workflow_execution'):
            batch_op.drop_index(
            'ix_workflow_execution_trace_id_workflow_execution'
            )
        if index_exists('workflow_execution', 'idx_workflow_workflow_execution'):
            batch_op.drop_index(
            'idx_workflow_workflow_execution'
            )

    if table_exists('workflow_execution'):
        op.drop_table('workflow_execution')
    with op.batch_alter_table('workflow_publish', schema=None) as batch_op:
        if index_exists('workflow_publish', 'ix_workflow_publish_workflow_id_workflow_publish'):
            batch_op.drop_index(
            'ix_workflow_publish_workflow_id_workflow_publish'
            )
        if index_exists('workflow_publish', 'idx_space_id_workflow_publish'):
            batch_op.drop_index('idx_space_id_workflow_publish')

    if table_exists('workflow_publish'):
        op.drop_table('workflow_publish')
    with op.batch_alter_table('tool', schema=None) as batch_op:
        if index_exists('tool', 'idx_space_id_tool'):
            batch_op.drop_index('idx_space_id_tool')

    if table_exists('tool'):
        op.drop_table('tool')
    with op.batch_alter_table('plugin_publish', schema=None) as batch_op:
        if index_exists('plugin_publish', 'ix_plugin_publish_plugin_id_plugin_publish'):
            batch_op.drop_index(
            'ix_plugin_publish_plugin_id_plugin_publish'
            )
        if index_exists('plugin_publish', 'idx_space_id_plugin_publish'):
            batch_op.drop_index('idx_space_id_plugin_publish')

    if table_exists('plugin_publish'):
        op.drop_table('plugin_publish')
    with op.batch_alter_table('model_usage_logs', schema=None) as batch_op:
        if index_exists('model_usage_logs', 'ix_model_usage_logs_request_id_model_usage_logs'):
            batch_op.drop_index(
            'ix_model_usage_logs_request_id_model_usage_logs'
            )
        if index_exists('model_usage_logs', 'ix_model_usage_logs_model_config_id_model_usage_logs'):
            batch_op.drop_index(
            'ix_model_usage_logs_model_config_id_model_usage_logs'
            )
        if index_exists('model_usage_logs', 'ix_model_usage_logs_id_model_usage_logs'):
            batch_op.drop_index(
            'ix_model_usage_logs_id_model_usage_logs'
            )
        if index_exists('model_usage_logs', 'ix_model_usage_logs_created_at_model_usage_logs'):
            batch_op.drop_index(
            'ix_model_usage_logs_created_at_model_usage_logs'
            )

    if table_exists('model_usage_logs'):
        op.drop_table('model_usage_logs')
    with op.batch_alter_table('agent_publish', schema=None) as batch_op:
        if index_exists('agent_publish', 'ix_agent_publish_agent_id_agent_publish'):
            batch_op.drop_index(
            'ix_agent_publish_agent_id_agent_publish'
            )

    if table_exists('agent_publish'):
        op.drop_table('agent_publish')
    with op.batch_alter_table('agent_execution_details', schema=None) as batch_op:
        if index_exists('agent_execution_details', 'ix_agent_execution_details_trace_id_agent_execution_details'):
            batch_op.drop_index(
            'ix_agent_execution_details_trace_id_agent_execution_details'
            )

    if table_exists('agent_execution_details'):
        op.drop_table('agent_execution_details')
    with op.batch_alter_table('workflow_tag_association', schema=None) as batch_op:
        if index_exists('workflow_tag_association', 'idx_workflow_tag_workflow_workflow_tag_association'):
            batch_op.drop_index(
            'idx_workflow_tag_workflow_workflow_tag_association'
            )
        if index_exists('workflow_tag_association', 'idx_workflow_tag_tag_workflow_tag_association'):
            batch_op.drop_index(
            'idx_workflow_tag_tag_workflow_tag_association'
            )
        if index_exists('workflow_tag_association', 'idx_workflow_tag_space_workflow_tag_association'):
            batch_op.drop_index(
            'idx_workflow_tag_space_workflow_tag_association'
            )

    if table_exists('workflow_tag_association'):
        op.drop_table('workflow_tag_association')
    with op.batch_alter_table('workflow', schema=None) as batch_op:
        if index_exists('workflow', 'ix_workflow_workflow_id_workflow'):
            batch_op.drop_index(
            'ix_workflow_workflow_id_workflow'
            )
        if index_exists('workflow', 'idx_space_id_workflow'):
            batch_op.drop_index('idx_space_id_workflow')

    if table_exists('workflow'):
        op.drop_table('workflow')
    if table_exists('user'):
        op.drop_table('user')
    if table_exists('trace_detail'):
        op.drop_table('trace_detail')
    with op.batch_alter_table('tag', schema=None) as batch_op:
        if index_exists('tag', 'idx_tag_space_tag'):
            batch_op.drop_index('idx_tag_space_tag')
        if index_exists('tag', 'idx_tag_active_tag'):
            batch_op.drop_index('idx_tag_active_tag')

    if table_exists('tag'):
        op.drop_table('tag')
    with op.batch_alter_table('space_user', schema=None) as batch_op:
        if index_exists('space_user', 'idx_user_id_space_user'):
            batch_op.drop_index('idx_user_id_space_user')

    if table_exists('space_user'):
        op.drop_table('space_user')
    with op.batch_alter_table('space', schema=None) as batch_op:
        if index_exists('space', 'idx_owner_id_space'):
            batch_op.drop_index('idx_owner_id_space')
        if index_exists('space', 'idx_creator_id_space'):
            batch_op.drop_index('idx_creator_id_space')

    if table_exists('space'):
        op.drop_table('space')
    if table_exists('reference'):
        op.drop_table('reference')
    with op.batch_alter_table('prompt_relation', schema=None) as batch_op:
        if index_exists('prompt_relation', 'idx_space_id_prompt_relation'):
            batch_op.drop_index('idx_space_id_prompt_relation')

    if table_exists('prompt_relation'):
        op.drop_table('prompt_relation')
    with op.batch_alter_table('plugin', schema=None) as batch_op:
        if index_exists('plugin', 'ix_plugin_plugin_id_plugin'):
            batch_op.drop_index(
            'ix_plugin_plugin_id_plugin'
            )
        if index_exists('plugin', 'idx_space_id_plugin'):
            batch_op.drop_index('idx_space_id_plugin')

    if table_exists('plugin'):
        op.drop_table('plugin')
    with op.batch_alter_table('model_configs', schema=None) as batch_op:
        if index_exists('model_configs', 'ix_model_configs_space_id_model_configs'):
            batch_op.drop_index(
            'ix_model_configs_space_id_model_configs'
            )
        if index_exists('model_configs', 'ix_model_configs_provider_model_configs'):
            batch_op.drop_index(
            'ix_model_configs_provider_model_configs'
            )
        if index_exists('model_configs', 'ix_model_configs_name_model_configs'):
            batch_op.drop_index(
            'ix_model_configs_name_model_configs'
            )
        if index_exists('model_configs', 'ix_model_configs_is_active_model_configs'):
            batch_op.drop_index(
            'ix_model_configs_is_active_model_configs'
            )
        if index_exists('model_configs', 'ix_model_configs_id_model_configs'):
            batch_op.drop_index(
            'ix_model_configs_id_model_configs'
            )

    if table_exists('model_configs'):
        op.drop_table('model_configs')
    with op.batch_alter_table('knowledge_base_document', schema=None) as batch_op:
        if index_exists('knowledge_base_document', 'ix_knowledge_base_document_kb_id_knowledge_base_document'):
            batch_op.drop_index(
            'ix_knowledge_base_document_kb_id_knowledge_base_document'
            )
        if index_exists('knowledge_base_document', 'ix_knowledge_base_document_doc_id_knowledge_base_document'):
            batch_op.drop_index(
            'ix_knowledge_base_document_doc_id_knowledge_base_document'
            )
        if index_exists('knowledge_base_document', 'idx_status_knowledge_base_document'):
            batch_op.drop_index('idx_status_knowledge_base_document')
        if index_exists('knowledge_base_document', 'idx_space_kb_knowledge_base_document'):
            batch_op.drop_index('idx_space_kb_knowledge_base_document')
        if index_exists('knowledge_base_document', 'idx_space_kb_doc_knowledge_base_document'):
            batch_op.drop_index('idx_space_kb_doc_knowledge_base_document')
        if index_exists('knowledge_base_document', 'idx_space_id_knowledge_base_document'):
            batch_op.drop_index('idx_space_id_knowledge_base_document')
        if index_exists('knowledge_base_document', 'idx_kb_id_knowledge_base_document'):
            batch_op.drop_index('idx_kb_id_knowledge_base_document')

    if table_exists('knowledge_base_document'):
        op.drop_table('knowledge_base_document')
    with op.batch_alter_table('knowledge_base', schema=None) as batch_op:
        if index_exists('knowledge_base', 'ix_knowledge_base_kb_id_knowledge_base'):
            batch_op.drop_index(
            'ix_knowledge_base_kb_id_knowledge_base'
            )
        if index_exists('knowledge_base', 'ix_knowledge_base_embedding_model_config_id_knowledge_base'):
            batch_op.drop_index(
            'ix_knowledge_base_embedding_model_config_id_knowledge_base'
            )
        if index_exists('knowledge_base', 'idx_space_kb_knowledge_base'):
            batch_op.drop_index('idx_space_kb_knowledge_base')
        if index_exists('knowledge_base', 'idx_space_id_knowledge_base'):
            batch_op.drop_index('idx_space_id_knowledge_base')

    if table_exists('knowledge_base'):
        op.drop_table('knowledge_base')
    with op.batch_alter_table('embedding_model_configs', schema=None) as batch_op:
        if index_exists('embedding_model_configs', 'ix_embedding_model_configs_space_id_embedding_model_configs'):
            batch_op.drop_index(
            'ix_embedding_model_configs_space_id_embedding_model_configs'
            )
        if index_exists('embedding_model_configs', 'ix_embedding_model_configs_protocol_embedding_model_configs'):
            batch_op.drop_index(
            'ix_embedding_model_configs_protocol_embedding_model_configs'
            )
        if index_exists('embedding_model_configs', 'ix_embedding_model_configs_model_name_embedding_model_configs'):
            batch_op.drop_index(
            'ix_embedding_model_configs_model_name_embedding_model_configs'
            )
        if index_exists('embedding_model_configs', 'ix_embedding_model_configs_is_active_embedding_model_configs'):
            batch_op.drop_index(
            'ix_embedding_model_configs_is_active_embedding_model_configs'
            )
        if index_exists('embedding_model_configs', 'ix_embedding_model_configs_id_embedding_model_configs'):
            batch_op.drop_index(
            'ix_embedding_model_configs_id_embedding_model_configs'
            )

    if table_exists('embedding_model_configs'):
        op.drop_table('embedding_model_configs')
    with op.batch_alter_table('agent_workflow_relation', schema=None) as batch_op:
        if index_exists('agent_workflow_relation', 'idx_workflow_agent_workflow_relation'):
            batch_op.drop_index(
            'idx_workflow_agent_workflow_relation'
            )
        if index_exists('agent_workflow_relation', 'idx_agent_agent_workflow_relation'):
            batch_op.drop_index(
            'idx_agent_agent_workflow_relation'
            )

    if table_exists('agent_workflow_relation'):
        op.drop_table('agent_workflow_relation')
    with op.batch_alter_table('agent_execution', schema=None) as batch_op:
        if index_exists('agent_execution', 'ix_agent_execution_trace_id_agent_execution'):
            batch_op.drop_index(
            'ix_agent_execution_trace_id_agent_execution'
            )
        if index_exists('agent_execution', 'idx_agent_agent_execution'):
            batch_op.drop_index(
            'idx_agent_agent_execution'
            )
        if index_exists('agent_execution', 'agent_id_version_agent_execution'):
            batch_op.drop_index(
            'agent_id_version_agent_execution'
            )

    if table_exists('agent_execution'):
        op.drop_table('agent_execution')
    with op.batch_alter_table('agent', schema=None) as batch_op:
        if index_exists('agent', 'ix_agent_agent_id_agent'):
            batch_op.drop_index(
            'ix_agent_agent_id_agent'
            )

    if table_exists('agent'):
        op.drop_table('agent')
    # ### end Alembic commands ###