Files
Genarrative/server-node/src/services/customWorldAgentSnapshotBuilder.ts
2026-04-21 18:27:46 +08:00

200 lines
6.9 KiB
TypeScript

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<string, unknown>;
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<string, unknown> | null;
anchorPack: Record<string, unknown> | null;
draftProfile: Record<string, unknown>;
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<string, unknown>)
: 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: [],
};
}
}