import type { CreatorIntentReadiness, CustomWorldAgentStage, CustomWorldAssetCoverageSummary, CustomWorldDraftCardSummary, CustomWorldPendingClarification, EightAnchorContent, } from '../../../packages/shared/src/contracts/customWorldAgent.js'; import { buildDraftSummaryFromIntent, buildDraftTitleFromIntent, type CustomWorldCreatorIntentRecord, } from './customWorldAgentIntentExtractionService.js'; import { CustomWorldAgentQualityGateService } from './customWorldAgentQualityGateService.js'; import { rebuildRoleAssetCoverage } from './customWorldAgentRoleAssetStateService.js'; import type { CustomWorldAgentSessionRecord } from './customWorldAgentSessionStore.js'; import { CustomWorldAgentSuggestedActionService } from './customWorldAgentSuggestedActionService.js'; import { buildAnchorPackFromEightAnchorContent } from './eightAnchorCompatibilityService.js'; import { CustomWorldAgentDraftCompiler } from './customWorldAgentDraftCompiler.js'; export type CustomWorldAgentDerivedStatePatch = Partial< Pick< CustomWorldAgentSessionRecord, | 'currentTurn' | 'anchorContent' | 'progressPercent' | 'lastAssistantReply' | 'stage' | 'focusCardId' | 'creatorIntent' | 'creatorIntentReadiness' | 'anchorPack' | 'draftProfile' | 'pendingClarifications' | 'suggestedActions' | 'recommendedReplies' | 'draftCards' | 'qualityFindings' | 'assetCoverage' > >; export class CustomWorldAgentSnapshotBuilder { constructor( private readonly draftCompiler: CustomWorldAgentDraftCompiler, private readonly suggestedActionService: CustomWorldAgentSuggestedActionService, private readonly qualityGateService: CustomWorldAgentQualityGateService, ) {} // 把“草稿改动后需要重算哪些派生字段”统一封装成一个入口,避免每个 action 都重复拼 patch。 buildRefiningState(params: { previousStage: CustomWorldAgentStage; draftProfile: Record; draftCards?: CustomWorldDraftCardSummary[]; assetCoverage?: CustomWorldAssetCoverageSummary; nextStage?: Extract< CustomWorldAgentStage, | 'object_refining' | 'visual_refining' | 'long_tail_review' | 'ready_to_publish' >; focusCardId?: string | null; }): CustomWorldAgentDerivedStatePatch { const nextDraftCards = params.draftCards ?? this.draftCompiler.compileDraftCards(params.draftProfile); const assetCoverage = params.assetCoverage ?? rebuildRoleAssetCoverage(params.draftProfile); const nextStage = params.nextStage ?? (params.previousStage === 'visual_refining' ? 'visual_refining' : params.previousStage === 'long_tail_review' ? 'long_tail_review' : params.previousStage === 'ready_to_publish' ? 'ready_to_publish' : 'object_refining'); return { stage: nextStage, draftProfile: params.draftProfile, draftCards: nextDraftCards, assetCoverage, qualityFindings: this.qualityGateService.buildQualityFindings({ draftProfile: params.draftProfile, assetCoverage, stage: nextStage, }), focusCardId: params.focusCardId, suggestedActions: this.suggestedActionService.buildSuggestedActions({ stage: nextStage, isReady: true, draftProfile: params.draftProfile, draftCards: nextDraftCards, }), recommendedReplies: [], }; } buildFoundationDraftState(params: { creatorIntent: Record | null; anchorPack: Record | null; draftProfile: Record; assetCoverage?: CustomWorldAssetCoverageSummary; }): CustomWorldAgentDerivedStatePatch { return { ...this.buildRefiningState({ previousStage: 'object_refining', nextStage: 'object_refining', draftProfile: params.draftProfile, assetCoverage: params.assetCoverage, }), creatorIntent: params.creatorIntent, anchorPack: params.anchorPack, pendingClarifications: [], }; } buildMessageTurnState(params: { latestSession: CustomWorldAgentSessionRecord; nextAnchorContent: EightAnchorContent; progressPercent: number; replyText: string; nextCreatorIntent: CustomWorldCreatorIntentRecord; creatorIntentReadiness: CreatorIntentReadiness; derivedDraftProfile: { title: string; summary: string; }; derivedPendingClarifications: CustomWorldPendingClarification[]; derivedStage: CustomWorldAgentStage; shouldStayInDraftStage: boolean; }): CustomWorldAgentDerivedStatePatch { const preservedStage = params.latestSession.stage === 'visual_refining' ? ('visual_refining' as const) : ('object_refining' as const); const nextDraftProfile = params.shouldStayInDraftStage ? ((params.latestSession.draftProfile ?? {}) as Record) : params.progressPercent >= 100 ? { title: buildDraftTitleFromIntent(params.nextCreatorIntent), summary: buildDraftSummaryFromIntent(params.nextCreatorIntent), } : params.derivedDraftProfile; const nextStage = params.shouldStayInDraftStage ? preservedStage : params.derivedStage; const assetCoverage = params.shouldStayInDraftStage ? params.latestSession.assetCoverage : rebuildRoleAssetCoverage(nextDraftProfile); return { currentTurn: params.latestSession.currentTurn + 1, anchorContent: params.nextAnchorContent, progressPercent: params.progressPercent, lastAssistantReply: params.replyText, stage: nextStage, focusCardId: params.shouldStayInDraftStage ? params.latestSession.focusCardId : null, creatorIntent: params.nextCreatorIntent, creatorIntentReadiness: params.creatorIntentReadiness, anchorPack: buildAnchorPackFromEightAnchorContent( params.nextAnchorContent, params.progressPercent, ), draftProfile: nextDraftProfile, draftCards: params.shouldStayInDraftStage ? params.latestSession.draftCards : [], assetCoverage, qualityFindings: this.qualityGateService.buildQualityFindings({ draftProfile: nextDraftProfile, assetCoverage, stage: nextStage, }), pendingClarifications: params.progressPercent >= 100 ? [] : params.derivedPendingClarifications, suggestedActions: params.shouldStayInDraftStage ? this.suggestedActionService.buildSuggestedActions({ stage: preservedStage, isReady: true, draftProfile: params.latestSession.draftProfile, draftCards: params.latestSession.draftCards, }) : params.progressPercent >= 100 ? [ { id: 'draft_foundation', type: 'draft_foundation', label: '生成游戏设定草稿', }, ] : [], recommendedReplies: [], }; } }