From 0ed2a513f998d1ee691fb77dbc45ba10674e9341 Mon Sep 17 00:00:00 2001 From: RockChinQ Date: Tue, 13 Oct 2026 13:28:03 +0000 Subject: [PATCH] test(persistence): verify tagged 4.10.11 upgrades on sqlite and postgres --- .../fixtures/release_4_10_11_audit.md | 39 +++ .../fixtures/release_4_10_11_schema.json | 250 ++++++++++++++++++ .../persistence/test_release_41011_upgrade.py | 130 +++++++++ 3 files changed, 419 insertions(+) create mode 100644 tests/integration/persistence/fixtures/release_4_10_11_audit.md create mode 100644 tests/integration/persistence/fixtures/release_4_10_11_schema.json create mode 100644 tests/integration/persistence/test_release_41011_upgrade.py diff --git a/tests/integration/persistence/fixtures/release_4_10_11_audit.md b/tests/integration/persistence/fixtures/release_4_10_11_audit.md new file mode 100644 index 000000000..768c64c6d --- /dev/null +++ b/tests/integration/persistence/fixtures/release_4_10_11_audit.md @@ -0,0 +1,39 @@ +# v4.10.11 database upgrade audit + +Baseline: `v4.10.11`, commit `273b8839b91cb74dfd083644efea18849a3fcee1`. +Audited target: `48c6a1f536bab421cbaab98a1e880fe767034463`. + +## Changes covered + +- Agent definitions, run ledger, interactions/delivery results, event logs and transcripts. +- Bot legacy pipeline routing to event bindings, followed by legacy-column removal; plugin processors. +- Workspace tenancy/ownership repairs and migration branch merges. +- Unified runner state, assistant conversations and pipeline migration snapshots. +- Passkey and TOTP credentials. +- Knowledge-base initialization/drafts and engine document identity. +- Operation traceability, monitoring links/tool calls, execution host leases and metadata text storage. + +The existing migration chain covers the audited ORM changes. No additional runtime migration was required by the exercised upgrade paths. + +## Added regression + +`release_4_10_11_schema.json` contains immutable dialect-specific DDL exported from the tagged release ORM, rather than current metadata. The test applies historical migrations through `0023_bot_scoped_sessions` to include migration-owned objects such as pgvector, seeds representative legacy records, then runs the current persistence schema initialization twice. + +Assertions cover legacy bot/pipeline preservation, converted bot event bindings, default plugin processors, initialized knowledge bases, SQLite foreign-key consistency, and missing tables/columns/indexes/constraints or column type/nullability differences against current metadata. Equivalent existing index/constraint column sets are accepted; extra migration-owned objects and removed-object diffs are not treated as missing schema. This is representative upgrade coverage, not an exhaustive test of every possible historical data value. + +## Executed verification + +Disposable SQLite files and an isolated PostgreSQL/pgvector container were used; no business database was changed. + +- New tagged-release upgrade test: **2 passed** (SQLite and PostgreSQL), including repeated initialization. +- Existing PostgreSQL migration / release-migration / RAG identity suite: **85 passed, 4 failed** on the first completed run. The four failures were release configuration validation because the test URL omitted the required port. +- Release-migration suite rerun with explicit `:5432`: **5 passed**. +- Ruff check and format: passed for the new regression test. + +Reproduce the new regression with `TEST_POSTGRES_URL` pointing to a disposable PostgreSQL/pgvector instance whose test role can create/drop databases: + +```sh +pytest tests/integration/persistence/test_release_41011_upgrade.py -q +``` + +Without `TEST_POSTGRES_URL`, PostgreSQL is explicitly skipped rather than reported as tested. diff --git a/tests/integration/persistence/fixtures/release_4_10_11_schema.json b/tests/integration/persistence/fixtures/release_4_10_11_schema.json new file mode 100644 index 000000000..cf8a2beda --- /dev/null +++ b/tests/integration/persistence/fixtures/release_4_10_11_schema.json @@ -0,0 +1,250 @@ +{ + "source_commit": "273b8839b91cb74dfd083644efea18849a3fcee1", + "revision": "0023_bot_scoped_sessions", + "dialects": { + "sqlite": [ + "\nCREATE TABLE directory_projection_inbox (\n\tinstance_uuid VARCHAR(255) NOT NULL, \n\tevent_uuid VARCHAR(36) NOT NULL, \n\tcursor BIGINT NOT NULL, \n\tevent_type VARCHAR(128) NOT NULL, \n\trevision BIGINT NOT NULL, \n\tfingerprint TEXT NOT NULL, \n\treceived_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tapplied_at DATETIME, \n\tPRIMARY KEY (instance_uuid, event_uuid), \n\tCONSTRAINT uq_directory_projection_inbox_cursor UNIQUE (instance_uuid, cursor), \n\tCONSTRAINT ck_directory_projection_inbox_cursor CHECK (cursor > 0), \n\tCONSTRAINT ck_directory_projection_inbox_revision CHECK (revision > 0), \n\tCONSTRAINT ck_directory_projection_inbox_fingerprint CHECK (length(fingerprint) = 64)\n)\n\n", + "CREATE INDEX ix_directory_projection_inbox_pending ON directory_projection_inbox (instance_uuid, applied_at, cursor)", + "\nCREATE TABLE directory_projection_states (\n\tinstance_uuid VARCHAR(255) NOT NULL, \n\tcursor BIGINT DEFAULT '0' NOT NULL, \n\tsnapshot_coverage_cursor BIGINT DEFAULT '0' NOT NULL, \n\tsnapshot_fingerprint TEXT NOT NULL, \n\tlast_applied_at DATETIME NOT NULL, \n\tlease_expires_at DATETIME, \n\tPRIMARY KEY (instance_uuid), \n\tCONSTRAINT ck_directory_projection_state_cursor CHECK (cursor >= 0), \n\tCONSTRAINT ck_directory_projection_state_snapshot_coverage CHECK (snapshot_coverage_cursor >= 0 AND snapshot_coverage_cursor <= cursor), \n\tCONSTRAINT ck_directory_projection_state_fingerprint CHECK (length(snapshot_fingerprint) = 64)\n)\n\n", + "\nCREATE TABLE metadata (\n\t\"key\" VARCHAR(255) NOT NULL, \n\tvalue VARCHAR(255), \n\tPRIMARY KEY (\"key\")\n)\n\n", + "\nCREATE TABLE users (\n\tid INTEGER NOT NULL, \n\tuuid VARCHAR(36) NOT NULL, \n\tuser VARCHAR(255) NOT NULL, \n\tnormalized_email VARCHAR(320) NOT NULL, \n\tpassword VARCHAR(255) NOT NULL, \n\tstatus VARCHAR(32) DEFAULT 'active' NOT NULL, \n\tsource VARCHAR(32) DEFAULT 'local' NOT NULL, \n\tprojection_revision BIGINT DEFAULT '0' NOT NULL, \n\taccount_type VARCHAR(32) DEFAULT 'local' NOT NULL, \n\tspace_account_uuid VARCHAR(255), \n\tspace_access_token TEXT, \n\tspace_refresh_token TEXT, \n\tspace_access_token_expires_at DATETIME, \n\tspace_api_key VARCHAR(255), \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (id), \n\tCONSTRAINT ck_users_normalized_email CHECK (normalized_email = trim(normalized_email) AND length(normalized_email) > 0 AND length(normalized_email) <= 320), \n\tCONSTRAINT ck_users_status CHECK (status IN ('active', 'disabled', 'deleted')), \n\tCONSTRAINT ck_users_source CHECK (source IN ('local', 'cloud_projection'))\n)\n\n", + "CREATE UNIQUE INDEX uq_users_normalized_email ON users (normalized_email)", + "CREATE UNIQUE INDEX uq_users_uuid ON users (uuid)", + "\nCREATE TABLE workspaces (\n\tuuid VARCHAR(36) NOT NULL, \n\tinstance_uuid VARCHAR(255) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\tslug VARCHAR(255) NOT NULL, \n\ttype VARCHAR(32) DEFAULT 'team' NOT NULL, \n\tstatus VARCHAR(32) DEFAULT 'active' NOT NULL, \n\tcreated_by_account_uuid VARCHAR(36), \n\tsource VARCHAR(32) DEFAULT 'local' NOT NULL, \n\tprojection_revision BIGINT DEFAULT '0' NOT NULL, \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_workspaces_instance_slug UNIQUE (instance_uuid, slug), \n\tCONSTRAINT ck_workspaces_type CHECK (type IN ('personal', 'team')), \n\tCONSTRAINT ck_workspaces_status CHECK (status IN ('provisioning', 'active', 'suspended', 'archived', 'deleted')), \n\tCONSTRAINT ck_workspaces_source CHECK (source IN ('local', 'cloud_projection')), \n\tFOREIGN KEY(created_by_account_uuid) REFERENCES users (uuid) ON DELETE SET NULL\n)\n\n", + "CREATE INDEX ix_workspaces_instance_status ON workspaces (instance_uuid, status)", + "CREATE UNIQUE INDEX uq_workspaces_local_instance ON workspaces (instance_uuid) WHERE source = 'local'", + "\nCREATE TABLE api_keys (\n\tid INTEGER NOT NULL, \n\tuuid VARCHAR(36) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tcreated_by_account_uuid VARCHAR(36), \n\tname VARCHAR(255) NOT NULL, \n\tkey_hash VARCHAR(64) NOT NULL, \n\tscopes JSON DEFAULT '[]' NOT NULL, \n\tstatus VARCHAR(32) DEFAULT 'active' NOT NULL, \n\texpires_at DATETIME, \n\tlast_used_at DATETIME, \n\tdescription VARCHAR(512), \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (id), \n\tCONSTRAINT ck_api_keys_status CHECK (status IN ('active', 'revoked')), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE, \n\tFOREIGN KEY(created_by_account_uuid) REFERENCES users (uuid) ON DELETE SET NULL\n)\n\n", + "CREATE INDEX ix_api_keys_workspace_name ON api_keys (workspace_uuid, name)", + "CREATE INDEX ix_api_keys_workspace_status ON api_keys (workspace_uuid, status)", + "CREATE UNIQUE INDEX uq_api_keys_key_hash ON api_keys (key_hash)", + "CREATE UNIQUE INDEX uq_api_keys_uuid ON api_keys (uuid)", + "\nCREATE TABLE binary_storages (\n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tunique_key VARCHAR(255) NOT NULL, \n\t\"key\" VARCHAR(255) NOT NULL, \n\towner_type VARCHAR(255) NOT NULL, \n\towner VARCHAR(255) NOT NULL, \n\tvalue BLOB NOT NULL, \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (workspace_uuid, unique_key), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_binary_storages_workspace_owner ON binary_storages (workspace_uuid, owner_type, owner)", + "\nCREATE TABLE bots (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\tdescription VARCHAR(255) NOT NULL, \n\tadapter VARCHAR(255) NOT NULL, \n\tadapter_config JSON NOT NULL, \n\tenable BOOLEAN NOT NULL, \n\tuse_pipeline_name VARCHAR(255), \n\tuse_pipeline_uuid VARCHAR(255), \n\tpipeline_routing_rules JSON DEFAULT '[]' NOT NULL, \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_bots_workspace_uuid UNIQUE (workspace_uuid, uuid), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_bots_workspace_name ON bots (workspace_uuid, name)", + "\nCREATE TABLE knowledge_bases (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR, \n\tdescription TEXT, \n\temoji VARCHAR(10), \n\tcreated_at DATETIME, \n\tupdated_at DATETIME, \n\tknowledge_engine_plugin_id VARCHAR, \n\tcollection_id VARCHAR, \n\tlegacy_vector_collection BOOLEAN DEFAULT 0 NOT NULL, \n\tcreation_settings JSON, \n\tretrieval_settings JSON, \n\tembedding_dimension INTEGER, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_knowledge_bases_workspace_uuid UNIQUE (workspace_uuid, uuid), \n\tCONSTRAINT ck_knowledge_bases_embedding_dimension_positive CHECK (embedding_dimension IS NULL OR embedding_dimension > 0), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_knowledge_bases_name ON knowledge_bases (name)", + "CREATE INDEX ix_knowledge_bases_workspace_name ON knowledge_bases (workspace_uuid, name)", + "CREATE UNIQUE INDEX uq_knowledge_bases_workspace_collection ON knowledge_bases (workspace_uuid, collection_id) WHERE collection_id IS NOT NULL", + "\nCREATE TABLE legacy_pipelines (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\tdescription VARCHAR(255) NOT NULL, \n\temoji VARCHAR(10), \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tfor_version VARCHAR(255) NOT NULL, \n\tis_default BOOLEAN NOT NULL, \n\tstages JSON NOT NULL, \n\tconfig JSON NOT NULL, \n\textensions_preferences JSON NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_legacy_pipelines_workspace_uuid UNIQUE (workspace_uuid, uuid), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_legacy_pipelines_workspace_default ON legacy_pipelines (workspace_uuid, is_default)", + "CREATE INDEX ix_legacy_pipelines_workspace_name ON legacy_pipelines (workspace_uuid, name)", + "\nCREATE TABLE mcp_servers (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\tenable BOOLEAN NOT NULL, \n\tmode VARCHAR(255) NOT NULL, \n\textra_args JSON NOT NULL, \n\treadme TEXT DEFAULT '' NOT NULL, \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_mcp_servers_workspace_name UNIQUE (workspace_uuid, name), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_mcp_servers_workspace_enable ON mcp_servers (workspace_uuid, enable)", + "\nCREATE TABLE model_providers (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\trequester VARCHAR(255) NOT NULL, \n\tbase_url VARCHAR(512) NOT NULL, \n\tapi_keys JSON NOT NULL, \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_model_providers_workspace_uuid UNIQUE (workspace_uuid, uuid), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_model_providers_workspace_name ON model_providers (workspace_uuid, name)", + "CREATE INDEX ix_model_providers_workspace_requester ON model_providers (workspace_uuid, requester)", + "\nCREATE TABLE monitoring_embedding_calls (\n\tid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\ttimestamp DATETIME NOT NULL, \n\tmodel_name VARCHAR(255) NOT NULL, \n\tprompt_tokens INTEGER NOT NULL, \n\ttotal_tokens INTEGER NOT NULL, \n\tduration INTEGER NOT NULL, \n\tinput_count INTEGER NOT NULL, \n\tstatus VARCHAR(50) NOT NULL, \n\terror_message TEXT, \n\tknowledge_base_id VARCHAR(255), \n\tquery_text TEXT, \n\tsession_id VARCHAR(255), \n\tmessage_id VARCHAR(255), \n\tcall_type VARCHAR(50), \n\tPRIMARY KEY (id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_monitoring_embedding_calls_knowledge_base_id ON monitoring_embedding_calls (knowledge_base_id)", + "CREATE INDEX ix_monitoring_embedding_calls_message_id ON monitoring_embedding_calls (message_id)", + "CREATE INDEX ix_monitoring_embedding_calls_session_id ON monitoring_embedding_calls (session_id)", + "CREATE INDEX ix_monitoring_embedding_calls_timestamp ON monitoring_embedding_calls (timestamp)", + "CREATE INDEX ix_monitoring_embedding_calls_workspace_kb ON monitoring_embedding_calls (workspace_uuid, knowledge_base_id)", + "CREATE INDEX ix_monitoring_embedding_calls_workspace_timestamp ON monitoring_embedding_calls (workspace_uuid, timestamp)", + "\nCREATE TABLE monitoring_errors (\n\tid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\ttimestamp DATETIME NOT NULL, \n\terror_type VARCHAR(255) NOT NULL, \n\terror_message TEXT NOT NULL, \n\tbot_id VARCHAR(255) NOT NULL, \n\tbot_name VARCHAR(255) NOT NULL, \n\tpipeline_id VARCHAR(255) NOT NULL, \n\tpipeline_name VARCHAR(255) NOT NULL, \n\tsession_id VARCHAR(255), \n\tstack_trace TEXT, \n\tmessage_id VARCHAR(255), \n\tPRIMARY KEY (id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_monitoring_errors_bot_id ON monitoring_errors (bot_id)", + "CREATE INDEX ix_monitoring_errors_message_id ON monitoring_errors (message_id)", + "CREATE INDEX ix_monitoring_errors_pipeline_id ON monitoring_errors (pipeline_id)", + "CREATE INDEX ix_monitoring_errors_timestamp ON monitoring_errors (timestamp)", + "CREATE INDEX ix_monitoring_errors_workspace_session ON monitoring_errors (workspace_uuid, session_id)", + "CREATE INDEX ix_monitoring_errors_workspace_timestamp ON monitoring_errors (workspace_uuid, timestamp)", + "\nCREATE TABLE monitoring_feedback (\n\tid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\ttimestamp DATETIME NOT NULL, \n\tfeedback_id VARCHAR(255) NOT NULL, \n\tfeedback_type INTEGER NOT NULL, \n\tfeedback_content TEXT, \n\tinaccurate_reasons TEXT, \n\tbot_id VARCHAR(255), \n\tbot_name VARCHAR(255), \n\tpipeline_id VARCHAR(255), \n\tpipeline_name VARCHAR(255), \n\tsession_id VARCHAR(255), \n\tmessage_id VARCHAR(255), \n\tstream_id VARCHAR(255), \n\tuser_id VARCHAR(255), \n\tplatform VARCHAR(255), \n\tPRIMARY KEY (id), \n\tCONSTRAINT uq_monitoring_feedback_workspace_feedback_id UNIQUE (workspace_uuid, feedback_id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_monitoring_feedback_bot_id ON monitoring_feedback (bot_id)", + "CREATE INDEX ix_monitoring_feedback_feedback_id ON monitoring_feedback (feedback_id)", + "CREATE INDEX ix_monitoring_feedback_message_id ON monitoring_feedback (message_id)", + "CREATE INDEX ix_monitoring_feedback_pipeline_id ON monitoring_feedback (pipeline_id)", + "CREATE INDEX ix_monitoring_feedback_session_id ON monitoring_feedback (session_id)", + "CREATE INDEX ix_monitoring_feedback_stream_id ON monitoring_feedback (stream_id)", + "CREATE INDEX ix_monitoring_feedback_timestamp ON monitoring_feedback (timestamp)", + "CREATE INDEX ix_monitoring_feedback_workspace_session ON monitoring_feedback (workspace_uuid, session_id)", + "CREATE INDEX ix_monitoring_feedback_workspace_timestamp ON monitoring_feedback (workspace_uuid, timestamp)", + "\nCREATE TABLE monitoring_llm_calls (\n\tid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\ttimestamp DATETIME NOT NULL, \n\tmodel_name VARCHAR(255) NOT NULL, \n\tinput_tokens INTEGER NOT NULL, \n\toutput_tokens INTEGER NOT NULL, \n\ttotal_tokens INTEGER NOT NULL, \n\tduration INTEGER NOT NULL, \n\tcost FLOAT, \n\tstatus VARCHAR(50) NOT NULL, \n\tbot_id VARCHAR(255) NOT NULL, \n\tbot_name VARCHAR(255) NOT NULL, \n\tpipeline_id VARCHAR(255) NOT NULL, \n\tpipeline_name VARCHAR(255) NOT NULL, \n\tsession_id VARCHAR(255) NOT NULL, \n\terror_message TEXT, \n\tmessage_id VARCHAR(255), \n\tPRIMARY KEY (id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_monitoring_llm_calls_bot_id ON monitoring_llm_calls (bot_id)", + "CREATE INDEX ix_monitoring_llm_calls_message_id ON monitoring_llm_calls (message_id)", + "CREATE INDEX ix_monitoring_llm_calls_pipeline_id ON monitoring_llm_calls (pipeline_id)", + "CREATE INDEX ix_monitoring_llm_calls_timestamp ON monitoring_llm_calls (timestamp)", + "CREATE INDEX ix_monitoring_llm_calls_workspace_session ON monitoring_llm_calls (workspace_uuid, session_id)", + "CREATE INDEX ix_monitoring_llm_calls_workspace_timestamp ON monitoring_llm_calls (workspace_uuid, timestamp)", + "\nCREATE TABLE monitoring_messages (\n\tid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\ttimestamp DATETIME NOT NULL, \n\tbot_id VARCHAR(255) NOT NULL, \n\tbot_name VARCHAR(255) NOT NULL, \n\tpipeline_id VARCHAR(255) NOT NULL, \n\tpipeline_name VARCHAR(255) NOT NULL, \n\tmessage_content TEXT NOT NULL, \n\tsession_id VARCHAR(255) NOT NULL, \n\tstatus VARCHAR(50) NOT NULL, \n\tlevel VARCHAR(50) NOT NULL, \n\tplatform VARCHAR(255), \n\tuser_id VARCHAR(255), \n\tuser_name VARCHAR(255), \n\trunner_name VARCHAR(255), \n\tvariables TEXT, \n\trole VARCHAR(50), \n\tPRIMARY KEY (id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_monitoring_messages_bot_id ON monitoring_messages (bot_id)", + "CREATE INDEX ix_monitoring_messages_pipeline_id ON monitoring_messages (pipeline_id)", + "CREATE INDEX ix_monitoring_messages_session_id ON monitoring_messages (session_id)", + "CREATE INDEX ix_monitoring_messages_timestamp ON monitoring_messages (timestamp)", + "CREATE INDEX ix_monitoring_messages_workspace_session ON monitoring_messages (workspace_uuid, session_id)", + "CREATE INDEX ix_monitoring_messages_workspace_timestamp ON monitoring_messages (workspace_uuid, timestamp)", + "\nCREATE TABLE monitoring_sessions (\n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tbot_id VARCHAR(255) NOT NULL, \n\tsession_id VARCHAR(255) NOT NULL, \n\tbot_name VARCHAR(255) NOT NULL, \n\tpipeline_id VARCHAR(255) NOT NULL, \n\tpipeline_name VARCHAR(255) NOT NULL, \n\tmessage_count INTEGER NOT NULL, \n\tstart_time DATETIME NOT NULL, \n\tlast_activity DATETIME NOT NULL, \n\tis_active BOOLEAN NOT NULL, \n\tplatform VARCHAR(255), \n\tuser_id VARCHAR(255), \n\tuser_name VARCHAR(255), \n\tPRIMARY KEY (workspace_uuid, bot_id, session_id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_monitoring_sessions_bot_id ON monitoring_sessions (bot_id)", + "CREATE INDEX ix_monitoring_sessions_is_active ON monitoring_sessions (is_active)", + "CREATE INDEX ix_monitoring_sessions_last_activity ON monitoring_sessions (last_activity)", + "CREATE INDEX ix_monitoring_sessions_pipeline_id ON monitoring_sessions (pipeline_id)", + "CREATE INDEX ix_monitoring_sessions_start_time ON monitoring_sessions (start_time)", + "CREATE INDEX ix_monitoring_sessions_workspace_active ON monitoring_sessions (workspace_uuid, is_active)", + "CREATE INDEX ix_monitoring_sessions_workspace_activity ON monitoring_sessions (workspace_uuid, last_activity)", + "\nCREATE TABLE monitoring_tool_calls (\n\tid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\ttimestamp DATETIME NOT NULL, \n\ttool_name VARCHAR(255) NOT NULL, \n\ttool_source VARCHAR(50) NOT NULL, \n\tduration INTEGER NOT NULL, \n\tstatus VARCHAR(50) NOT NULL, \n\tbot_id VARCHAR(255) NOT NULL, \n\tbot_name VARCHAR(255) NOT NULL, \n\tpipeline_id VARCHAR(255) NOT NULL, \n\tpipeline_name VARCHAR(255) NOT NULL, \n\tsession_id VARCHAR(255), \n\tmessage_id VARCHAR(255), \n\targuments TEXT, \n\tresult TEXT, \n\terror_message TEXT, \n\tPRIMARY KEY (id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_monitoring_tool_calls_bot_id ON monitoring_tool_calls (bot_id)", + "CREATE INDEX ix_monitoring_tool_calls_message_id ON monitoring_tool_calls (message_id)", + "CREATE INDEX ix_monitoring_tool_calls_pipeline_id ON monitoring_tool_calls (pipeline_id)", + "CREATE INDEX ix_monitoring_tool_calls_session_id ON monitoring_tool_calls (session_id)", + "CREATE INDEX ix_monitoring_tool_calls_timestamp ON monitoring_tool_calls (timestamp)", + "CREATE INDEX ix_monitoring_tool_calls_workspace_session ON monitoring_tool_calls (workspace_uuid, session_id)", + "CREATE INDEX ix_monitoring_tool_calls_workspace_timestamp ON monitoring_tool_calls (workspace_uuid, timestamp)", + "\nCREATE TABLE plugin_settings (\n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tplugin_author VARCHAR(255) NOT NULL, \n\tplugin_name VARCHAR(255) NOT NULL, \n\tinstallation_uuid VARCHAR(36) NOT NULL, \n\tartifact_digest VARCHAR(64) NOT NULL, \n\truntime_revision INTEGER NOT NULL, \n\tenabled BOOLEAN NOT NULL, \n\tpriority INTEGER NOT NULL, \n\tconfig JSON NOT NULL, \n\tinstall_source VARCHAR(255) NOT NULL, \n\tinstall_info JSON NOT NULL, \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (workspace_uuid, plugin_author, plugin_name), \n\tCONSTRAINT uq_plugin_settings_installation_uuid UNIQUE (installation_uuid), \n\tCONSTRAINT ck_plugin_settings_runtime_revision_positive CHECK (runtime_revision >= 1), \n\tCONSTRAINT ck_plugin_settings_artifact_digest_length CHECK (length(artifact_digest) = 64), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_plugin_settings_workspace_enabled ON plugin_settings (workspace_uuid, enabled)", + "CREATE UNIQUE INDEX ix_plugin_settings_workspace_installation ON plugin_settings (workspace_uuid, installation_uuid)", + "\nCREATE TABLE support_admin_temporary_sessions (\n\tgrant_jti_hash VARCHAR(64) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tactor_account_uuid VARCHAR(36) NOT NULL, \n\tissued_at DATETIME NOT NULL, \n\texpires_at DATETIME NOT NULL, \n\trevoked_at DATETIME, \n\tlast_used_at DATETIME, \n\tPRIMARY KEY (grant_jti_hash), \n\tCONSTRAINT ck_support_admin_sessions_grant_jti_hash CHECK (length(grant_jti_hash) = 64), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_support_admin_sessions_workspace_expiry ON support_admin_temporary_sessions (workspace_uuid, expires_at)", + "\nCREATE TABLE webhooks (\n\tid INTEGER NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\turl VARCHAR(1024) NOT NULL, \n\tdescription VARCHAR(512), \n\tenabled BOOLEAN NOT NULL, \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_webhooks_workspace_name ON webhooks (workspace_uuid, name)", + "\nCREATE TABLE workspace_execution_states (\n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tinstance_uuid VARCHAR(255) NOT NULL, \n\tactive_generation BIGINT DEFAULT '1' NOT NULL, \n\tstate VARCHAR(32) DEFAULT 'active' NOT NULL, \n\twrite_fenced BOOLEAN DEFAULT 0 NOT NULL, \n\tsource VARCHAR(32) DEFAULT 'local' NOT NULL, \n\tdesired_state_revision BIGINT DEFAULT '0' NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (workspace_uuid), \n\tCONSTRAINT ck_workspace_execution_generation CHECK (active_generation > 0), \n\tCONSTRAINT ck_workspace_execution_state CHECK (state IN ('provisioning', 'active', 'migrating', 'draining', 'inactive')), \n\tCONSTRAINT ck_workspace_execution_source CHECK (source IN ('local', 'cloud')), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_workspace_execution_states_instance_state ON workspace_execution_states (instance_uuid, state)", + "\nCREATE TABLE workspace_invitations (\n\tuuid VARCHAR(36) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tnormalized_email VARCHAR(320) NOT NULL, \n\trole VARCHAR(32) NOT NULL, \n\ttoken_hash VARCHAR(255) NOT NULL, \n\tstatus VARCHAR(32) DEFAULT 'pending' NOT NULL, \n\texpires_at DATETIME NOT NULL, \n\taccepted_at DATETIME, \n\trevoked_at DATETIME, \n\tcreated_by_account_uuid VARCHAR(36) NOT NULL, \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT ck_workspace_invitations_role CHECK (role IN ('admin', 'developer', 'operator', 'viewer')), \n\tCONSTRAINT ck_workspace_invitations_status CHECK (status IN ('pending', 'accepted', 'revoked', 'expired')), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE, \n\tFOREIGN KEY(created_by_account_uuid) REFERENCES users (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE UNIQUE INDEX uq_workspace_invitations_pending_email ON workspace_invitations (workspace_uuid, normalized_email) WHERE status = 'pending'", + "CREATE UNIQUE INDEX uq_workspace_invitations_token_hash ON workspace_invitations (token_hash)", + "\nCREATE TABLE workspace_memberships (\n\tuuid VARCHAR(36) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\taccount_uuid VARCHAR(36) NOT NULL, \n\trole VARCHAR(32) NOT NULL, \n\tstatus VARCHAR(32) DEFAULT 'active' NOT NULL, \n\tinvited_by_account_uuid VARCHAR(36), \n\tjoined_at DATETIME, \n\tsource VARCHAR(32) DEFAULT 'local' NOT NULL, \n\tprojection_revision BIGINT DEFAULT '0' NOT NULL, \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_workspace_membership_account UNIQUE (workspace_uuid, account_uuid), \n\tCONSTRAINT ck_workspace_memberships_role CHECK (role IN ('owner', 'admin', 'developer', 'operator', 'viewer')), \n\tCONSTRAINT ck_workspace_memberships_status CHECK (status IN ('active', 'disabled', 'removed')), \n\tCONSTRAINT ck_workspace_memberships_source CHECK (source IN ('local', 'cloud_projection')), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE, \n\tFOREIGN KEY(account_uuid) REFERENCES users (uuid) ON DELETE CASCADE, \n\tFOREIGN KEY(invited_by_account_uuid) REFERENCES users (uuid) ON DELETE SET NULL\n)\n\n", + "CREATE INDEX ix_workspace_memberships_account_status ON workspace_memberships (account_uuid, status)", + "CREATE UNIQUE INDEX uq_workspace_memberships_one_active_owner ON workspace_memberships (workspace_uuid) WHERE role = 'owner' AND status = 'active'", + "\nCREATE TABLE workspace_metadata (\n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\t\"key\" VARCHAR(255) NOT NULL, \n\tvalue VARCHAR(255), \n\tPRIMARY KEY (workspace_uuid, \"key\"), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "\nCREATE TABLE bot_admins (\n\tid INTEGER NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tbot_uuid VARCHAR(255) NOT NULL, \n\tlauncher_type VARCHAR(64) NOT NULL, \n\tlauncher_id VARCHAR(255) NOT NULL, \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (id), \n\tCONSTRAINT uq_bot_admin UNIQUE (workspace_uuid, bot_uuid, launcher_type, launcher_id), \n\tCONSTRAINT fk_bot_admins_workspace_bot FOREIGN KEY(workspace_uuid, bot_uuid) REFERENCES bots (workspace_uuid, uuid) ON DELETE CASCADE, \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "\nCREATE TABLE codex_credentials (\n\tprovider_uuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tpayload JSON NOT NULL, \n\tversion INTEGER NOT NULL, \n\tlease_owner VARCHAR(64), \n\tlease_until FLOAT NOT NULL, \n\tPRIMARY KEY (provider_uuid), \n\tCONSTRAINT fk_codex_credentials_workspace_provider FOREIGN KEY(workspace_uuid, provider_uuid) REFERENCES model_providers (workspace_uuid, uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_codex_credentials_workspace ON codex_credentials (workspace_uuid)", + "\nCREATE TABLE embedding_models (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\tprovider_uuid VARCHAR(255) NOT NULL, \n\textra_args JSON NOT NULL, \n\tprefered_ranking INTEGER NOT NULL, \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT fk_embedding_models_workspace_provider FOREIGN KEY(workspace_uuid, provider_uuid) REFERENCES model_providers (workspace_uuid, uuid), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_embedding_models_workspace_name ON embedding_models (workspace_uuid, name)", + "CREATE INDEX ix_embedding_models_workspace_provider ON embedding_models (workspace_uuid, provider_uuid)", + "\nCREATE TABLE knowledge_base_files (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tkb_id VARCHAR(255), \n\tfile_name VARCHAR, \n\textension VARCHAR, \n\tcreated_at DATETIME, \n\tstatus VARCHAR, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_knowledge_base_files_workspace_uuid UNIQUE (workspace_uuid, uuid), \n\tCONSTRAINT fk_knowledge_base_files_workspace_kb FOREIGN KEY(workspace_uuid, kb_id) REFERENCES knowledge_bases (workspace_uuid, uuid) ON DELETE CASCADE, \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_knowledge_base_files_workspace_kb ON knowledge_base_files (workspace_uuid, kb_id)", + "\nCREATE TABLE llm_models (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\tprovider_uuid VARCHAR(255) NOT NULL, \n\tabilities JSON NOT NULL, \n\tcontext_length INTEGER, \n\treasoning_config JSON DEFAULT '{\"level\":\"provider_default\"}' NOT NULL, \n\textra_args JSON NOT NULL, \n\tprefered_ranking INTEGER NOT NULL, \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT fk_llm_models_workspace_provider FOREIGN KEY(workspace_uuid, provider_uuid) REFERENCES model_providers (workspace_uuid, uuid), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_llm_models_workspace_name ON llm_models (workspace_uuid, name)", + "CREATE INDEX ix_llm_models_workspace_provider ON llm_models (workspace_uuid, provider_uuid)", + "\nCREATE TABLE pipeline_run_records (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tpipeline_uuid VARCHAR(255) NOT NULL, \n\tstatus VARCHAR(255) NOT NULL, \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tstarted_at DATETIME NOT NULL, \n\tfinished_at DATETIME NOT NULL, \n\tresult JSON NOT NULL, \n\tknowledge_base_uuid VARCHAR(255), \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT fk_pipeline_run_records_workspace_pipeline FOREIGN KEY(workspace_uuid, pipeline_uuid) REFERENCES legacy_pipelines (workspace_uuid, uuid) ON DELETE CASCADE, \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_pipeline_run_records_workspace_created ON pipeline_run_records (workspace_uuid, created_at)", + "CREATE INDEX ix_pipeline_run_records_workspace_pipeline ON pipeline_run_records (workspace_uuid, pipeline_uuid)", + "\nCREATE TABLE rerank_models (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\tprovider_uuid VARCHAR(255) NOT NULL, \n\textra_args JSON NOT NULL, \n\tprefered_ranking INTEGER NOT NULL, \n\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT fk_rerank_models_workspace_provider FOREIGN KEY(workspace_uuid, provider_uuid) REFERENCES model_providers (workspace_uuid, uuid), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_rerank_models_workspace_name ON rerank_models (workspace_uuid, name)", + "CREATE INDEX ix_rerank_models_workspace_provider ON rerank_models (workspace_uuid, provider_uuid)", + "\nCREATE TABLE knowledge_base_chunks (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tfile_id VARCHAR(255), \n\ttext TEXT, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT fk_knowledge_base_chunks_workspace_file FOREIGN KEY(workspace_uuid, file_id) REFERENCES knowledge_base_files (workspace_uuid, uuid) ON DELETE CASCADE, \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_knowledge_base_chunks_workspace_file ON knowledge_base_chunks (workspace_uuid, file_id)" + ], + "postgresql": [ + "\nCREATE TABLE directory_projection_inbox (\n\tinstance_uuid VARCHAR(255) NOT NULL, \n\tevent_uuid VARCHAR(36) NOT NULL, \n\tcursor BIGINT NOT NULL, \n\tevent_type VARCHAR(128) NOT NULL, \n\trevision BIGINT NOT NULL, \n\tfingerprint TEXT NOT NULL, \n\treceived_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, \n\tapplied_at TIMESTAMP WITH TIME ZONE, \n\tPRIMARY KEY (instance_uuid, event_uuid), \n\tCONSTRAINT uq_directory_projection_inbox_cursor UNIQUE (instance_uuid, cursor), \n\tCONSTRAINT ck_directory_projection_inbox_cursor CHECK (cursor > 0), \n\tCONSTRAINT ck_directory_projection_inbox_revision CHECK (revision > 0), \n\tCONSTRAINT ck_directory_projection_inbox_fingerprint CHECK (length(fingerprint) = 64)\n)\n\n", + "CREATE INDEX ix_directory_projection_inbox_pending ON directory_projection_inbox (instance_uuid, applied_at, cursor)", + "\nCREATE TABLE directory_projection_states (\n\tinstance_uuid VARCHAR(255) NOT NULL, \n\tcursor BIGINT DEFAULT '0' NOT NULL, \n\tsnapshot_coverage_cursor BIGINT DEFAULT '0' NOT NULL, \n\tsnapshot_fingerprint TEXT NOT NULL, \n\tlast_applied_at TIMESTAMP WITH TIME ZONE NOT NULL, \n\tlease_expires_at TIMESTAMP WITH TIME ZONE, \n\tPRIMARY KEY (instance_uuid), \n\tCONSTRAINT ck_directory_projection_state_cursor CHECK (cursor >= 0), \n\tCONSTRAINT ck_directory_projection_state_snapshot_coverage CHECK (snapshot_coverage_cursor >= 0 AND snapshot_coverage_cursor <= cursor), \n\tCONSTRAINT ck_directory_projection_state_fingerprint CHECK (length(snapshot_fingerprint) = 64)\n)\n\n", + "\nCREATE TABLE metadata (\n\tkey VARCHAR(255) NOT NULL, \n\tvalue VARCHAR(255), \n\tPRIMARY KEY (key)\n)\n\n", + "\nCREATE TABLE users (\n\tid SERIAL NOT NULL, \n\tuuid VARCHAR(36) NOT NULL, \n\t\"user\" VARCHAR(255) NOT NULL, \n\tnormalized_email VARCHAR(320) NOT NULL, \n\tpassword VARCHAR(255) NOT NULL, \n\tstatus VARCHAR(32) DEFAULT 'active' NOT NULL, \n\tsource VARCHAR(32) DEFAULT 'local' NOT NULL, \n\tprojection_revision BIGINT DEFAULT '0' NOT NULL, \n\taccount_type VARCHAR(32) DEFAULT 'local' NOT NULL, \n\tspace_account_uuid VARCHAR(255), \n\tspace_access_token TEXT, \n\tspace_refresh_token TEXT, \n\tspace_access_token_expires_at TIMESTAMP WITHOUT TIME ZONE, \n\tspace_api_key VARCHAR(255), \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (id), \n\tCONSTRAINT ck_users_normalized_email CHECK (normalized_email = trim(normalized_email) AND length(normalized_email) > 0 AND length(normalized_email) <= 320), \n\tCONSTRAINT ck_users_status CHECK (status IN ('active', 'disabled', 'deleted')), \n\tCONSTRAINT ck_users_source CHECK (source IN ('local', 'cloud_projection'))\n)\n\n", + "CREATE UNIQUE INDEX uq_users_normalized_email ON users (normalized_email)", + "CREATE UNIQUE INDEX uq_users_uuid ON users (uuid)", + "\nCREATE TABLE workspaces (\n\tuuid VARCHAR(36) NOT NULL, \n\tinstance_uuid VARCHAR(255) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\tslug VARCHAR(255) NOT NULL, \n\ttype VARCHAR(32) DEFAULT 'team' NOT NULL, \n\tstatus VARCHAR(32) DEFAULT 'active' NOT NULL, \n\tcreated_by_account_uuid VARCHAR(36), \n\tsource VARCHAR(32) DEFAULT 'local' NOT NULL, \n\tprojection_revision BIGINT DEFAULT '0' NOT NULL, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_workspaces_instance_slug UNIQUE (instance_uuid, slug), \n\tCONSTRAINT ck_workspaces_type CHECK (type IN ('personal', 'team')), \n\tCONSTRAINT ck_workspaces_status CHECK (status IN ('provisioning', 'active', 'suspended', 'archived', 'deleted')), \n\tCONSTRAINT ck_workspaces_source CHECK (source IN ('local', 'cloud_projection')), \n\tFOREIGN KEY(created_by_account_uuid) REFERENCES users (uuid) ON DELETE SET NULL\n)\n\n", + "CREATE INDEX ix_workspaces_instance_status ON workspaces (instance_uuid, status)", + "CREATE UNIQUE INDEX uq_workspaces_local_instance ON workspaces (instance_uuid) WHERE source = 'local'", + "\nCREATE TABLE api_keys (\n\tid SERIAL NOT NULL, \n\tuuid VARCHAR(36) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tcreated_by_account_uuid VARCHAR(36), \n\tname VARCHAR(255) NOT NULL, \n\tkey_hash VARCHAR(64) NOT NULL, \n\tscopes JSON DEFAULT '[]' NOT NULL, \n\tstatus VARCHAR(32) DEFAULT 'active' NOT NULL, \n\texpires_at TIMESTAMP WITHOUT TIME ZONE, \n\tlast_used_at TIMESTAMP WITHOUT TIME ZONE, \n\tdescription VARCHAR(512), \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (id), \n\tCONSTRAINT ck_api_keys_status CHECK (status IN ('active', 'revoked')), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE, \n\tFOREIGN KEY(created_by_account_uuid) REFERENCES users (uuid) ON DELETE SET NULL\n)\n\n", + "CREATE INDEX ix_api_keys_workspace_name ON api_keys (workspace_uuid, name)", + "CREATE INDEX ix_api_keys_workspace_status ON api_keys (workspace_uuid, status)", + "CREATE UNIQUE INDEX uq_api_keys_key_hash ON api_keys (key_hash)", + "CREATE UNIQUE INDEX uq_api_keys_uuid ON api_keys (uuid)", + "\nCREATE TABLE binary_storages (\n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tunique_key VARCHAR(255) NOT NULL, \n\tkey VARCHAR(255) NOT NULL, \n\towner_type VARCHAR(255) NOT NULL, \n\towner VARCHAR(255) NOT NULL, \n\tvalue BYTEA NOT NULL, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (workspace_uuid, unique_key), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_binary_storages_workspace_owner ON binary_storages (workspace_uuid, owner_type, owner)", + "\nCREATE TABLE bots (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\tdescription VARCHAR(255) NOT NULL, \n\tadapter VARCHAR(255) NOT NULL, \n\tadapter_config JSON NOT NULL, \n\tenable BOOLEAN NOT NULL, \n\tuse_pipeline_name VARCHAR(255), \n\tuse_pipeline_uuid VARCHAR(255), \n\tpipeline_routing_rules JSON DEFAULT '[]' NOT NULL, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_bots_workspace_uuid UNIQUE (workspace_uuid, uuid), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_bots_workspace_name ON bots (workspace_uuid, name)", + "\nCREATE TABLE knowledge_bases (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR, \n\tdescription TEXT, \n\temoji VARCHAR(10), \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE, \n\tknowledge_engine_plugin_id VARCHAR, \n\tcollection_id VARCHAR, \n\tlegacy_vector_collection BOOLEAN DEFAULT false NOT NULL, \n\tcreation_settings JSON, \n\tretrieval_settings JSON, \n\tembedding_dimension INTEGER, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_knowledge_bases_workspace_uuid UNIQUE (workspace_uuid, uuid), \n\tCONSTRAINT ck_knowledge_bases_embedding_dimension_positive CHECK (embedding_dimension IS NULL OR embedding_dimension > 0), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_knowledge_bases_name ON knowledge_bases (name)", + "CREATE INDEX ix_knowledge_bases_workspace_name ON knowledge_bases (workspace_uuid, name)", + "CREATE UNIQUE INDEX uq_knowledge_bases_workspace_collection ON knowledge_bases (workspace_uuid, collection_id) WHERE collection_id IS NOT NULL", + "\nCREATE TABLE legacy_pipelines (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\tdescription VARCHAR(255) NOT NULL, \n\temoji VARCHAR(10), \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tfor_version VARCHAR(255) NOT NULL, \n\tis_default BOOLEAN NOT NULL, \n\tstages JSON NOT NULL, \n\tconfig JSON NOT NULL, \n\textensions_preferences JSON NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_legacy_pipelines_workspace_uuid UNIQUE (workspace_uuid, uuid), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_legacy_pipelines_workspace_default ON legacy_pipelines (workspace_uuid, is_default)", + "CREATE INDEX ix_legacy_pipelines_workspace_name ON legacy_pipelines (workspace_uuid, name)", + "\nCREATE TABLE mcp_servers (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\tenable BOOLEAN NOT NULL, \n\tmode VARCHAR(255) NOT NULL, \n\textra_args JSON NOT NULL, \n\treadme TEXT DEFAULT '' NOT NULL, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_mcp_servers_workspace_name UNIQUE (workspace_uuid, name), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_mcp_servers_workspace_enable ON mcp_servers (workspace_uuid, enable)", + "\nCREATE TABLE model_providers (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\trequester VARCHAR(255) NOT NULL, \n\tbase_url VARCHAR(512) NOT NULL, \n\tapi_keys JSON NOT NULL, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_model_providers_workspace_uuid UNIQUE (workspace_uuid, uuid), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_model_providers_workspace_name ON model_providers (workspace_uuid, name)", + "CREATE INDEX ix_model_providers_workspace_requester ON model_providers (workspace_uuid, requester)", + "\nCREATE TABLE monitoring_embedding_calls (\n\tid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\ttimestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL, \n\tmodel_name VARCHAR(255) NOT NULL, \n\tprompt_tokens INTEGER NOT NULL, \n\ttotal_tokens INTEGER NOT NULL, \n\tduration INTEGER NOT NULL, \n\tinput_count INTEGER NOT NULL, \n\tstatus VARCHAR(50) NOT NULL, \n\terror_message TEXT, \n\tknowledge_base_id VARCHAR(255), \n\tquery_text TEXT, \n\tsession_id VARCHAR(255), \n\tmessage_id VARCHAR(255), \n\tcall_type VARCHAR(50), \n\tPRIMARY KEY (id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_monitoring_embedding_calls_knowledge_base_id ON monitoring_embedding_calls (knowledge_base_id)", + "CREATE INDEX ix_monitoring_embedding_calls_message_id ON monitoring_embedding_calls (message_id)", + "CREATE INDEX ix_monitoring_embedding_calls_session_id ON monitoring_embedding_calls (session_id)", + "CREATE INDEX ix_monitoring_embedding_calls_timestamp ON monitoring_embedding_calls (timestamp)", + "CREATE INDEX ix_monitoring_embedding_calls_workspace_kb ON monitoring_embedding_calls (workspace_uuid, knowledge_base_id)", + "CREATE INDEX ix_monitoring_embedding_calls_workspace_timestamp ON monitoring_embedding_calls (workspace_uuid, timestamp)", + "\nCREATE TABLE monitoring_errors (\n\tid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\ttimestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL, \n\terror_type VARCHAR(255) NOT NULL, \n\terror_message TEXT NOT NULL, \n\tbot_id VARCHAR(255) NOT NULL, \n\tbot_name VARCHAR(255) NOT NULL, \n\tpipeline_id VARCHAR(255) NOT NULL, \n\tpipeline_name VARCHAR(255) NOT NULL, \n\tsession_id VARCHAR(255), \n\tstack_trace TEXT, \n\tmessage_id VARCHAR(255), \n\tPRIMARY KEY (id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_monitoring_errors_bot_id ON monitoring_errors (bot_id)", + "CREATE INDEX ix_monitoring_errors_message_id ON monitoring_errors (message_id)", + "CREATE INDEX ix_monitoring_errors_pipeline_id ON monitoring_errors (pipeline_id)", + "CREATE INDEX ix_monitoring_errors_timestamp ON monitoring_errors (timestamp)", + "CREATE INDEX ix_monitoring_errors_workspace_session ON monitoring_errors (workspace_uuid, session_id)", + "CREATE INDEX ix_monitoring_errors_workspace_timestamp ON monitoring_errors (workspace_uuid, timestamp)", + "\nCREATE TABLE monitoring_feedback (\n\tid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\ttimestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL, \n\tfeedback_id VARCHAR(255) NOT NULL, \n\tfeedback_type INTEGER NOT NULL, \n\tfeedback_content TEXT, \n\tinaccurate_reasons TEXT, \n\tbot_id VARCHAR(255), \n\tbot_name VARCHAR(255), \n\tpipeline_id VARCHAR(255), \n\tpipeline_name VARCHAR(255), \n\tsession_id VARCHAR(255), \n\tmessage_id VARCHAR(255), \n\tstream_id VARCHAR(255), \n\tuser_id VARCHAR(255), \n\tplatform VARCHAR(255), \n\tPRIMARY KEY (id), \n\tCONSTRAINT uq_monitoring_feedback_workspace_feedback_id UNIQUE (workspace_uuid, feedback_id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_monitoring_feedback_bot_id ON monitoring_feedback (bot_id)", + "CREATE INDEX ix_monitoring_feedback_feedback_id ON monitoring_feedback (feedback_id)", + "CREATE INDEX ix_monitoring_feedback_message_id ON monitoring_feedback (message_id)", + "CREATE INDEX ix_monitoring_feedback_pipeline_id ON monitoring_feedback (pipeline_id)", + "CREATE INDEX ix_monitoring_feedback_session_id ON monitoring_feedback (session_id)", + "CREATE INDEX ix_monitoring_feedback_stream_id ON monitoring_feedback (stream_id)", + "CREATE INDEX ix_monitoring_feedback_timestamp ON monitoring_feedback (timestamp)", + "CREATE INDEX ix_monitoring_feedback_workspace_session ON monitoring_feedback (workspace_uuid, session_id)", + "CREATE INDEX ix_monitoring_feedback_workspace_timestamp ON monitoring_feedback (workspace_uuid, timestamp)", + "\nCREATE TABLE monitoring_llm_calls (\n\tid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\ttimestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL, \n\tmodel_name VARCHAR(255) NOT NULL, \n\tinput_tokens INTEGER NOT NULL, \n\toutput_tokens INTEGER NOT NULL, \n\ttotal_tokens INTEGER NOT NULL, \n\tduration INTEGER NOT NULL, \n\tcost FLOAT, \n\tstatus VARCHAR(50) NOT NULL, \n\tbot_id VARCHAR(255) NOT NULL, \n\tbot_name VARCHAR(255) NOT NULL, \n\tpipeline_id VARCHAR(255) NOT NULL, \n\tpipeline_name VARCHAR(255) NOT NULL, \n\tsession_id VARCHAR(255) NOT NULL, \n\terror_message TEXT, \n\tmessage_id VARCHAR(255), \n\tPRIMARY KEY (id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_monitoring_llm_calls_bot_id ON monitoring_llm_calls (bot_id)", + "CREATE INDEX ix_monitoring_llm_calls_message_id ON monitoring_llm_calls (message_id)", + "CREATE INDEX ix_monitoring_llm_calls_pipeline_id ON monitoring_llm_calls (pipeline_id)", + "CREATE INDEX ix_monitoring_llm_calls_timestamp ON monitoring_llm_calls (timestamp)", + "CREATE INDEX ix_monitoring_llm_calls_workspace_session ON monitoring_llm_calls (workspace_uuid, session_id)", + "CREATE INDEX ix_monitoring_llm_calls_workspace_timestamp ON monitoring_llm_calls (workspace_uuid, timestamp)", + "\nCREATE TABLE monitoring_messages (\n\tid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\ttimestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL, \n\tbot_id VARCHAR(255) NOT NULL, \n\tbot_name VARCHAR(255) NOT NULL, \n\tpipeline_id VARCHAR(255) NOT NULL, \n\tpipeline_name VARCHAR(255) NOT NULL, \n\tmessage_content TEXT NOT NULL, \n\tsession_id VARCHAR(255) NOT NULL, \n\tstatus VARCHAR(50) NOT NULL, \n\tlevel VARCHAR(50) NOT NULL, \n\tplatform VARCHAR(255), \n\tuser_id VARCHAR(255), \n\tuser_name VARCHAR(255), \n\trunner_name VARCHAR(255), \n\tvariables TEXT, \n\trole VARCHAR(50), \n\tPRIMARY KEY (id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_monitoring_messages_bot_id ON monitoring_messages (bot_id)", + "CREATE INDEX ix_monitoring_messages_pipeline_id ON monitoring_messages (pipeline_id)", + "CREATE INDEX ix_monitoring_messages_session_id ON monitoring_messages (session_id)", + "CREATE INDEX ix_monitoring_messages_timestamp ON monitoring_messages (timestamp)", + "CREATE INDEX ix_monitoring_messages_workspace_session ON monitoring_messages (workspace_uuid, session_id)", + "CREATE INDEX ix_monitoring_messages_workspace_timestamp ON monitoring_messages (workspace_uuid, timestamp)", + "\nCREATE TABLE monitoring_sessions (\n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tbot_id VARCHAR(255) NOT NULL, \n\tsession_id VARCHAR(255) NOT NULL, \n\tbot_name VARCHAR(255) NOT NULL, \n\tpipeline_id VARCHAR(255) NOT NULL, \n\tpipeline_name VARCHAR(255) NOT NULL, \n\tmessage_count INTEGER NOT NULL, \n\tstart_time TIMESTAMP WITHOUT TIME ZONE NOT NULL, \n\tlast_activity TIMESTAMP WITHOUT TIME ZONE NOT NULL, \n\tis_active BOOLEAN NOT NULL, \n\tplatform VARCHAR(255), \n\tuser_id VARCHAR(255), \n\tuser_name VARCHAR(255), \n\tPRIMARY KEY (workspace_uuid, bot_id, session_id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_monitoring_sessions_bot_id ON monitoring_sessions (bot_id)", + "CREATE INDEX ix_monitoring_sessions_is_active ON monitoring_sessions (is_active)", + "CREATE INDEX ix_monitoring_sessions_last_activity ON monitoring_sessions (last_activity)", + "CREATE INDEX ix_monitoring_sessions_pipeline_id ON monitoring_sessions (pipeline_id)", + "CREATE INDEX ix_monitoring_sessions_start_time ON monitoring_sessions (start_time)", + "CREATE INDEX ix_monitoring_sessions_workspace_active ON monitoring_sessions (workspace_uuid, is_active)", + "CREATE INDEX ix_monitoring_sessions_workspace_activity ON monitoring_sessions (workspace_uuid, last_activity)", + "\nCREATE TABLE monitoring_tool_calls (\n\tid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\ttimestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL, \n\ttool_name VARCHAR(255) NOT NULL, \n\ttool_source VARCHAR(50) NOT NULL, \n\tduration INTEGER NOT NULL, \n\tstatus VARCHAR(50) NOT NULL, \n\tbot_id VARCHAR(255) NOT NULL, \n\tbot_name VARCHAR(255) NOT NULL, \n\tpipeline_id VARCHAR(255) NOT NULL, \n\tpipeline_name VARCHAR(255) NOT NULL, \n\tsession_id VARCHAR(255), \n\tmessage_id VARCHAR(255), \n\targuments TEXT, \n\tresult TEXT, \n\terror_message TEXT, \n\tPRIMARY KEY (id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_monitoring_tool_calls_bot_id ON monitoring_tool_calls (bot_id)", + "CREATE INDEX ix_monitoring_tool_calls_message_id ON monitoring_tool_calls (message_id)", + "CREATE INDEX ix_monitoring_tool_calls_pipeline_id ON monitoring_tool_calls (pipeline_id)", + "CREATE INDEX ix_monitoring_tool_calls_session_id ON monitoring_tool_calls (session_id)", + "CREATE INDEX ix_monitoring_tool_calls_timestamp ON monitoring_tool_calls (timestamp)", + "CREATE INDEX ix_monitoring_tool_calls_workspace_session ON monitoring_tool_calls (workspace_uuid, session_id)", + "CREATE INDEX ix_monitoring_tool_calls_workspace_timestamp ON monitoring_tool_calls (workspace_uuid, timestamp)", + "\nCREATE TABLE plugin_settings (\n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tplugin_author VARCHAR(255) NOT NULL, \n\tplugin_name VARCHAR(255) NOT NULL, \n\tinstallation_uuid VARCHAR(36) NOT NULL, \n\tartifact_digest VARCHAR(64) NOT NULL, \n\truntime_revision INTEGER NOT NULL, \n\tenabled BOOLEAN NOT NULL, \n\tpriority INTEGER NOT NULL, \n\tconfig JSON NOT NULL, \n\tinstall_source VARCHAR(255) NOT NULL, \n\tinstall_info JSON NOT NULL, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (workspace_uuid, plugin_author, plugin_name), \n\tCONSTRAINT uq_plugin_settings_installation_uuid UNIQUE (installation_uuid), \n\tCONSTRAINT ck_plugin_settings_runtime_revision_positive CHECK (runtime_revision >= 1), \n\tCONSTRAINT ck_plugin_settings_artifact_digest_length CHECK (length(artifact_digest) = 64), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_plugin_settings_workspace_enabled ON plugin_settings (workspace_uuid, enabled)", + "CREATE UNIQUE INDEX ix_plugin_settings_workspace_installation ON plugin_settings (workspace_uuid, installation_uuid)", + "\nCREATE TABLE support_admin_temporary_sessions (\n\tgrant_jti_hash VARCHAR(64) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tactor_account_uuid VARCHAR(36) NOT NULL, \n\tissued_at TIMESTAMP WITHOUT TIME ZONE NOT NULL, \n\texpires_at TIMESTAMP WITHOUT TIME ZONE NOT NULL, \n\trevoked_at TIMESTAMP WITHOUT TIME ZONE, \n\tlast_used_at TIMESTAMP WITHOUT TIME ZONE, \n\tPRIMARY KEY (grant_jti_hash), \n\tCONSTRAINT ck_support_admin_sessions_grant_jti_hash CHECK (length(grant_jti_hash) = 64), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_support_admin_sessions_workspace_expiry ON support_admin_temporary_sessions (workspace_uuid, expires_at)", + "\nCREATE TABLE webhooks (\n\tid SERIAL NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\turl VARCHAR(1024) NOT NULL, \n\tdescription VARCHAR(512), \n\tenabled BOOLEAN NOT NULL, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (id), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_webhooks_workspace_name ON webhooks (workspace_uuid, name)", + "\nCREATE TABLE workspace_execution_states (\n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tinstance_uuid VARCHAR(255) NOT NULL, \n\tactive_generation BIGINT DEFAULT '1' NOT NULL, \n\tstate VARCHAR(32) DEFAULT 'active' NOT NULL, \n\twrite_fenced BOOLEAN DEFAULT false NOT NULL, \n\tsource VARCHAR(32) DEFAULT 'local' NOT NULL, \n\tdesired_state_revision BIGINT DEFAULT '0' NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (workspace_uuid), \n\tCONSTRAINT ck_workspace_execution_generation CHECK (active_generation > 0), \n\tCONSTRAINT ck_workspace_execution_state CHECK (state IN ('provisioning', 'active', 'migrating', 'draining', 'inactive')), \n\tCONSTRAINT ck_workspace_execution_source CHECK (source IN ('local', 'cloud')), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_workspace_execution_states_instance_state ON workspace_execution_states (instance_uuid, state)", + "\nCREATE TABLE workspace_invitations (\n\tuuid VARCHAR(36) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tnormalized_email VARCHAR(320) NOT NULL, \n\trole VARCHAR(32) NOT NULL, \n\ttoken_hash VARCHAR(255) NOT NULL, \n\tstatus VARCHAR(32) DEFAULT 'pending' NOT NULL, \n\texpires_at TIMESTAMP WITHOUT TIME ZONE NOT NULL, \n\taccepted_at TIMESTAMP WITHOUT TIME ZONE, \n\trevoked_at TIMESTAMP WITHOUT TIME ZONE, \n\tcreated_by_account_uuid VARCHAR(36) NOT NULL, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT ck_workspace_invitations_role CHECK (role IN ('admin', 'developer', 'operator', 'viewer')), \n\tCONSTRAINT ck_workspace_invitations_status CHECK (status IN ('pending', 'accepted', 'revoked', 'expired')), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE, \n\tFOREIGN KEY(created_by_account_uuid) REFERENCES users (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE UNIQUE INDEX uq_workspace_invitations_pending_email ON workspace_invitations (workspace_uuid, normalized_email) WHERE status = 'pending'", + "CREATE UNIQUE INDEX uq_workspace_invitations_token_hash ON workspace_invitations (token_hash)", + "\nCREATE TABLE workspace_memberships (\n\tuuid VARCHAR(36) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\taccount_uuid VARCHAR(36) NOT NULL, \n\trole VARCHAR(32) NOT NULL, \n\tstatus VARCHAR(32) DEFAULT 'active' NOT NULL, \n\tinvited_by_account_uuid VARCHAR(36), \n\tjoined_at TIMESTAMP WITHOUT TIME ZONE, \n\tsource VARCHAR(32) DEFAULT 'local' NOT NULL, \n\tprojection_revision BIGINT DEFAULT '0' NOT NULL, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_workspace_membership_account UNIQUE (workspace_uuid, account_uuid), \n\tCONSTRAINT ck_workspace_memberships_role CHECK (role IN ('owner', 'admin', 'developer', 'operator', 'viewer')), \n\tCONSTRAINT ck_workspace_memberships_status CHECK (status IN ('active', 'disabled', 'removed')), \n\tCONSTRAINT ck_workspace_memberships_source CHECK (source IN ('local', 'cloud_projection')), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE, \n\tFOREIGN KEY(account_uuid) REFERENCES users (uuid) ON DELETE CASCADE, \n\tFOREIGN KEY(invited_by_account_uuid) REFERENCES users (uuid) ON DELETE SET NULL\n)\n\n", + "CREATE INDEX ix_workspace_memberships_account_status ON workspace_memberships (account_uuid, status)", + "CREATE UNIQUE INDEX uq_workspace_memberships_one_active_owner ON workspace_memberships (workspace_uuid) WHERE role = 'owner' AND status = 'active'", + "\nCREATE TABLE workspace_metadata (\n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tkey VARCHAR(255) NOT NULL, \n\tvalue VARCHAR(255), \n\tPRIMARY KEY (workspace_uuid, key), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "\nCREATE TABLE bot_admins (\n\tid SERIAL NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tbot_uuid VARCHAR(255) NOT NULL, \n\tlauncher_type VARCHAR(64) NOT NULL, \n\tlauncher_id VARCHAR(255) NOT NULL, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (id), \n\tCONSTRAINT uq_bot_admin UNIQUE (workspace_uuid, bot_uuid, launcher_type, launcher_id), \n\tCONSTRAINT fk_bot_admins_workspace_bot FOREIGN KEY(workspace_uuid, bot_uuid) REFERENCES bots (workspace_uuid, uuid) ON DELETE CASCADE, \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "\nCREATE TABLE codex_credentials (\n\tprovider_uuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tpayload JSON NOT NULL, \n\tversion INTEGER NOT NULL, \n\tlease_owner VARCHAR(64), \n\tlease_until FLOAT NOT NULL, \n\tPRIMARY KEY (provider_uuid), \n\tCONSTRAINT fk_codex_credentials_workspace_provider FOREIGN KEY(workspace_uuid, provider_uuid) REFERENCES model_providers (workspace_uuid, uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_codex_credentials_workspace ON codex_credentials (workspace_uuid)", + "\nCREATE TABLE embedding_models (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\tprovider_uuid VARCHAR(255) NOT NULL, \n\textra_args JSON NOT NULL, \n\tprefered_ranking INTEGER NOT NULL, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT fk_embedding_models_workspace_provider FOREIGN KEY(workspace_uuid, provider_uuid) REFERENCES model_providers (workspace_uuid, uuid), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_embedding_models_workspace_name ON embedding_models (workspace_uuid, name)", + "CREATE INDEX ix_embedding_models_workspace_provider ON embedding_models (workspace_uuid, provider_uuid)", + "\nCREATE TABLE knowledge_base_files (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tkb_id VARCHAR(255), \n\tfile_name VARCHAR, \n\textension VARCHAR, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE, \n\tstatus VARCHAR, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT uq_knowledge_base_files_workspace_uuid UNIQUE (workspace_uuid, uuid), \n\tCONSTRAINT fk_knowledge_base_files_workspace_kb FOREIGN KEY(workspace_uuid, kb_id) REFERENCES knowledge_bases (workspace_uuid, uuid) ON DELETE CASCADE, \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_knowledge_base_files_workspace_kb ON knowledge_base_files (workspace_uuid, kb_id)", + "\nCREATE TABLE llm_models (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\tprovider_uuid VARCHAR(255) NOT NULL, \n\tabilities JSON NOT NULL, \n\tcontext_length INTEGER, \n\treasoning_config JSON DEFAULT '{\"level\":\"provider_default\"}' NOT NULL, \n\textra_args JSON NOT NULL, \n\tprefered_ranking INTEGER NOT NULL, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT fk_llm_models_workspace_provider FOREIGN KEY(workspace_uuid, provider_uuid) REFERENCES model_providers (workspace_uuid, uuid), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_llm_models_workspace_name ON llm_models (workspace_uuid, name)", + "CREATE INDEX ix_llm_models_workspace_provider ON llm_models (workspace_uuid, provider_uuid)", + "\nCREATE TABLE pipeline_run_records (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tpipeline_uuid VARCHAR(255) NOT NULL, \n\tstatus VARCHAR(255) NOT NULL, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tstarted_at TIMESTAMP WITHOUT TIME ZONE NOT NULL, \n\tfinished_at TIMESTAMP WITHOUT TIME ZONE NOT NULL, \n\tresult JSON NOT NULL, \n\tknowledge_base_uuid VARCHAR(255), \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT fk_pipeline_run_records_workspace_pipeline FOREIGN KEY(workspace_uuid, pipeline_uuid) REFERENCES legacy_pipelines (workspace_uuid, uuid) ON DELETE CASCADE, \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_pipeline_run_records_workspace_created ON pipeline_run_records (workspace_uuid, created_at)", + "CREATE INDEX ix_pipeline_run_records_workspace_pipeline ON pipeline_run_records (workspace_uuid, pipeline_uuid)", + "\nCREATE TABLE rerank_models (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tname VARCHAR(255) NOT NULL, \n\tprovider_uuid VARCHAR(255) NOT NULL, \n\textra_args JSON NOT NULL, \n\tprefered_ranking INTEGER NOT NULL, \n\tcreated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tupdated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT fk_rerank_models_workspace_provider FOREIGN KEY(workspace_uuid, provider_uuid) REFERENCES model_providers (workspace_uuid, uuid), \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_rerank_models_workspace_name ON rerank_models (workspace_uuid, name)", + "CREATE INDEX ix_rerank_models_workspace_provider ON rerank_models (workspace_uuid, provider_uuid)", + "\nCREATE TABLE knowledge_base_chunks (\n\tuuid VARCHAR(255) NOT NULL, \n\tworkspace_uuid VARCHAR(36) NOT NULL, \n\tfile_id VARCHAR(255), \n\ttext TEXT, \n\tPRIMARY KEY (uuid), \n\tCONSTRAINT fk_knowledge_base_chunks_workspace_file FOREIGN KEY(workspace_uuid, file_id) REFERENCES knowledge_base_files (workspace_uuid, uuid) ON DELETE CASCADE, \n\tUNIQUE (uuid), \n\tFOREIGN KEY(workspace_uuid) REFERENCES workspaces (uuid) ON DELETE CASCADE\n)\n\n", + "CREATE INDEX ix_knowledge_base_chunks_workspace_file ON knowledge_base_chunks (workspace_uuid, file_id)" + ] + } +} diff --git a/tests/integration/persistence/test_release_41011_upgrade.py b/tests/integration/persistence/test_release_41011_upgrade.py new file mode 100644 index 000000000..ad73be4e6 --- /dev/null +++ b/tests/integration/persistence/test_release_41011_upgrade.py @@ -0,0 +1,130 @@ +"""Upgrade the immutable v4.10.11 ORM schema, not current metadata.""" + +import json + +import pytest +import sqlalchemy as sa +from alembic.autogenerate import compare_metadata +from alembic.migration import MigrationContext + +from langbot.pkg.entity.persistence.base import Base +from langbot.pkg.persistence.alembic_runner import run_alembic_upgrade +from tests.integration.persistence.test_migration_branch_convergence import ( + FIXTURES, + _seed_common, +) + + +@pytest.fixture(params=['sqlite', 'postgresql']) +async def convergence_engine(request, tmp_path): + import os + import uuid + from sqlalchemy.ext.asyncio import create_async_engine + + if request.param == 'sqlite': + engine = create_async_engine(f'sqlite+aiosqlite:///{tmp_path / "release.db"}') + try: + yield engine + finally: + await engine.dispose() + return + url = os.environ.get('TEST_POSTGRES_URL') + if not url: + pytest.skip('TEST_POSTGRES_URL required for disposable PostgreSQL') + name = 'release_audit_' + uuid.uuid4().hex + admin = create_async_engine(url, isolation_level='AUTOCOMMIT') + async with admin.connect() as conn: + await conn.exec_driver_sql(f'CREATE DATABASE {name}') + engine = create_async_engine(sa.engine.make_url(url).set(database=name)) + try: + yield engine + finally: + await engine.dispose() + async with admin.connect() as conn: + await conn.exec_driver_sql(f'DROP DATABASE {name}') + await admin.dispose() + + +@pytest.mark.asyncio +async def test_release_41011_upgrade(convergence_engine, monkeypatch): + from langbot.pkg.utils import constants + + monkeypatch.setattr(constants, 'instance_id', 'migration-convergence') + engine = convergence_engine + fixture = json.loads((FIXTURES / 'release_4_10_11_schema.json').read_text()) + async with engine.begin() as conn: + for statement in fixture['dialects'][engine.dialect.name]: + await conn.exec_driver_sql(statement) + # Apply the historical migrations too: pgvector is migration-owned, + # not represented in ORM metadata. + await run_alembic_upgrade(engine, fixture['revision']) + await _seed_common(engine) + async with engine.begin() as conn: + await conn.execute(sa.text("DELETE FROM metadata WHERE key='oss_workspace_uuid'")) + await conn.execute( + sa.text( + "INSERT INTO metadata (key,value) VALUES ('oss_workspace_uuid', '41100000-0000-4000-8000-000000000001')" + ) + ) + from types import SimpleNamespace + from unittest.mock import MagicMock + from langbot.pkg.persistence.mgr import PersistenceManager + + manager = PersistenceManager(SimpleNamespace(logger=MagicMock(), instance_uuid='migration-convergence')) + manager.db = SimpleNamespace(engine=engine, get_engine=lambda: engine) + await manager._initialize_managed_schema() + async with engine.connect() as conn: + assert await conn.scalar(sa.text('SELECT name FROM bots')) == 'Fixture bot' + assert await conn.scalar(sa.text('SELECT name FROM legacy_pipelines')) == 'Fixture pipeline' + bot = await conn.run_sync(lambda sync: sa.Table('bots', sa.MetaData(), autoload_with=sync)) + bindings = await conn.scalar(sa.select(bot.c.event_bindings)) + assert any(binding['target_uuid'] == 'pipeline-1' for binding in bindings) + assert await conn.scalar(sa.select(bot.c.plugin_processors)) == [] + kb = await conn.run_sync(lambda sync: sa.Table('knowledge_bases', sa.MetaData(), autoload_with=sync)) + assert all(await conn.scalars(sa.select(kb.c.initialized))) + if engine.dialect.name == 'sqlite': + assert (await conn.exec_driver_sql('PRAGMA foreign_key_check')).all() == [] + async with engine.connect() as conn: + + def differences(sync): + context = MigrationContext.configure(sync, opts={'compare_type': True}) + return compare_metadata(context, Base.metadata) + + diffs = await conn.run_sync(differences) + + def substantive(sync, diff): + if isinstance(diff, list): + return True + if diff[0] not in ('add_table', 'add_column', 'add_index', 'add_constraint'): + return False + if diff[0] in ('add_index', 'add_constraint'): + obj = diff[1] + inspector = sa.inspect(sync) + columns = [c.name for c in obj.columns] + existing = inspector.get_indexes(obj.table.name) + inspector.get_unique_constraints(obj.table.name) + if any( + item['column_names'] == columns and (diff[0] != 'add_constraint' or item.get('unique', True)) + for item in existing + ): + return False + if ( + diff[0] == 'add_constraint' + and inspector.get_pk_constraint(obj.table.name)['constrained_columns'] == columns + ): + return False + return True + + actionable = await conn.run_sync(lambda sync: [d for d in diffs if substantive(sync, d)]) + assert not actionable, repr(actionable) + await manager._initialize_managed_schema() + async with engine.connect() as conn: + assert await conn.scalar(sa.text('SELECT name FROM bots')) == 'Fixture bot' + assert await conn.scalar(sa.text('SELECT name FROM legacy_pipelines')) == 'Fixture pipeline' + bot = await conn.run_sync(lambda sync: sa.Table('bots', sa.MetaData(), autoload_with=sync)) + bindings = await conn.scalar(sa.select(bot.c.event_bindings)) + assert any(binding['target_uuid'] == 'pipeline-1' for binding in bindings) + assert await conn.scalar(sa.select(bot.c.plugin_processors)) == [] + kb = await conn.run_sync(lambda sync: sa.Table('knowledge_bases', sa.MetaData(), autoload_with=sync)) + assert all(await conn.scalars(sa.select(kb.c.initialized))) + if engine.dialect.name == 'sqlite': + assert (await conn.exec_driver_sql('PRAGMA foreign_key_check')).all() == []