Files
xinmi/migrations/versioned/000206_legacy_agent_persona.up.sql
T

112 lines
6.6 KiB
SQL
Raw Normal View History

-- Existing effective style is imported, not re-distilled or falsely approved.
CREATE TABLE IF NOT EXISTS yawan_legacy_agent_persona_mappings (
tenant_id BIGINT NOT NULL,
agent_id VARCHAR(36) NOT NULL,
source_system TEXT NOT NULL,
source_organization_id BIGINT NOT NULL,
source_id BIGINT NOT NULL,
owner_id VARCHAR(36) NOT NULL,
digital_human_id VARCHAR(36) NOT NULL,
version_id VARCHAR(36) NOT NULL,
binding_id VARCHAR(36) NOT NULL,
source_persona JSONB NOT NULL,
source_snapshot_sha256 VARCHAR(64) NOT NULL,
migrated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (tenant_id, agent_id),
UNIQUE (source_system, source_organization_id, source_id, tenant_id)
);
DO $legacy_persona$
DECLARE
item RECORD;
human_id TEXT;
version_id TEXT;
binding_id TEXT;
seed TEXT;
prompt TEXT;
persona_lines TEXT;
globally_visible BOOLEAN;
BEGIN
IF to_regclass('yawan_legacy_asset_mappings') IS NULL THEN
RETURN;
END IF;
FOR item IN
SELECT m.*, a.created_by, a.name, a.avatar, a.config, a.visibility
FROM yawan_legacy_asset_mappings m
JOIN custom_agents a ON a.tenant_id = m.target_tenant_id AND a.id = m.target_id
WHERE m.source_system = 'yawan-workbench' AND m.source_organization_id = 1
AND m.source_kind = 'agent' AND m.source_snapshot->>'status' = 'active'
AND m.source_snapshot->'persona_json' IS NOT NULL
AND m.source_snapshot->'persona_json' <> '{}'::jsonb
AND COALESCE(m.source_snapshot->>'digital_human_id', '') IN ('', '0')
AND a.deleted_at IS NULL AND COALESCE(a.created_by, '') <> ''
AND NOT EXISTS (SELECT 1 FROM yawan_legacy_agent_persona_mappings p
WHERE p.tenant_id = a.tenant_id AND p.agent_id = a.id)
AND NOT EXISTS (SELECT 1 FROM digital_human_bindings b
WHERE b.tenant_id = a.tenant_id AND b.agent_id = a.id)
FOR UPDATE OF a
LOOP
IF jsonb_typeof(item.source_snapshot->'persona_json') <> 'object' THEN
RAISE EXCEPTION 'Legacy Agent persona must be an object';
END IF;
IF EXISTS (SELECT 1 FROM jsonb_each(item.source_snapshot->'persona_json') p
WHERE jsonb_typeof(p.value) <> 'string' OR length(p.value #>> '{}') > 6000
OR p.key NOT IN ('persona_name', 'identity', 'tone', 'pace', 'vocab', 'taboo',
'opening_habit', 'emotion_style', 'interaction', 'expertise_border', 'sample_excerpt',
'writing_style', 'narrative_style', 'thinking_style', 'audience_profile', 'hook_patterns',
'pain_point_hooks', 'itch_point_hooks', 'sales_logic', 'cta_transition',
'expression_prompt', 'expression_rules'))
OR (SELECT COALESCE(sum(length(value)), 0) FROM jsonb_each_text(item.source_snapshot->'persona_json')) > 30000 THEN
RAISE EXCEPTION 'Legacy Agent persona requires explicit field review';
END IF;
IF NOT EXISTS (SELECT 1 FROM jsonb_each_text(item.source_snapshot->'persona_json') p WHERE btrim(p.value) <> '') THEN
CONTINUE;
END IF;
seed := item.source_system || ':' || item.source_organization_id || ':agent-persona:' || item.target_tenant_id || ':' || item.source_id;
human_id := md5(seed || ':human')::uuid::text;
version_id := md5(seed || ':version')::uuid::text;
binding_id := md5(seed || ':binding')::uuid::text;
-- A preexisting deterministic target is a conflict, never permission to overwrite it.
IF EXISTS (SELECT 1 FROM digital_humans WHERE id = human_id)
OR EXISTS (SELECT 1 FROM digital_human_versions WHERE id = version_id)
OR EXISTS (SELECT 1 FROM digital_human_bindings WHERE id = binding_id) THEN
RAISE EXCEPTION 'Legacy Agent persona target already exists without migration provenance';
END IF;
SELECT string_agg(p.key || ':' || btrim(p.value) || E'\n', '' ORDER BY p.key COLLATE "C")
INTO persona_lines FROM jsonb_each_text(item.source_snapshot->'persona_json') p
WHERE btrim(p.value) <> '';
prompt := COALESCE(item.config->>'system_prompt', '') || E'\n\n<!-- weknora:digital-human:' || human_id || E':start -->\n'
|| '## 旧配置迁入数字人(未重新蒸馏):' || item.name || E'(v1)\n'
|| E'以下档案仅约束表达方式,不能替代任务目标、事实来源、工具权限或上文衔接约束。不得把档案样本当作新的事实依据。\n'
|| persona_lines || '<!-- weknora:digital-human:' || human_id || ':end -->';
INSERT INTO digital_humans (id, tenant_id, owner_id, name, description, avatar, model_id,
status, latest_version, active_version, primary_agent_id)
VALUES (human_id, item.target_tenant_id, item.created_by, item.name,
'从原 Agent 的有效风格配置迁入,未重新蒸馏或审核。', COALESCE(item.avatar, ''),
COALESCE(item.config->>'model_id', ''), 'active', 1, 1, item.target_id);
INSERT INTO digital_human_versions (id, tenant_id, owner_id, digital_human_id, number,
status, persona, sources, advice, review_note, reviewed_at)
VALUES (version_id, item.target_tenant_id, item.created_by, human_id, 1, 'imported',
item.source_snapshot->'persona_json', '[]', '', '', NULL);
INSERT INTO digital_human_bindings (id, tenant_id, owner_id, digital_human_id, agent_id, base_prompt, applied_version)
VALUES (binding_id, item.target_tenant_id, item.created_by, human_id, item.target_id,
COALESCE(item.config->>'system_prompt', ''), 1);
UPDATE custom_agents SET config = jsonb_set(config::jsonb, '{system_prompt}', to_jsonb(prompt))
WHERE tenant_id = item.target_tenant_id AND id = item.target_id;
SELECT COALESCE((SELECT global FROM workbench_access_publications
WHERE tenant_id = item.target_tenant_id AND kind = 'agents' AND resource_id = item.target_id),
item.visibility = 'global') INTO globally_visible;
INSERT INTO workbench_access_publications (tenant_id, kind, resource_id, global)
VALUES (item.target_tenant_id, 'digital-humans', human_id, globally_visible);
INSERT INTO workbench_access_grants (tenant_id, kind, resource_id, user_id)
SELECT tenant_id, 'digital-humans', human_id, user_id FROM workbench_access_grants
WHERE tenant_id = item.target_tenant_id AND kind = 'agents' AND resource_id = item.target_id;
INSERT INTO yawan_legacy_agent_persona_mappings (tenant_id, agent_id, source_system,
source_organization_id, source_id, owner_id, digital_human_id, version_id, binding_id,
source_persona, source_snapshot_sha256)
VALUES (item.target_tenant_id, item.target_id, item.source_system, item.source_organization_id,
item.source_id, item.created_by, human_id, version_id, binding_id,
item.source_snapshot->'persona_json', item.source_snapshot_sha256);
END LOOP;
END $legacy_persona$;