import { buildCreatorIntentFromEightAnchorContent, buildAnchorPackFromEightAnchorContent, } from '../eightAnchorCompatibilityService.js'; import { rebuildRoleAssetCoverage } from '../customWorldAgentRoleAssetStateService.js'; import type { CustomWorldAgentActionExecutor } from './types.js'; import type { CustomWorldAgentFoundationDraftService } from '../customWorldAgentFoundationDraftService.js'; import type { CustomWorldAgentAutoAssetService } from '../customWorldAgentAutoAssetService.js'; import type { CustomWorldAgentSnapshotBuilder } from '../customWorldAgentSnapshotBuilder.js'; import type { CustomWorldAgentSessionStore } from '../customWorldAgentSessionStore.js'; import { buildFoundationDraftAssistantMessage } from './helpers.js'; import { buildCheckpointSnapshot, createOperationUpdater, getRequiredSession, } from './executorShared.js'; export function createDraftFoundationExecutor(params: { sessionStore: CustomWorldAgentSessionStore; foundationDraftService: CustomWorldAgentFoundationDraftService; autoAssetService: CustomWorldAgentAutoAssetService | null; snapshotBuilder: CustomWorldAgentSnapshotBuilder; }): CustomWorldAgentActionExecutor<'draft_foundation'> { return async ({ userId, sessionId, operationId }) => { const updateOperation = createOperationUpdater({ sessionStore: params.sessionStore, userId, sessionId, operationId, }); try { await updateOperation({ status: 'running', phaseLabel: '整理世界骨架', phaseDetail: '正在校验已确认锚点,并准备第一版世界框架生成链路。', progress: 12, }); const latestSession = await getRequiredSession({ sessionStore: params.sessionStore, userId, sessionId, }); if (latestSession.progressPercent < 100) { throw new Error('session progressPercent is below 100'); } const creatorIntent = buildCreatorIntentFromEightAnchorContent( latestSession.anchorContent, ); const anchorPack = buildAnchorPackFromEightAnchorContent( latestSession.anchorContent, latestSession.progressPercent, ); const draftProfile = await params.foundationDraftService.generate({ creatorIntent, anchorPack, anchorContent: latestSession.anchorContent, onProgress: async (progress) => { await updateOperation({ status: 'running', phaseLabel: progress.phaseLabel, phaseDetail: progress.phaseDetail, progress: progress.progress, }); }, }); const draftWithAssets = params.autoAssetService ? await params.autoAssetService.populateDraftAssets({ draftProfile, onProgress: async (progress) => { await updateOperation({ status: 'running', phaseLabel: progress.phaseLabel, phaseDetail: progress.phaseDetail, progress: progress.progress, }); }, }) : { draftProfile, assetCoverage: rebuildRoleAssetCoverage(draftProfile), warnings: [], }; await updateOperation({ phaseLabel: '编译草稿卡', phaseDetail: '正在把世界底稿整理成可浏览的卡片摘要和详情结构。', progress: 98, }); const nextState = params.snapshotBuilder.buildFoundationDraftState({ creatorIntent, anchorPack, draftProfile: draftWithAssets.draftProfile as unknown as Record, assetCoverage: draftWithAssets.assetCoverage, }); await params.sessionStore.replaceDerivedState(userId, sessionId, nextState); await params.sessionStore.appendCheckpoint(userId, sessionId, { label: '世界底稿 V1', snapshot: buildCheckpointSnapshot(latestSession, nextState), }); await params.sessionStore.appendMessage( userId, sessionId, buildFoundationDraftAssistantMessage({ relatedOperationId: operationId, draftProfile: draftWithAssets.draftProfile, warnings: draftWithAssets.warnings, }), ); await updateOperation({ status: 'completed', phaseLabel: '世界底稿已生成', phaseDetail: draftWithAssets.warnings.length > 0 ? `第一版世界底稿和 ${(nextState.draftCards ?? []).length} 张草稿卡已经整理完成,另有 ${draftWithAssets.warnings.length} 项资产补齐待后续处理。` : `第一版世界底稿和 ${(nextState.draftCards ?? []).length} 张草稿卡已经整理完成。`, progress: 100, error: null, }); } catch (error) { const currentOperation = await params.sessionStore.getOperation( userId, sessionId, operationId, ); await updateOperation({ status: 'failed', phaseLabel: currentOperation?.phaseLabel?.trim() || '底稿生成失败', phaseDetail: currentOperation?.phaseDetail?.trim() || '这一轮没有成功把设定编成世界底稿。', progress: 100, error: error instanceof Error ? error.message : 'draft foundation failed', }); } }; }