Persist custom world asset configs in runtime snapshots

This commit is contained in:
2026-04-18 17:00:46 +08:00
parent 7ce61e9879
commit ac801fe05f
29 changed files with 3397 additions and 400 deletions

View File

@@ -3,7 +3,7 @@ import { describe, expect, it } from 'vitest';
import { buildDefaultRolePromptBundle } from './customWorldRolePromptDefaults';
describe('buildDefaultRolePromptBundle', () => {
it('prefers model-generated role descriptions instead of rule-based assembly', () => {
it('uses model-generated role descriptions directly', () => {
const result = buildDefaultRolePromptBundle({
name: '沈砺',
title: '灰炬向导',
@@ -28,7 +28,7 @@ describe('buildDefaultRolePromptBundle', () => {
);
});
it('falls back to compact role descriptions without reintroducing built-in prompt rules', () => {
it('falls back to existing entity descriptions without assembling new rules', () => {
const result = buildDefaultRolePromptBundle({
name: '顾潮音',
title: '港口守望者',
@@ -41,11 +41,11 @@ describe('buildDefaultRolePromptBundle', () => {
tags: ['潮雾港', '守望', '旧案'],
});
expect(result.visualPromptText).toContain('总在潮雾港高处盯着来往船影的守望者。');
expect(result.animationPromptText).toContain('长枪封线后借高差压制。');
expect(result.scenePromptText).toContain('他把许多没说出口的旧案痕迹留在港口高处。');
expect(result.visualPromptText).not.toContain('2D 横版 RPG');
expect(result.visualPromptText).not.toContain('纯绿色绿幕');
expect(result.visualPromptText).toBe('总在潮雾港高处盯着来往船影的守望者。');
expect(result.animationPromptText).toBe('长枪封线后借高差压制。');
expect(result.scenePromptText).toBe('他把许多没说出口的旧案痕迹留在港口高处。');
expect(result.visualPromptText).not.toContain('经典横版像素动作角色');
expect(result.visualPromptText).not.toContain('深色粗轮廓配合清晰大色块');
expect(result.visualPromptText).not.toContain('提示词');
});
});

View File

@@ -23,52 +23,35 @@ function cleanSeedText(value: string | undefined, maxLength: number) {
return (value ?? '').replace(/\s+/gu, ' ').trim().slice(0, maxLength);
}
function compactDescription(parts: Array<string | undefined>, maxLength: number) {
return parts
.map((item) => cleanSeedText(item, maxLength))
.filter(Boolean)
.join(' ')
.slice(0, maxLength);
function pickFirstDescription(
values: Array<string | undefined>,
maxLength: number,
) {
for (const value of values) {
const normalized = cleanSeedText(value, maxLength);
if (normalized) {
return normalized;
}
}
return '';
}
export function buildDefaultRolePromptBundle(
role: PromptDefaultRole,
): CustomWorldRolePromptBundle {
const roleLabel = [cleanSeedText(role.name, 40), cleanSeedText(role.title, 40)]
.filter(Boolean)
.join('');
const fallbackVisualDescription = compactDescription(
[
roleLabel || cleanSeedText(role.role, 40),
role.description,
role.personality,
role.tags && role.tags.length > 0 ? role.tags.slice(0, 8).join('、') : '',
],
220,
);
const fallbackActionDescription = compactDescription(
[
role.actionDescription,
role.combatStyle,
role.motivation,
role.personality,
],
180,
);
const generatedSceneDescription = cleanSeedText(role.sceneVisualDescription, 220);
const fallbackSceneDescription = compactDescription(
[
role.backstory,
role.description,
role.motivation,
],
220,
);
return {
visualPromptText:
cleanSeedText(role.visualDescription, 220) || fallbackVisualDescription,
animationPromptText: fallbackActionDescription,
scenePromptText: generatedSceneDescription || fallbackSceneDescription,
visualPromptText: pickFirstDescription(
[role.visualDescription, role.description],
220,
),
animationPromptText: pickFirstDescription(
[role.actionDescription, role.combatStyle],
180,
),
scenePromptText: pickFirstDescription(
[role.sceneVisualDescription, role.backstory],
220,
),
};
}