chore: commit pending gateway changes

This commit is contained in:
2026-05-10 22:34:15 +08:00
parent 53f8edfb67
commit d59756a27c
71 changed files with 15106 additions and 656 deletions
+3
View File
@@ -7,6 +7,8 @@ CREATE TABLE IF NOT EXISTS model_catalog_providers (
display_name text NOT NULL,
provider_type text NOT NULL DEFAULT 'openai',
icon_path text,
default_base_url text,
default_auth_type text NOT NULL DEFAULT 'APIKey',
source text NOT NULL DEFAULT 'gateway',
capability_schema jsonb NOT NULL DEFAULT '{}'::jsonb,
default_rate_limit_policy jsonb NOT NULL DEFAULT '{}'::jsonb,
@@ -272,6 +274,7 @@ CREATE TABLE IF NOT EXISTS gateway_api_keys (
tenant_key text,
user_id text,
key_prefix text NOT NULL,
key_secret text,
key_hash text NOT NULL UNIQUE,
name text NOT NULL,
scopes jsonb NOT NULL DEFAULT '[]'::jsonb,
@@ -252,6 +252,7 @@ CREATE TABLE IF NOT EXISTS gateway_api_keys (
tenant_key text,
user_id text,
key_prefix text NOT NULL,
key_secret text,
key_hash text NOT NULL UNIQUE,
name text NOT NULL,
scopes jsonb NOT NULL DEFAULT '[]'::jsonb,
@@ -0,0 +1,50 @@
ALTER TABLE model_catalog_providers
ADD COLUMN IF NOT EXISTS default_base_url text,
ADD COLUMN IF NOT EXISTS default_auth_type text NOT NULL DEFAULT 'APIKey';
WITH source_defaults(provider_key, default_base_url, default_auth_type) AS (
VALUES
('easyai', 'https://51easyai.com/api/v1', 'APIKey'),
('runninghub', 'https://www.runninghub.ai', 'APIKey'),
('LiblibAI', 'https://openapi.liblibai.cloud', 'AccessKey-SecretKey'),
('keling', 'https://api-beijing.klingai.com/v1', 'AccessKey-SecretKey'),
('gemini', 'https://generativelanguage.googleapis.com/v1beta', 'APIKey'),
('openai', 'https://api.openai.com/v1', 'APIKey'),
('aliyun-bailian-openai', 'https://dashscope.aliyuncs.com/compatible-mode/v1', 'APIKey'),
('gemini-openai', 'https://generativelanguage.googleapis.com/v1beta/openai', 'APIKey'),
('volces-openai', 'https://ark.cn-beijing.volces.com/api/v3', 'APIKey'),
('zhipu-openai', 'https://open.bigmodel.cn/api/paas/v4', 'APIKey'),
('minimax-openai', 'https://api.minimaxi.com/v1', 'APIKey'),
('openrouter-openai', 'https://openrouter.ai/api/v1', 'APIKey'),
('aliyun-bailian', 'https://dashscope.aliyuncs.com/api/v1', 'APIKey'),
('ollama', 'http://<your-local-ip>:11434/v1', 'APIKey'),
('blackforest', 'https://api.bfl.ai/v1', 'APIKey'),
('dify', 'http://localhost/v1', 'APIKey'),
('volces', 'https://ark.cn-beijing.volces.com/api/v3', 'AccessKey-SecretKey'),
('jimeng', '', 'APIKey'),
('silicon-flow-openai', 'https://api.siliconflow.cn/v1', 'APIKey'),
('tripo3d', 'https://api.tripo3d.ai/v2/openapi', 'APIKey'),
('tencent-hunyuan-image', 'https://aiart.tencentcloudapi.com', 'AccessKey-SecretKey'),
('tencent-hunyuan-video', 'https://vclm.tencentcloudapi.com', 'AccessKey-SecretKey'),
('tencent-hunyuan', 'https://ai3d.tencentcloudapi.com', 'AccessKey-SecretKey'),
('suno', 'https://api.cqtai.com/api/cqt', 'APIKey'),
('minimax', 'https://api.minimaxi.com/v1', 'APIKey'),
('midjourney', 'https://api.legnext.ai/api/v1', 'APIKey'),
('tencent-lke', 'https://wss.lke.cloud.tencent.com/v1', 'AccessKey-SecretKey'),
('universal', 'https://example.com/v1/image/edits', 'APIKey'),
('newapi', 'https://api.newapi.com/v1', 'APIKey'),
('vidu', 'https://api.vidu.cn/ent/v2', 'APIKey'),
('n8n', 'http://127.0.0.1:5678', 'APIKey'),
('mock-test', 'http://mock.test', 'APIKey')
)
UPDATE model_catalog_providers p
SET default_base_url = NULLIF(source_defaults.default_base_url, ''),
default_auth_type = source_defaults.default_auth_type,
metadata = p.metadata || jsonb_build_object(
'defaultConnectionSource', 'server-main.integration-platform',
'defaultBaseUrlSynced', NULLIF(source_defaults.default_base_url, ''),
'defaultAuthTypeSynced', source_defaults.default_auth_type
),
updated_at = now()
FROM source_defaults
WHERE p.provider_key = source_defaults.provider_key;
@@ -0,0 +1,28 @@
ALTER TABLE IF EXISTS base_model_catalog
ADD COLUMN IF NOT EXISTS pricing_rule_set_id uuid REFERENCES model_pricing_rule_sets(id) ON DELETE SET NULL;
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1
FROM pg_constraint c
JOIN pg_attribute a ON a.attrelid = c.conrelid AND a.attnum = ANY(c.conkey)
WHERE c.contype = 'f'
AND c.conrelid = 'base_model_catalog'::regclass
AND a.attname = 'pricing_rule_set_id'
) THEN
ALTER TABLE base_model_catalog
ADD CONSTRAINT fk_base_model_catalog_pricing_rule_set
FOREIGN KEY (pricing_rule_set_id) REFERENCES model_pricing_rule_sets(id) ON DELETE SET NULL;
END IF;
END $$;
CREATE INDEX IF NOT EXISTS idx_base_model_catalog_pricing_rule_set
ON base_model_catalog(pricing_rule_set_id);
UPDATE base_model_catalog
SET pricing_rule_set_id = (
SELECT id FROM model_pricing_rule_sets WHERE rule_set_key = 'default-multimodal-v1' LIMIT 1
)
WHERE pricing_rule_set_id IS NULL
AND EXISTS (SELECT 1 FROM model_pricing_rule_sets WHERE rule_set_key = 'default-multimodal-v1');
@@ -0,0 +1,2 @@
ALTER TABLE IF EXISTS integration_platforms
ADD COLUMN IF NOT EXISTS internal_name text;
@@ -0,0 +1,51 @@
CREATE TABLE IF NOT EXISTS model_runtime_policy_sets (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
policy_key text NOT NULL UNIQUE,
name text NOT NULL,
description text,
rate_limit_policy jsonb NOT NULL DEFAULT '{}'::jsonb,
retry_policy jsonb NOT NULL DEFAULT '{}'::jsonb,
auto_disable_policy jsonb NOT NULL DEFAULT '{}'::jsonb,
degrade_policy jsonb NOT NULL DEFAULT '{}'::jsonb,
metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
status text NOT NULL DEFAULT 'active',
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
INSERT INTO model_runtime_policy_sets (
policy_key, name, description, rate_limit_policy, retry_policy, auto_disable_policy, degrade_policy, metadata, status
)
VALUES (
'default-runtime-v1',
'默认运行策略',
'默认包含 TPM/RPM/并发、失败重试、自动禁用和优先级降级关键词。',
'{"rules":[{"metric":"rpm","limit":120,"windowSeconds":60},{"metric":"tpm_total","limit":240000,"windowSeconds":60},{"metric":"concurrent","limit":6,"leaseTtlSeconds":120}]}'::jsonb,
'{"enabled":true,"maxAttempts":2,"allowKeywords":["rate_limit","timeout","server_error","network","429","5xx"],"denyKeywords":["invalid_api_key","insufficient_quota","billing_not_active","permission_denied"]}'::jsonb,
'{"enabled":false,"threshold":3,"windowSeconds":300,"keywords":["invalid_api_key","account_deactivated","permission_denied","billing_not_active"]}'::jsonb,
'{"enabled":true,"cooldownSeconds":300,"keywords":["rate_limit","quota","timeout","temporarily_unavailable","overloaded"]}'::jsonb,
'{"seed":"0012_runtime_policy_sets"}'::jsonb,
'active'
)
ON CONFLICT (policy_key) DO NOTHING;
ALTER TABLE IF EXISTS base_model_catalog
ADD COLUMN IF NOT EXISTS runtime_policy_set_id uuid REFERENCES model_runtime_policy_sets(id) ON DELETE SET NULL,
ADD COLUMN IF NOT EXISTS runtime_policy_override jsonb NOT NULL DEFAULT '{}'::jsonb;
ALTER TABLE IF EXISTS platform_models
ADD COLUMN IF NOT EXISTS runtime_policy_set_id uuid REFERENCES model_runtime_policy_sets(id) ON DELETE SET NULL,
ADD COLUMN IF NOT EXISTS runtime_policy_override jsonb NOT NULL DEFAULT '{}'::jsonb;
CREATE INDEX IF NOT EXISTS idx_base_model_catalog_runtime_policy
ON base_model_catalog(runtime_policy_set_id);
CREATE INDEX IF NOT EXISTS idx_platform_models_runtime_policy
ON platform_models(runtime_policy_set_id);
UPDATE base_model_catalog
SET runtime_policy_set_id = (
SELECT id FROM model_runtime_policy_sets WHERE policy_key = 'default-runtime-v1' LIMIT 1
)
WHERE runtime_policy_set_id IS NULL
AND EXISTS (SELECT 1 FROM model_runtime_policy_sets WHERE policy_key = 'default-runtime-v1');
+25
View File
@@ -0,0 +1,25 @@
CREATE TABLE IF NOT EXISTS gateway_access_rules (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
subject_type text NOT NULL CHECK (subject_type IN ('user_group', 'tenant', 'user', 'api_key')),
subject_id uuid NOT NULL,
resource_type text NOT NULL CHECK (resource_type IN ('platform', 'platform_model', 'base_model')),
resource_id uuid NOT NULL,
effect text NOT NULL CHECK (effect IN ('allow', 'deny')),
priority integer NOT NULL DEFAULT 100,
min_permission_level integer NOT NULL DEFAULT 0,
conditions jsonb NOT NULL DEFAULT '{}'::jsonb,
metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
status text NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'disabled')),
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
UNIQUE (subject_type, subject_id, resource_type, resource_id, effect)
);
CREATE INDEX IF NOT EXISTS idx_gateway_access_rules_subject
ON gateway_access_rules(subject_type, subject_id, status);
CREATE INDEX IF NOT EXISTS idx_gateway_access_rules_resource
ON gateway_access_rules(resource_type, resource_id, status);
CREATE INDEX IF NOT EXISTS idx_gateway_access_rules_effect
ON gateway_access_rules(effect, status, priority);
@@ -0,0 +1,73 @@
ALTER TABLE IF EXISTS base_model_catalog
ADD COLUMN IF NOT EXISTS catalog_type text NOT NULL DEFAULT 'system',
ADD COLUMN IF NOT EXISTS default_snapshot jsonb,
ADD COLUMN IF NOT EXISTS customized_at timestamptz;
UPDATE base_model_catalog
SET catalog_type = CASE
WHEN metadata ->> 'source' = 'server-main.integration-platform'
OR metadata ? 'sourceProviderCode'
OR metadata ? 'rawModel'
THEN 'system'
ELSE 'custom'
END;
UPDATE base_model_catalog
SET default_snapshot = jsonb_build_object(
'providerKey', provider_key,
'canonicalModelKey', canonical_model_key,
'providerModelName', provider_model_name,
'modelType', CASE
WHEN jsonb_typeof(capabilities -> 'originalTypes') = 'array' THEN capabilities -> 'originalTypes'
ELSE jsonb_build_array(model_type)
END,
'modelAlias', display_name,
'capabilities', capabilities,
'baseBillingConfig', base_billing_config,
'defaultRateLimitPolicy', default_rate_limit_policy,
'pricingRuleSetId', COALESCE(pricing_rule_set_id::text, ''),
'runtimePolicySetId', COALESCE(runtime_policy_set_id::text, ''),
'runtimePolicyOverride', runtime_policy_override,
'metadata', metadata,
'pricingVersion', pricing_version,
'status', status
)
WHERE catalog_type = 'system'
AND COALESCE(default_snapshot, '{}'::jsonb) = '{}'::jsonb;
CREATE OR REPLACE FUNCTION fill_system_base_model_default_snapshot()
RETURNS trigger AS $$
BEGIN
IF NEW.catalog_type = 'system' AND NEW.default_snapshot IS NULL THEN
NEW.default_snapshot = jsonb_build_object(
'providerKey', NEW.provider_key,
'canonicalModelKey', NEW.canonical_model_key,
'providerModelName', NEW.provider_model_name,
'modelType', CASE
WHEN jsonb_typeof(NEW.capabilities -> 'originalTypes') = 'array' THEN NEW.capabilities -> 'originalTypes'
ELSE jsonb_build_array(NEW.model_type)
END,
'modelAlias', NEW.display_name,
'capabilities', NEW.capabilities,
'baseBillingConfig', NEW.base_billing_config,
'defaultRateLimitPolicy', NEW.default_rate_limit_policy,
'pricingRuleSetId', COALESCE(NEW.pricing_rule_set_id::text, ''),
'runtimePolicySetId', COALESCE(NEW.runtime_policy_set_id::text, ''),
'runtimePolicyOverride', NEW.runtime_policy_override,
'metadata', NEW.metadata,
'pricingVersion', NEW.pricing_version,
'status', NEW.status
);
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS trg_fill_system_base_model_default_snapshot ON base_model_catalog;
CREATE TRIGGER trg_fill_system_base_model_default_snapshot
BEFORE INSERT ON base_model_catalog
FOR EACH ROW
EXECUTE FUNCTION fill_system_base_model_default_snapshot();
CREATE INDEX IF NOT EXISTS idx_base_model_catalog_type
ON base_model_catalog(catalog_type, status);
@@ -0,0 +1,41 @@
UPDATE base_model_catalog
SET default_snapshot = default_snapshot
|| jsonb_build_object(
'modelType', CASE
WHEN jsonb_typeof(default_snapshot -> 'modelType') = 'array' THEN default_snapshot -> 'modelType'
WHEN COALESCE(default_snapshot ->> 'modelType', '') <> '' THEN jsonb_build_array(default_snapshot ->> 'modelType')
WHEN jsonb_typeof(capabilities -> 'originalTypes') = 'array' THEN capabilities -> 'originalTypes'
ELSE jsonb_build_array(model_type)
END,
'modelAlias', COALESCE(default_snapshot ->> 'modelAlias', default_snapshot ->> 'displayName', display_name)
)
WHERE catalog_type = 'system'
AND COALESCE(default_snapshot, '{}'::jsonb) <> '{}'::jsonb;
CREATE OR REPLACE FUNCTION fill_system_base_model_default_snapshot()
RETURNS trigger AS $$
BEGIN
IF NEW.catalog_type = 'system' AND NEW.default_snapshot IS NULL THEN
NEW.default_snapshot = jsonb_build_object(
'providerKey', NEW.provider_key,
'canonicalModelKey', NEW.canonical_model_key,
'providerModelName', NEW.provider_model_name,
'modelType', CASE
WHEN jsonb_typeof(NEW.capabilities -> 'originalTypes') = 'array' THEN NEW.capabilities -> 'originalTypes'
ELSE jsonb_build_array(NEW.model_type)
END,
'modelAlias', NEW.display_name,
'capabilities', NEW.capabilities,
'baseBillingConfig', NEW.base_billing_config,
'defaultRateLimitPolicy', NEW.default_rate_limit_policy,
'pricingRuleSetId', COALESCE(NEW.pricing_rule_set_id::text, ''),
'runtimePolicySetId', COALESCE(NEW.runtime_policy_set_id::text, ''),
'runtimePolicyOverride', NEW.runtime_policy_override,
'metadata', NEW.metadata,
'pricingVersion', NEW.pricing_version,
'status', NEW.status
);
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
@@ -0,0 +1,2 @@
ALTER TABLE gateway_api_keys
ADD COLUMN IF NOT EXISTS key_secret text;