CREATE TABLE IF NOT EXISTS gateway_response_chains ( public_response_id text PRIMARY KEY, parent_response_id text REFERENCES gateway_response_chains(public_response_id) ON DELETE RESTRICT, gateway_task_id uuid NOT NULL REFERENCES gateway_tasks(id) ON DELETE CASCADE, gateway_user_id uuid REFERENCES gateway_users(id) ON DELETE SET NULL, user_id text NOT NULL, user_source text NOT NULL DEFAULT 'gateway', gateway_tenant_id uuid REFERENCES gateway_tenants(id) ON DELETE SET NULL, tenant_id text, tenant_key text, api_key_id text, platform_id uuid NOT NULL REFERENCES integration_platforms(id) ON DELETE RESTRICT, platform_model_id uuid NOT NULL REFERENCES platform_models(id) ON DELETE RESTRICT, client_id text NOT NULL, upstream_protocol text NOT NULL, upstream_endpoint text NOT NULL, upstream_response_id text, request_snapshot jsonb NOT NULL DEFAULT '{}'::jsonb, response_snapshot jsonb NOT NULL DEFAULT '{}'::jsonb, internal_snapshot jsonb NOT NULL DEFAULT '{}'::jsonb, created_at timestamptz NOT NULL DEFAULT now(), expires_at timestamptz NOT NULL, CONSTRAINT gateway_response_chains_public_id_check CHECK (public_response_id ~ '^resp_[A-Za-z0-9_-]+$'), CONSTRAINT gateway_response_chains_protocol_check CHECK (upstream_protocol IN ('openai_chat_completions', 'openai_responses')) ); ALTER TABLE gateway_response_chains DROP CONSTRAINT IF EXISTS gateway_response_chains_public_id_check; ALTER TABLE gateway_response_chains ADD CONSTRAINT gateway_response_chains_public_id_check CHECK (public_response_id ~ '^resp_[A-Za-z0-9_-]+$'); CREATE INDEX IF NOT EXISTS idx_gateway_response_chains_owner ON gateway_response_chains(gateway_user_id, user_id, gateway_tenant_id, tenant_id, tenant_key); CREATE INDEX IF NOT EXISTS idx_gateway_response_chains_expiry ON gateway_response_chains(expires_at); CREATE INDEX IF NOT EXISTS idx_gateway_response_chains_platform_model ON gateway_response_chains(platform_model_id, created_at DESC); CREATE INDEX IF NOT EXISTS idx_gateway_response_chains_upstream_response ON gateway_response_chains(upstream_response_id) WHERE upstream_response_id IS NOT NULL; -- Keep capability data provider-specific. A missing supportedApiProtocols field -- intentionally remains legacy-compatible and means Chat Completions only. UPDATE base_model_catalog SET capabilities = jsonb_set( capabilities, '{text_generate,supportedApiProtocols}', '["openai_chat_completions","openai_responses"]'::jsonb, true ), default_snapshot = CASE WHEN COALESCE(default_snapshot, '{}'::jsonb) = '{}'::jsonb THEN default_snapshot ELSE jsonb_set( default_snapshot, '{capabilities,text_generate,supportedApiProtocols}', '["openai_chat_completions","openai_responses"]'::jsonb, true ) END, updated_at = now() WHERE provider_key = 'volces-openai' AND provider_model_name = 'doubao-seed-2-0-pro-260215'; WITH provider AS ( SELECT id FROM model_catalog_providers WHERE provider_key = 'aliyun-bailian-openai' OR provider_code = 'aliyun-bailian-openai' LIMIT 1 ), template AS ( SELECT * FROM base_model_catalog WHERE provider_key = 'aliyun-bailian-openai' AND provider_model_name IN ('qwen3.7-max', 'qwen3.7-plus') ORDER BY CASE WHEN provider_model_name = 'qwen3.7-plus' THEN 0 ELSE 1 END LIMIT 1 ), payload AS ( SELECT provider.id AS provider_id, 'aliyun-bailian-openai'::text AS provider_key, 'aliyun-bailian-openai:qwen3.7-plus'::text AS canonical_model_key, 'qwen3.7-plus'::text AS provider_model_name, '["text_generate","tools_call"]'::jsonb AS model_type, 'Qwen3.7-Plus'::text AS display_name, jsonb_set( COALESCE(template.capabilities, '{"originalTypes":["text_generate","tools_call"],"text_generate":{"supportTool":true},"tools_call":{"supportTool":true}}'::jsonb), '{text_generate,supportedApiProtocols}', '["openai_chat_completions","openai_responses"]'::jsonb, true ) AS capabilities, COALESCE(template.base_billing_config, '{}'::jsonb) AS base_billing_config, COALESCE(template.default_rate_limit_policy, '{}'::jsonb) AS default_rate_limit_policy, COALESCE(template.metadata, '{}'::jsonb) || jsonb_build_object( 'alias', 'Qwen3.7-Plus', 'selectable', true, 'sourceProviderCode', 'aliyun-bailian-openai' ) AS metadata, COALESCE(template.pricing_version, 1) AS pricing_version FROM provider LEFT JOIN template ON true ), snapshot AS ( SELECT payload.*, jsonb_build_object( 'providerKey', provider_key, 'canonicalModelKey', canonical_model_key, 'providerModelName', provider_model_name, 'modelType', model_type, 'modelAlias', display_name, 'capabilities', capabilities, 'baseBillingConfig', base_billing_config, 'defaultRateLimitPolicy', default_rate_limit_policy, 'metadata', metadata, 'pricingVersion', pricing_version, 'status', 'active' ) AS default_snapshot FROM payload ) INSERT INTO base_model_catalog ( provider_id, provider_key, canonical_model_key, provider_model_name, model_type, display_name, capabilities, base_billing_config, default_rate_limit_policy, metadata, catalog_type, default_snapshot, pricing_version, status ) SELECT provider_id, provider_key, canonical_model_key, provider_model_name, model_type, display_name, capabilities, base_billing_config, default_rate_limit_policy, metadata, 'system', default_snapshot, pricing_version, 'active' FROM snapshot ON CONFLICT (canonical_model_key) DO UPDATE SET provider_id = EXCLUDED.provider_id, provider_key = EXCLUDED.provider_key, provider_model_name = EXCLUDED.provider_model_name, model_type = EXCLUDED.model_type, display_name = EXCLUDED.display_name, capabilities = jsonb_set( base_model_catalog.capabilities, '{text_generate,supportedApiProtocols}', '["openai_chat_completions","openai_responses"]'::jsonb, true ), default_snapshot = EXCLUDED.default_snapshot, status = 'active', updated_at = now(); INSERT INTO model_catalog_providers ( provider_key, provider_code, provider_type, display_name, icon_path, source, capability_schema, default_rate_limit_policy, metadata, status ) VALUES ( 'deepseek-openai', 'deepseek-openai', 'openai', 'DeepSeek', 'https://static.51easyai.com/deepseek-color%20%281%29.webp', 'gateway.responses-protocol-migration', '{}'::jsonb, '{}'::jsonb, '{"seed":"responses-protocols","sourceSpecType":"openai"}'::jsonb, 'active' ) ON CONFLICT (provider_key) DO UPDATE SET provider_code = EXCLUDED.provider_code, provider_type = EXCLUDED.provider_type, display_name = EXCLUDED.display_name, icon_path = EXCLUDED.icon_path, metadata = model_catalog_providers.metadata || EXCLUDED.metadata, status = 'active', updated_at = now(); WITH provider AS ( SELECT id FROM model_catalog_providers WHERE provider_key = 'deepseek-openai' OR provider_code = 'deepseek-openai' LIMIT 1 ), template AS ( SELECT * FROM base_model_catalog WHERE provider_model_name = 'deepseek-v4-pro' ORDER BY CASE WHEN provider_key = 'deepseek-openai' THEN 0 ELSE 1 END LIMIT 1 ), payload AS ( SELECT provider.id AS provider_id, 'deepseek-openai'::text AS provider_key, 'deepseek-openai:deepseek-v4-pro'::text AS canonical_model_key, 'deepseek-v4-pro'::text AS provider_model_name, '["text_generate","tools_call"]'::jsonb AS model_type, 'DeepSeek-V4-Pro'::text AS display_name, jsonb_set( COALESCE(template.capabilities, '{"originalTypes":["text_generate","tools_call"],"text_generate":{"supportTool":true},"tools_call":{"supportTool":true}}'::jsonb), '{text_generate,supportedApiProtocols}', '["openai_chat_completions","anthropic_messages"]'::jsonb, true ) AS capabilities, COALESCE(template.base_billing_config, '{}'::jsonb) AS base_billing_config, COALESCE(template.default_rate_limit_policy, '{}'::jsonb) AS default_rate_limit_policy, COALESCE(template.metadata, '{}'::jsonb) || jsonb_build_object( 'alias', 'DeepSeek-V4-Pro', 'selectable', true, 'sourceProviderCode', 'deepseek-openai', 'sourceProviderName', 'DeepSeek 官网' ) AS metadata, COALESCE(template.pricing_version, 1) AS pricing_version FROM provider LEFT JOIN template ON true ), snapshot AS ( SELECT payload.*, jsonb_build_object( 'providerKey', provider_key, 'canonicalModelKey', canonical_model_key, 'providerModelName', provider_model_name, 'modelType', model_type, 'modelAlias', display_name, 'capabilities', capabilities, 'baseBillingConfig', base_billing_config, 'defaultRateLimitPolicy', default_rate_limit_policy, 'metadata', metadata, 'pricingVersion', pricing_version, 'status', 'active' ) AS default_snapshot FROM payload ) INSERT INTO base_model_catalog ( provider_id, provider_key, canonical_model_key, provider_model_name, model_type, display_name, capabilities, base_billing_config, default_rate_limit_policy, metadata, catalog_type, default_snapshot, pricing_version, status ) SELECT provider_id, provider_key, canonical_model_key, provider_model_name, model_type, display_name, capabilities, base_billing_config, default_rate_limit_policy, metadata, 'system', default_snapshot, pricing_version, 'active' FROM snapshot ON CONFLICT (canonical_model_key) DO UPDATE SET provider_id = EXCLUDED.provider_id, provider_key = EXCLUDED.provider_key, provider_model_name = EXCLUDED.provider_model_name, model_type = EXCLUDED.model_type, display_name = EXCLUDED.display_name, capabilities = jsonb_set( base_model_catalog.capabilities, '{text_generate,supportedApiProtocols}', '["openai_chat_completions","anthropic_messages"]'::jsonb, true ), default_snapshot = EXCLUDED.default_snapshot, status = 'active', updated_at = now(); UPDATE platform_models model SET base_model_id = base.id, model_name = base.provider_model_name, provider_model_name = CASE WHEN platform.provider = 'volces-openai' THEN 'doubao-seed-2-0-pro-260215' WHEN platform.provider = 'aliyun-bailian-openai' THEN 'qwen3.7-plus' WHEN platform.provider = 'deepseek-openai' THEN 'deepseek-v4-pro' ELSE model.provider_model_name END, model_alias = CASE WHEN platform.provider = 'volces-openai' THEN 'Doubao Seed 2.0 Pro' WHEN platform.provider = 'aliyun-bailian-openai' THEN 'Qwen3.7-Plus' WHEN platform.provider = 'deepseek-openai' THEN 'DeepSeek-V4-Pro' END, display_name = CASE WHEN platform.provider = 'volces-openai' THEN 'Doubao Seed 2.0 Pro' WHEN platform.provider = 'aliyun-bailian-openai' THEN 'Qwen3.7-Plus' WHEN platform.provider = 'deepseek-openai' THEN 'DeepSeek-V4-Pro' END, model_type = '["text_generate","tools_call"]'::jsonb, enabled = true, updated_at = now() FROM integration_platforms platform, base_model_catalog base WHERE model.platform_id = platform.id AND ( (platform.provider = 'volces-openai' AND base.canonical_model_key = 'volces-openai:doubao-seed-2-0-pro-260215' AND (model.model_name = 'doubao-seed-2-0-pro-260215' OR model.provider_model_name = 'doubao-seed-2-0-pro-260215' OR model.model_alias = 'Doubao Seed 2.0 Pro')) OR (platform.provider = 'aliyun-bailian-openai' AND base.canonical_model_key = 'aliyun-bailian-openai:qwen3.7-plus' AND (model.model_name = 'qwen3.7-plus' OR model.provider_model_name = 'qwen3.7-plus' OR model.display_name = 'Qwen3.7-Plus')) OR (platform.provider = 'deepseek-openai' AND base.canonical_model_key = 'deepseek-openai:deepseek-v4-pro' AND (model.model_name = 'deepseek-v4-pro' OR model.provider_model_name = 'deepseek-v4-pro' OR model.display_name = 'DeepSeek-V4-Pro')) );