Files
xinmi/migrations/versioned/000206_legacy_agent_persona.up.sql
T
yawan f7fc992f57
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
WeKnora deployment source with the reviewed wiki identity, summary and recovery fixes
2026-09-22 16:19:06 +08:00

112 lines
6.6 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- 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$;