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
112 lines
6.6 KiB
SQL
112 lines
6.6 KiB
SQL
-- 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$;
|