import type { EightAnchorContent } from '../../packages/shared/src/contracts/customWorldAgent'; import { normalizeCustomWorldCreatorIntent } from './customWorldCreatorIntent'; import type { CustomWorldProfile } from '../types'; export type CustomWorldFoundationEntryId = | 'world-promise' | 'player-fantasy' | 'theme-boundary' | 'player-entry-point' | 'core-conflict' | 'key-relationships' | 'hidden-lines' | 'iconic-elements'; export type CustomWorldFoundationEntry = { id: CustomWorldFoundationEntryId; label: string; value: string; }; export function compactFoundationTextList( values: Array, ) { return values.map((value) => value?.trim()).filter(Boolean) as string[]; } export function parseFoundationTagText(value: string) { return value .split(/[;;]/u) .map((item) => item.trim()) .filter(Boolean); } function toText(value: unknown) { return typeof value === 'string' ? value.trim() : ''; } function toRecord(value: unknown) { return value && typeof value === 'object' && !Array.isArray(value) ? (value as Record) : null; } function compactAnchorValue(value: unknown): string | null { const text = toText(value); if (text) { return text; } if (Array.isArray(value)) { const compacted = compactFoundationTextList( value.map((item) => compactAnchorValue(item)), ).join(';'); return compacted || null; } const record = toRecord(value); if (record) { const compacted = compactFoundationTextList( Object.values(record).map((item) => compactAnchorValue(item)), ).join(';'); return compacted || null; } return null; } function buildRelationshipSeedText(value: unknown) { const record = toRecord(value); if (!record) { return ''; } return compactFoundationTextList([ toText(record.name), toText(record.role), toText(record.relationToPlayer) ? `与玩家:${toText(record.relationToPlayer)}` : '', toText(record.hiddenHook) ? `代价/暗线:${toText(record.hiddenHook)}` : '', ]).join(';'); } function buildAnchorContentFromProfileFallback( profile: CustomWorldProfile, ): EightAnchorContent { const creatorIntent = normalizeCustomWorldCreatorIntent(profile.creatorIntent); const relationshipSeed = creatorIntent?.keyCharacters[0] ?? null; return { worldPromise: compactFoundationTextList([ creatorIntent?.worldHook || profile.anchorPack?.worldSummary || profile.summary, profile.subtitle || profile.settingText, creatorIntent?.toneDirectives.join('、') || profile.tone, ]).join(';') || null, playerFantasy: compactFoundationTextList([ creatorIntent?.playerPremise || profile.playerGoal, profile.playerGoal, relationshipSeed?.hiddenHook || creatorIntent?.coreConflicts[0] || profile.coreConflicts[0] || '', ]).join(';') || null, themeBoundary: compactFoundationTextList([ creatorIntent?.themeKeywords.join('、') || '', creatorIntent?.toneDirectives.join('、') || '', profile.tone, profile.subtitle, creatorIntent?.forbiddenDirectives.length ? `避免:${creatorIntent.forbiddenDirectives.join('、')}` : '', ]).join(';') || null, playerEntryPoint: compactFoundationTextList([ creatorIntent?.playerPremise || '', creatorIntent?.openingSituation || profile.coreConflicts[0] || '', profile.playerGoal, ]).join(';') || null, coreConflict: compactFoundationTextList([ (creatorIntent?.coreConflicts.length ? creatorIntent.coreConflicts : profile.coreConflicts ).join('、'), relationshipSeed?.hiddenHook || profile.summary || profile.settingText, creatorIntent?.openingSituation || profile.coreConflicts[0] || profile.playerGoal, ]).join(';') || null, keyRelationships: relationshipSeed ? compactFoundationTextList([ relationshipSeed.name, relationshipSeed.role, relationshipSeed.relationToPlayer, relationshipSeed.hiddenHook ? `代价/秘密:${relationshipSeed.hiddenHook}` : '', ]).join(';') : null, hiddenLines: compactFoundationTextList([ relationshipSeed?.hiddenHook || '', profile.summary, profile.subtitle, profile.majorFactions[0] || '', creatorIntent?.openingSituation || profile.coreConflicts[0] || profile.playerGoal, ]).join(';') || null, iconicElements: compactFoundationTextList([ (creatorIntent?.iconicElements.length ? creatorIntent.iconicElements : [ profile.anchorPack?.motifDirectives.join('、') || '', profile.landmarks[0]?.name || '', ] ).join('、'), profile.camp?.name || '', profile.majorFactions[0] || '', profile.playerGoal, profile.coreConflicts[0] || '', ]).join(';') || null, } satisfies EightAnchorContent; } export function getCustomWorldFoundationAnchorContent( profile: CustomWorldProfile, ) { const anchorContentRecord = profile.anchorContent; if (!anchorContentRecord) { return buildAnchorContentFromProfileFallback(profile); } return { worldPromise: compactAnchorValue(anchorContentRecord.worldPromise), playerFantasy: compactAnchorValue(anchorContentRecord.playerFantasy), themeBoundary: compactAnchorValue(anchorContentRecord.themeBoundary), playerEntryPoint: compactAnchorValue(anchorContentRecord.playerEntryPoint), coreConflict: compactAnchorValue(anchorContentRecord.coreConflict), keyRelationships: compactAnchorValue(anchorContentRecord.keyRelationships), hiddenLines: compactAnchorValue(anchorContentRecord.hiddenLines), iconicElements: compactAnchorValue(anchorContentRecord.iconicElements), } satisfies EightAnchorContent; } export function buildCustomWorldFoundationEntries( profile: CustomWorldProfile, ): CustomWorldFoundationEntry[] { const creatorIntent = normalizeCustomWorldCreatorIntent(profile.creatorIntent); const anchorContent = getCustomWorldFoundationAnchorContent(profile); const fallbackRelationshipText = buildRelationshipSeedText(creatorIntent?.keyCharacters[0]) || profile.playableNpcs[0]?.relationshipHooks.join(';') || profile.storyNpcs[0]?.relationshipHooks.join(';') || ''; return [ { id: 'world-promise', label: '世界承诺', value: anchorContent.worldPromise || '', }, { id: 'player-fantasy', label: '玩家幻想', value: anchorContent.playerFantasy || '', }, { id: 'theme-boundary', label: '主题边界', value: anchorContent.themeBoundary || '', }, { id: 'player-entry-point', label: '玩家切入口', value: anchorContent.playerEntryPoint || '', }, { id: 'core-conflict', label: '核心冲突', value: anchorContent.coreConflict || '', }, { id: 'key-relationships', label: '关键关系', value: anchorContent.keyRelationships || fallbackRelationshipText, }, { id: 'hidden-lines', label: '暗线与揭示', value: anchorContent.hiddenLines || '', }, { id: 'iconic-elements', label: '标志元素', value: anchorContent.iconicElements || '', }, ]; }