#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
"""create initial database schema for v0.1.2

Revision ID: 54351e123cf0
Revises:
Create Date: 2026-01-20 20:54:08.507260

"""

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
from sqlalchemy import inspect

# revision identifiers, used by Alembic.
revision: str = "54351e123cf0"
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.BigInteger(), 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"),
        )
    if not index_exists("agent", "ix_agent_agent_id"):
        op.create_index(op.f("ix_agent_agent_id"), "agent", ["agent_id"], unique=True)
    
    if not table_exists("agent_execution"):
        op.create_table(
            "agent_execution",
            sa.Column("id", sa.BigInteger(), 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("now()"),
                nullable=True,
                comment="更新时间",
            ),
            sa.PrimaryKeyConstraint("id"),
            comment="某次agent执行的总结信息",
        )
    if not index_exists("agent_execution", "agent_id_version"):
        op.create_index(
            "agent_id_version",
            "agent_execution",
            ["agent_id", "agent_version"],
            unique=False,
        )
    if not index_exists("agent_execution", "idx_agent"):
        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"):
        op.create_index(
            op.f("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.BigInteger(), 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",
            ),
        )
    if not index_exists("agent_workflow_relation", "idx_agent"):
        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"):
        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("now()"),
                nullable=True,
            ),
            sa.Column(
                "updated_at",
                sa.DateTime(timezone=True),
                server_default=sa.text("now()"),
                nullable=True,
            ),
            sa.PrimaryKeyConstraint("id"),
        )
    if not index_exists("embedding_model_configs", "ix_embedding_model_configs_id"):
        op.create_index(
            op.f("ix_embedding_model_configs_id"),
            "embedding_model_configs",
            ["id"],
            unique=False,
        )
    if not index_exists("embedding_model_configs", "ix_embedding_model_configs_is_active"):
        op.create_index(
            op.f("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"):
        op.create_index(
            op.f("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"):
        op.create_index(
            op.f("ix_embedding_model_configs_protocol"),
            "embedding_model_configs",
            ["protocol"],
            unique=False,
        )
    if not index_exists("embedding_model_configs", "ix_embedding_model_configs_space_id"):
        op.create_index(
            op.f("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.BigInteger(), 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="知识库表，存储知识库基本信息",
        )
    if not index_exists("knowledge_base", "idx_space_id"):
        op.create_index("idx_space_id", "knowledge_base", ["space_id"], unique=False)
    if not index_exists("knowledge_base", "idx_space_kb"):
        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"):
        op.create_index(
            op.f("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"):
        op.create_index(
            op.f("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.BigInteger(), 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="知识库文档表，存储文档元数据信息",
        )
    if not index_exists("knowledge_base_document", "idx_kb_id"):
        op.create_index("idx_kb_id", "knowledge_base_document", ["kb_id"], unique=False)
    if not index_exists("knowledge_base_document", "idx_space_id"):
        op.create_index(
            "idx_space_id", "knowledge_base_document", ["space_id"], unique=False
        )
    if not index_exists("knowledge_base_document", "idx_space_kb"):
        op.create_index(
            "idx_space_kb", "knowledge_base_document", ["space_id", "kb_id"], unique=False
        )
    if not index_exists("knowledge_base_document", "idx_space_kb_doc"):
        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_status"):
        op.create_index("idx_status", "knowledge_base_document", ["status"], unique=False)
    if not index_exists("knowledge_base_document", "ix_knowledge_base_document_doc_id"):
        op.create_index(
            op.f("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"):
        op.create_index(
            op.f("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("now()"),
                nullable=True,
            ),
            sa.Column(
                "updated_at",
                sa.DateTime(timezone=True),
                server_default=sa.text("now()"),
                nullable=True,
            ),
            sa.PrimaryKeyConstraint("id"),
        )
    if not index_exists("model_configs", "ix_model_configs_id"):
        op.create_index(op.f("ix_model_configs_id"), "model_configs", ["id"], unique=False)
    if not index_exists("model_configs", "ix_model_configs_is_active"):
        op.create_index(
            op.f("ix_model_configs_is_active"), "model_configs", ["is_active"], unique=False
        )
    if not index_exists("model_configs", "ix_model_configs_name"):
        op.create_index(
            op.f("ix_model_configs_name"), "model_configs", ["name"], unique=False
        )
    if not index_exists("model_configs", "ix_model_configs_provider"):
        op.create_index(
            op.f("ix_model_configs_provider"), "model_configs", ["provider"], unique=False
        )
    if not index_exists("model_configs", "ix_model_configs_space_id"):
        op.create_index(
            op.f("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.BigInteger(), 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"
            ),
        )
    if not index_exists("plugin", "idx_space_id"):
        op.create_index("idx_space_id", "plugin", ["space_id"], unique=False)
    if not index_exists("plugin", "ix_plugin_plugin_id"):
        op.create_index(op.f("ix_plugin_plugin_id"), "plugin", ["plugin_id"], unique=True)

    if not table_exists("prompt_relation"):
        op.create_table(
            "prompt_relation",
            sa.Column(
                "id",
                sa.BigInteger(),
                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",
            ),
        )
    if not index_exists("prompt_relation", "idx_space_id"):
        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.BigInteger(), 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.BigInteger(),
                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"),
        )
    if not index_exists("space", "idx_creator_id"):
        op.create_index("idx_creator_id", "space", ["creator_id"], unique=False)
    if not index_exists("space", "idx_owner_id"):
        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.BigInteger(),
                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"),
        )
    if not index_exists("space_user", "idx_user_id"):
        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.BigInteger(), 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"),
        )
    if not index_exists("tag", "idx_tag_active"):
        op.create_index("idx_tag_active", "tag", ["is_active"], unique=False)
    if not index_exists("tag", "idx_tag_space"):
        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.BigInteger(), 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("trace_summary"):
        op.create_table(
            "trace_summary",
            sa.Column(
                "id", sa.BigInteger(), 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(
                "business_version",
                sa.String(length=100),
                nullable=True,
                comment="业务版本号，草稿版本为空",
            ),
            sa.Column(
                "trace_id", sa.String(length=100), nullable=False, comment="执行追踪ID"
            ),
            sa.Column(
                "mode",
                sa.Integer(),
                nullable=False,
                comment="执行模式：0-调试运行，1-发布运行，2-节点调试",
            ),
            sa.Column(
                "call_type", sa.String(length=100), nullable=True, comment="调用方类型"
            ),
            sa.Column("duration", sa.Integer(), nullable=True, comment="执行时长（毫秒）"),
            sa.Column(
                "status",
                sa.String(length=16),
                nullable=True,
                comment="执行状态：finish/start/error/running/interrupted/unknown",
            ),
            sa.Column("input_tokens", sa.Integer(), nullable=True, comment="输入Token数量"),
            sa.Column(
                "output_tokens", sa.Integer(), nullable=True, comment="输出Token数量"
            ),
            sa.Column("inputs", sa.JSON(), nullable=True, comment="执行输入参数"),
            sa.Column("outputs", sa.JSON(), nullable=True, comment="执行输出结果"),
            sa.Column(
                "execute_info_list",
                sa.JSON(),
                nullable=True,
                comment="工作流组件执行信息列表",
            ),
            sa.Column("error_code", sa.Integer(), nullable=True, comment="错误代码"),
            sa.Column("fail_reason", sa.Text(), nullable=True, comment="失败原因"),
            sa.Column("create_time", sa.DateTime(), nullable=True, comment="创建时间"),
            sa.Column("update_time", sa.DateTime(), nullable=True, comment="更新时间"),
            sa.PrimaryKeyConstraint("id"),
            comment="执行摘要表",
        )

    if not table_exists("user"):
        op.create_table(
            "user",
            sa.Column(
                "id",
                sa.BigInteger(),
                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.BigInteger(), 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"
            ),
        )
    if not index_exists("workflow", "idx_space_id"):
        op.create_index("idx_space_id", "workflow", ["space_id"], unique=False)
    if not index_exists("workflow", "ix_workflow_workflow_id"):
        op.create_index(
            op.f("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"
            ),
        )
    if not index_exists("workflow_tag_association", "idx_workflow_tag_space"):
        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"):
        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"):
        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.BigInteger(), 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执行每个步骤的详细信息",
        )
    if not index_exists("agent_execution_details", "ix_agent_execution_details_trace_id"):
        op.create_index(
            op.f("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.BigInteger(), 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"),
        )
    if not index_exists("agent_publish", "ix_agent_publish_agent_id"):
        op.create_index(
            op.f("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("now()"),
                nullable=True,
            ),
            sa.ForeignKeyConstraint(
                ["model_config_id"],
                ["model_configs.id"],
            ),
            sa.PrimaryKeyConstraint("id"),
        )
    if not index_exists("model_usage_logs", "ix_model_usage_logs_created_at"):
        op.create_index(
            op.f("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"):
        op.create_index(
            op.f("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"):
        op.create_index(
            op.f("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"):
        op.create_index(
            op.f("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.BigInteger(), 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"
            ),
        )
    if not index_exists("plugin_publish", "idx_space_id"):
        op.create_index("idx_space_id", "plugin_publish", ["space_id"], unique=False)
    if not index_exists("plugin_publish", "ix_plugin_publish_plugin_id"):
        op.create_index(
            op.f("ix_plugin_publish_plugin_id"),
            "plugin_publish",
            ["plugin_id"],
            unique=False,
        )

    if not table_exists("tool"):
        op.create_table(
            "tool",
            sa.Column("id", sa.BigInteger(), 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"),
        )
    if not index_exists("tool", "idx_space_id"):
        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.BigInteger(), 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"
            ),
        )
    if not index_exists("workflow_publish", "idx_space_id"):
        op.create_index("idx_space_id", "workflow_publish", ["space_id"], unique=False)
    if not index_exists("workflow_publish", "ix_workflow_publish_workflow_id"):
        op.create_index(
            op.f("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.BigInteger(), 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("now()"),
                nullable=True,
                comment="更新时间",
            ),
            sa.ForeignKeyConstraint(
                ["agent_execution_detail_id"],
                ["agent_execution_details.id"],
            ),
            sa.PrimaryKeyConstraint("id"),
            sa.UniqueConstraint("agent_execution_detail_id"),
            comment="某次workflow执行的总结信息",
        )
    if not index_exists("workflow_execution", "idx_workflow"):
        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"):
        op.create_index(
            op.f("ix_workflow_execution_trace_id"),
            "workflow_execution",
            ["trace_id"],
            unique=False,
        )
    if not index_exists("workflow_execution", "workflow_id_version"):
        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.BigInteger(), 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 the execution time of the 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执行每个步骤的详细信息",
        )
    if not index_exists("workflow_execution_details", "ix_workflow_execution_details_workflow_execution_id"):
        op.create_index(
            op.f("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! ###
    if index_exists("workflow_execution_details", "ix_workflow_execution_details_workflow_execution_id"):
        op.drop_index(
            op.f("ix_workflow_execution_details_workflow_execution_id"),
            table_name="workflow_execution_details",
        )
    if table_exists("workflow_execution_details"):
        op.drop_table("workflow_execution_details")
    
    if index_exists("workflow_execution", "workflow_id_version"):
        op.drop_index("workflow_id_version", table_name="workflow_execution")
    if index_exists("workflow_execution", "ix_workflow_execution_trace_id"):
        op.drop_index(
            op.f("ix_workflow_execution_trace_id"), table_name="workflow_execution"
        )
    if index_exists("workflow_execution", "idx_workflow"):
        op.drop_index("idx_workflow", table_name="workflow_execution")
    if table_exists("workflow_execution"):
        op.drop_table("workflow_execution")
    
    if index_exists("workflow_publish", "ix_workflow_publish_workflow_id"):
        op.drop_index(
            op.f("ix_workflow_publish_workflow_id"), table_name="workflow_publish"
        )
    if index_exists("workflow_publish", "idx_space_id"):
        op.drop_index("idx_space_id", table_name="workflow_publish")
    if table_exists("workflow_publish"):
        op.drop_table("workflow_publish")
    
    if index_exists("tool", "idx_space_id"):
        op.drop_index("idx_space_id", table_name="tool")
    if table_exists("tool"):
        op.drop_table("tool")
    
    if index_exists("plugin_publish", "ix_plugin_publish_plugin_id"):
        op.drop_index(op.f("ix_plugin_publish_plugin_id"), table_name="plugin_publish")
    if index_exists("plugin_publish", "idx_space_id"):
        op.drop_index("idx_space_id", table_name="plugin_publish")
    if table_exists("plugin_publish"):
        op.drop_table("plugin_publish")
    
    if index_exists("model_usage_logs", "ix_model_usage_logs_request_id"):
        op.drop_index(op.f("ix_model_usage_logs_request_id"), table_name="model_usage_logs")
    if index_exists("model_usage_logs", "ix_model_usage_logs_model_config_id"):
        op.drop_index(
            op.f("ix_model_usage_logs_model_config_id"), table_name="model_usage_logs"
        )
    if index_exists("model_usage_logs", "ix_model_usage_logs_id"):
        op.drop_index(op.f("ix_model_usage_logs_id"), table_name="model_usage_logs")
    if index_exists("model_usage_logs", "ix_model_usage_logs_created_at"):
        op.drop_index(op.f("ix_model_usage_logs_created_at"), table_name="model_usage_logs")
    if table_exists("model_usage_logs"):
        op.drop_table("model_usage_logs")
    
    if index_exists("agent_publish", "ix_agent_publish_agent_id"):
        op.drop_index(op.f("ix_agent_publish_agent_id"), table_name="agent_publish")
    if table_exists("agent_publish"):
        op.drop_table("agent_publish")
    
    if index_exists("agent_execution_details", "ix_agent_execution_details_trace_id"):
        op.drop_index(
            op.f("ix_agent_execution_details_trace_id"),
            table_name="agent_execution_details",
        )
    if table_exists("agent_execution_details"):
        op.drop_table("agent_execution_details")
    
    if index_exists("workflow_tag_association", "idx_workflow_tag_workflow"):
        op.drop_index("idx_workflow_tag_workflow", table_name="workflow_tag_association")
    if index_exists("workflow_tag_association", "idx_workflow_tag_tag"):
        op.drop_index("idx_workflow_tag_tag", table_name="workflow_tag_association")
    if index_exists("workflow_tag_association", "idx_workflow_tag_space"):
        op.drop_index("idx_workflow_tag_space", table_name="workflow_tag_association")
    if table_exists("workflow_tag_association"):
        op.drop_table("workflow_tag_association")
    
    if index_exists("workflow", "ix_workflow_workflow_id"):
        op.drop_index(op.f("ix_workflow_workflow_id"), table_name="workflow")
    if index_exists("workflow", "idx_space_id"):
        op.drop_index("idx_space_id", table_name="workflow")
    if table_exists("workflow"):
        op.drop_table("workflow")
    
    if table_exists("user"):
        op.drop_table("user")
    
    if table_exists("trace_summary"):
        op.drop_table("trace_summary")
    
    if table_exists("trace_detail"):
        op.drop_table("trace_detail")
    
    if index_exists("tag", "idx_tag_space"):
        op.drop_index("idx_tag_space", table_name="tag")
    if index_exists("tag", "idx_tag_active"):
        op.drop_index("idx_tag_active", table_name="tag")
    if table_exists("tag"):
        op.drop_table("tag")
    
    if index_exists("space_user", "idx_user_id"):
        op.drop_index("idx_user_id", table_name="space_user")
    if table_exists("space_user"):
        op.drop_table("space_user")
    
    if index_exists("space", "idx_owner_id"):
        op.drop_index("idx_owner_id", table_name="space")
    if index_exists("space", "idx_creator_id"):
        op.drop_index("idx_creator_id", table_name="space")
    if table_exists("space"):
        op.drop_table("space")
    
    if table_exists("reference"):
        op.drop_table("reference")
    
    if index_exists("prompt_relation", "idx_space_id"):
        op.drop_index("idx_space_id", table_name="prompt_relation")
    if table_exists("prompt_relation"):
        op.drop_table("prompt_relation")
    
    if index_exists("plugin", "ix_plugin_plugin_id"):
        op.drop_index(op.f("ix_plugin_plugin_id"), table_name="plugin")
    if index_exists("plugin", "idx_space_id"):
        op.drop_index("idx_space_id", table_name="plugin")
    if table_exists("plugin"):
        op.drop_table("plugin")
    
    if index_exists("model_configs", "ix_model_configs_space_id"):
        op.drop_index(op.f("ix_model_configs_space_id"), table_name="model_configs")
    if index_exists("model_configs", "ix_model_configs_provider"):
        op.drop_index(op.f("ix_model_configs_provider"), table_name="model_configs")
    if index_exists("model_configs", "ix_model_configs_name"):
        op.drop_index(op.f("ix_model_configs_name"), table_name="model_configs")
    if index_exists("model_configs", "ix_model_configs_is_active"):
        op.drop_index(op.f("ix_model_configs_is_active"), table_name="model_configs")
    if index_exists("model_configs", "ix_model_configs_id"):
        op.drop_index(op.f("ix_model_configs_id"), table_name="model_configs")
    if table_exists("model_configs"):
        op.drop_table("model_configs")
    
    if index_exists("knowledge_base_document", "ix_knowledge_base_document_kb_id"):
        op.drop_index(
            op.f("ix_knowledge_base_document_kb_id"), table_name="knowledge_base_document"
        )
    if index_exists("knowledge_base_document", "ix_knowledge_base_document_doc_id"):
        op.drop_index(
            op.f("ix_knowledge_base_document_doc_id"), table_name="knowledge_base_document"
        )
    if index_exists("knowledge_base_document", "idx_status"):
        op.drop_index("idx_status", table_name="knowledge_base_document")
    if index_exists("knowledge_base_document", "idx_space_kb_doc"):
        op.drop_index("idx_space_kb_doc", table_name="knowledge_base_document")
    if index_exists("knowledge_base_document", "idx_space_kb"):
        op.drop_index("idx_space_kb", table_name="knowledge_base_document")
    if index_exists("knowledge_base_document", "idx_space_id"):
        op.drop_index("idx_space_id", table_name="knowledge_base_document")
    if index_exists("knowledge_base_document", "idx_kb_id"):
        op.drop_index("idx_kb_id", table_name="knowledge_base_document")
    if table_exists("knowledge_base_document"):
        op.drop_table("knowledge_base_document")
    
    if index_exists("knowledge_base", "ix_knowledge_base_kb_id"):
        op.drop_index(op.f("ix_knowledge_base_kb_id"), table_name="knowledge_base")
    if index_exists("knowledge_base", "ix_knowledge_base_embedding_model_config_id"):
        op.drop_index(
            op.f("ix_knowledge_base_embedding_model_config_id"), table_name="knowledge_base"
        )
    if index_exists("knowledge_base", "idx_space_kb"):
        op.drop_index("idx_space_kb", table_name="knowledge_base")
    if index_exists("knowledge_base", "idx_space_id"):
        op.drop_index("idx_space_id", table_name="knowledge_base")
    if table_exists("knowledge_base"):
        op.drop_table("knowledge_base")
    
    if index_exists("embedding_model_configs", "ix_embedding_model_configs_space_id"):
        op.drop_index(
            op.f("ix_embedding_model_configs_space_id"),
            table_name="embedding_model_configs",
        )
    if index_exists("embedding_model_configs", "ix_embedding_model_configs_protocol"):
        op.drop_index(
            op.f("ix_embedding_model_configs_protocol"),
            table_name="embedding_model_configs",
        )
    if index_exists("embedding_model_configs", "ix_embedding_model_configs_model_name"):
        op.drop_index(
            op.f("ix_embedding_model_configs_model_name"),
            table_name="embedding_model_configs",
        )
    if index_exists("embedding_model_configs", "ix_embedding_model_configs_is_active"):
        op.drop_index(
            op.f("ix_embedding_model_configs_is_active"),
            table_name="embedding_model_configs",
        )
    if index_exists("embedding_model_configs", "ix_embedding_model_configs_id"):
        op.drop_index(
            op.f("ix_embedding_model_configs_id"), table_name="embedding_model_configs"
        )
    if table_exists("embedding_model_configs"):
        op.drop_table("embedding_model_configs")
    
    if index_exists("agent_workflow_relation", "idx_workflow"):
        op.drop_index("idx_workflow", table_name="agent_workflow_relation")
    if index_exists("agent_workflow_relation", "idx_agent"):
        op.drop_index("idx_agent", table_name="agent_workflow_relation")
    if table_exists("agent_workflow_relation"):
        op.drop_table("agent_workflow_relation")
    
    if index_exists("agent_execution", "ix_agent_execution_trace_id"):
        op.drop_index(op.f("ix_agent_execution_trace_id"), table_name="agent_execution")
    if index_exists("agent_execution", "idx_agent"):
        op.drop_index("idx_agent", table_name="agent_execution")
    if index_exists("agent_execution", "agent_id_version"):
        op.drop_index("agent_id_version", table_name="agent_execution")
    if table_exists("agent_execution"):
        op.drop_table("agent_execution")
    
    if index_exists("agent", "ix_agent_agent_id"):
        op.drop_index(op.f("ix_agent_agent_id"), table_name="agent")
    if table_exists("agent"):
        op.drop_table("agent")
    # ### end Alembic commands ###
