import { AnimatePresence, motion } from 'motion/react'; import { lazy, Suspense, useCallback, useEffect, useMemo, useRef, useState, } from 'react'; import type { BigFishRuntimeSnapshotResponse, BigFishSessionSnapshotResponse, ExecuteBigFishActionRequest, SendBigFishMessageRequest, SubmitBigFishInputRequest, } from '../../../packages/shared/src/contracts/bigFish'; import type { BigFishWorkSummary } from '../../../packages/shared/src/contracts/bigFishWorkSummary'; import type { PuzzleAgentActionRequest, PuzzleAgentOperationRecord, } from '../../../packages/shared/src/contracts/puzzleAgentActions'; import type { PuzzleAgentSessionSnapshot, SendPuzzleAgentMessageRequest, } from '../../../packages/shared/src/contracts/puzzleAgentSession'; import type { PuzzleRunSnapshot } from '../../../packages/shared/src/contracts/puzzleRuntimeSession'; import type { PuzzleWorkSummary } from '../../../packages/shared/src/contracts/puzzleWorkSummary'; import type { CustomWorldGalleryCard, CustomWorldLibraryEntry, } from '../../../packages/shared/src/contracts/runtime'; import type { PublicUserSummary } from '../../../packages/shared/src/contracts/auth'; import { buildCustomWorldPlayableCharacters } from '../../data/characterPresets'; import { getPublicAuthUserByCode, getPublicAuthUserById, } from '../../services/authService'; import { createBigFishCreationSession, executeBigFishCreationAction, getBigFishCreationSession, streamBigFishCreationMessage, } from '../../services/big-fish-creation'; import { deleteBigFishWork, listBigFishWorks, } from '../../services/big-fish-works'; import { startBigFishRuntimeRun, submitBigFishRuntimeInput, } from '../../services/big-fish-runtime'; import { readCustomWorldAgentUiState } from '../../services/customWorldAgentUiState'; import { getPlatformProfileDashboard } from '../../services/platform-entry'; import { createPuzzleAgentSession, executePuzzleAgentAction, getPuzzleAgentSession, streamPuzzleAgentMessage, } from '../../services/puzzle-agent'; import { getPuzzleGalleryDetail } from '../../services/puzzle-gallery'; import { advanceLocalPuzzleLevel, dragLocalPuzzlePiece, startLocalPuzzleRun, swapLocalPuzzlePieces, } from '../../services/puzzle-runtime/puzzleLocalRuntime'; import { deletePuzzleWork, listPuzzleWorks } from '../../services/puzzle-works'; import { deleteRpgEntryWorldProfile } from '../../services/rpg-entry'; import { getRpgEntryWorldGalleryDetailByCode } from '../../services/rpg-entry/rpgEntryLibraryClient'; import { deleteRpgCreationAgentSession } from '../../services/rpg-creation'; import { rpgCreationPreviewAdapter } from '../../services/rpg-creation/rpgCreationPreviewAdapter'; import type { CustomWorldProfile } from '../../types'; import { useAuthUi } from '../auth/AuthUiContext'; import { CustomWorldCreationHub } from '../custom-world-home/CustomWorldCreationHub'; import { PuzzleAgentWorkspace } from '../puzzle-agent/PuzzleAgentWorkspace'; import { PuzzleGalleryDetailView } from '../puzzle-gallery/PuzzleGalleryDetailView'; import { PuzzleResultView } from '../puzzle-result/PuzzleResultView'; import { PuzzleRuntimeShell } from '../puzzle-runtime/PuzzleRuntimeShell'; import { useRpgCreationAgentOperationPolling } from '../rpg-entry/useRpgCreationAgentOperationPolling'; import { useRpgCreationEnterWorld } from '../rpg-entry/useRpgCreationEnterWorld'; import { useRpgCreationResultAutosave } from '../rpg-entry/useRpgCreationResultAutosave'; import { useRpgCreationSessionController } from '../rpg-entry/useRpgCreationSessionController'; import { PlatformEntryCreationTypeModal } from './PlatformEntryCreationTypeModal'; import { PlatformEntryHomeView } from './PlatformEntryHomeView'; import { buildCreationHubFallbackItems, normalizeAgentBackedProfile, resolveRpgCreationErrorMessage, } from './platformEntryShared'; import type { PlatformCreationTypeId } from './platformEntryCreationTypes'; import type { PlatformEntryFlowShellProps } from './platformEntryTypes'; import { PlatformEntryWorldDetailView } from './PlatformEntryWorldDetailView'; import { usePlatformEntryBootstrap } from './usePlatformEntryBootstrap'; import { usePlatformEntryLibraryDetail } from './usePlatformEntryLibraryDetail'; import { usePlatformEntryNavigation } from './usePlatformEntryNavigation'; type AgentResultPublishGateView = { blockers: string[]; publishReady: boolean; }; type AgentResultBlockerView = { code?: string; message: string; }; const AGENT_RESULT_STRUCTURAL_BLOCKER_CODES = new Set([ 'publish_missing_world_hook', 'publish_missing_player_premise', 'publish_missing_core_conflict', 'publish_missing_main_chapter', 'publish_missing_first_act', ]); function readProfileTextField( profile: CustomWorldProfile | null, paths: string[], ) { for (const path of paths) { let current: unknown = profile; for (const segment of path.split('.')) { if (!current || typeof current !== 'object') { current = null; break; } current = (current as Record)[segment]; } if (typeof current === 'string' && current.trim()) { return current.trim(); } } return null; } function hasProfileTextArray(profile: CustomWorldProfile | null, key: string) { const value = profile ? (profile as unknown as Record)[key] : null; return Array.isArray(value) ? value.some((entry) => typeof entry === 'string' && entry.trim()) : false; } function hasProfileArray(profile: CustomWorldProfile | null, key: string) { const value = profile ? (profile as unknown as Record)[key] : null; return Array.isArray(value) && value.length > 0; } function hasSceneAct(profile: CustomWorldProfile | null) { const rawProfile = profile as unknown as Record | null; const chapters = rawProfile && (Array.isArray(rawProfile.sceneChapterBlueprints) ? rawProfile.sceneChapterBlueprints : Array.isArray(rawProfile.sceneChapters) ? rawProfile.sceneChapters : []); return Array.isArray(chapters) ? chapters.some((chapter) => { const acts = chapter && typeof chapter === 'object' ? (chapter as Record).acts : null; return Array.isArray(acts) && acts.length > 0; }) : false; } function isAgentResultStructuralBlockerResolved( profile: CustomWorldProfile, code: string | undefined, ) { if (!code || !AGENT_RESULT_STRUCTURAL_BLOCKER_CODES.has(code)) { return false; } if (code === 'publish_missing_world_hook') { return Boolean( readProfileTextField(profile, [ 'worldHook', 'creatorIntent.worldHook', 'anchorContent.worldPromise.hook', 'settingText', ]), ); } if (code === 'publish_missing_player_premise') { return Boolean( readProfileTextField(profile, [ 'playerPremise', 'creatorIntent.playerPremise', 'anchorContent.playerEntryPoint.openingIdentity', 'anchorContent.playerEntryPoint.openingProblem', 'anchorContent.playerEntryPoint.entryMotivation', ]), ); } if (code === 'publish_missing_core_conflict') { return hasProfileTextArray(profile, 'coreConflicts'); } if (code === 'publish_missing_main_chapter') { return ( hasProfileArray(profile, 'chapters') || hasProfileArray(profile, 'sceneChapterBlueprints') || hasProfileArray(profile, 'sceneChapters') ); } return hasSceneAct(profile); } function buildAgentResultPublishGateView( profile: CustomWorldProfile | null, fallbackBlockers: AgentResultBlockerView[], fallbackPublishReady: boolean, ): AgentResultPublishGateView { if (!profile) { return { blockers: fallbackBlockers.map((entry) => entry.message), publishReady: fallbackPublishReady, }; } const blockers = fallbackBlockers .filter( (entry) => !isAgentResultStructuralBlockerResolved(profile, entry.code), ) .map((entry) => entry.message); return { blockers, publishReady: blockers.length === 0, }; } const CustomWorldGenerationView = lazy(async () => { const module = await import('../CustomWorldGenerationView'); return { default: module.CustomWorldGenerationView, }; }); const RpgCreationResultView = lazy(async () => { const module = await import('../rpg-creation-result/RpgCreationResultView'); return { default: module.RpgCreationResultView, }; }); const CustomWorldAgentWorkspace = lazy(async () => { const module = await import( '../custom-world-agent/CustomWorldAgentWorkspace' ); return { default: module.CustomWorldAgentWorkspace, }; }); const BigFishAgentWorkspace = lazy(async () => { const module = await import('../big-fish-creation/BigFishAgentWorkspace'); return { default: module.BigFishAgentWorkspace, }; }); const BigFishResultView = lazy(async () => { const module = await import('../big-fish-result/BigFishResultView'); return { default: module.BigFishResultView, }; }); const BigFishRuntimeShell = lazy(async () => { const module = await import('../big-fish-runtime/BigFishRuntimeShell'); return { default: module.BigFishRuntimeShell, }; }); function LazyPanelFallback({ label }: { label: string }) { return (
{label}
); } export function PlatformEntryFlowShellImpl({ selectionStage, setSelectionStage, hasSavedGame, savedSnapshot, handleContinueGame, handleStartNewGame, handleCustomWorldSelect, }: PlatformEntryFlowShellProps) { const authUi = useAuthUi(); const [showCreationTypeModal, setShowCreationTypeModal] = useState(false); const [selectedDetailEntry, setSelectedDetailEntry] = useState | null>(null); const [bigFishSession, setBigFishSession] = useState(null); const [bigFishWorks, setBigFishWorks] = useState([]); const [bigFishRun, setBigFishRun] = useState(null); const [bigFishError, setBigFishError] = useState(null); const [isBigFishBusy, setIsBigFishBusy] = useState(false); const [isBigFishLoadingLibrary, setIsBigFishLoadingLibrary] = useState(false); const [streamingBigFishReplyText, setStreamingBigFishReplyText] = useState(''); const [isStreamingBigFishReply, setIsStreamingBigFishReply] = useState(false); const bigFishInputInFlightRef = useRef(false); const [puzzleSession, setPuzzleSession] = useState(null); const [puzzleOperation, setPuzzleOperation] = useState(null); const [puzzleWorks, setPuzzleWorks] = useState([]); const [selectedPuzzleDetail, setSelectedPuzzleDetail] = useState(null); const [puzzleRun, setPuzzleRun] = useState(null); const [puzzleError, setPuzzleError] = useState(null); const [isPuzzleBusy, setIsPuzzleBusy] = useState(false); const [isPuzzleLoadingLibrary, setIsPuzzleLoadingLibrary] = useState(false); const [isSearchingPublicCode, setIsSearchingPublicCode] = useState(false); const [publicSearchError, setPublicSearchError] = useState(null); const [searchedPublicUser, setSearchedPublicUser] = useState(null); const [deletingCreationWorkId, setDeletingCreationWorkId] = useState< string | null >(null); const [streamingPuzzleReplyText, setStreamingPuzzleReplyText] = useState(''); const [isStreamingPuzzleReply, setIsStreamingPuzzleReply] = useState(false); const hasInitialAgentSession = Boolean( readCustomWorldAgentUiState().activeSessionId, ); const platformBootstrap = usePlatformEntryBootstrap({ user: authUi?.user, canAccessProtectedData: authUi?.canAccessProtectedData, getProfileDashboard: getPlatformProfileDashboard, handleContinueGame, hasInitialAgentSession, }); const entryNavigation = usePlatformEntryNavigation({ setSelectionStage, setSelectedDetailEntry, }); const { setPlatformTab } = platformBootstrap; const enterCreateTab = useCallback(() => { // 只依赖稳定的 setter,避免把 bootstrap 对象的 render 级引用变化 // 传导成 Agent session 恢复 effect 的重复触发。 setPlatformTab('create'); }, [setPlatformTab]); const sessionController = useRpgCreationSessionController({ userId: authUi?.user?.id, openLoginModal: authUi?.openLoginModal, selectionStage, setSelectionStage, enterCreateTab, onSessionOpened: () => { setShowCreationTypeModal(false); }, }); useRpgCreationAgentOperationPolling({ activeAgentSessionId: sessionController.activeAgentSessionId, activeAgentOperationId: sessionController.activeAgentOperationId, userId: authUi?.user?.id, setAgentOperation: sessionController.setAgentOperation, persistAgentUiState: sessionController.persistAgentUiState, syncAgentSessionSnapshot: sessionController.syncAgentSessionSnapshot, }); const autosaveCoordinator = useRpgCreationResultAutosave({ selectionStage, activeAgentSessionId: sessionController.activeAgentSessionId, agentSession: sessionController.agentSession, generatedCustomWorldProfile: sessionController.generatedCustomWorldProfile, isAgentDraftResultView: sessionController.isAgentDraftResultView, userId: authUi?.user?.id, setGeneratedCustomWorldProfile: sessionController.setGeneratedCustomWorldProfile, setAgentOperation: sessionController.setAgentOperation, setSavedCustomWorldEntries: platformBootstrap.setSavedCustomWorldEntries, setSelectedDetailEntry, refreshCustomWorldWorks: platformBootstrap.refreshCustomWorldWorks, persistAgentUiState: sessionController.persistAgentUiState, syncAgentSessionSnapshot: sessionController.syncAgentSessionSnapshot, buildDraftResultProfile: (session) => rpgCreationPreviewAdapter.buildPreviewFromSession(session), }); const detailNavigation = usePlatformEntryLibraryDetail({ userId: authUi?.user?.id, selectedDetailEntry, setSelectedDetailEntry, savedCustomWorldEntries: platformBootstrap.savedCustomWorldEntries, setSavedCustomWorldEntries: platformBootstrap.setSavedCustomWorldEntries, setGeneratedCustomWorldProfile: sessionController.setGeneratedCustomWorldProfile, setCustomWorldError: sessionController.setCustomWorldError, setCustomWorldAutoSaveError: autosaveCoordinator.setCustomWorldAutoSaveError, setCustomWorldAutoSaveState: autosaveCoordinator.setCustomWorldAutoSaveState, setCustomWorldGenerationViewSource: sessionController.setCustomWorldGenerationViewSource, setCustomWorldResultViewSource: sessionController.setCustomWorldResultViewSource, setSelectionStage, setPlatformTabToCreate: enterCreateTab, setPlatformError: platformBootstrap.setPlatformError, appendBrowseHistoryEntry: platformBootstrap.appendBrowseHistoryEntry, refreshCustomWorldWorks: platformBootstrap.refreshCustomWorldWorks, refreshPublishedGallery: platformBootstrap.refreshPublishedGallery, persistAgentUiState: sessionController.persistAgentUiState, syncAgentSessionSnapshot: sessionController.syncAgentSessionSnapshot, buildDraftResultProfile: (session) => rpgCreationPreviewAdapter.buildPreviewFromSession(session), suppressAgentDraftResultAutoOpen: sessionController.suppressAgentDraftResultAutoOpen, releaseAgentDraftResultAutoOpenSuppression: sessionController.releaseAgentDraftResultAutoOpenSuppression, resetAutoSaveTrackingToIdle: autosaveCoordinator.resetAutoSaveTrackingToIdle, markAutoSavedProfile: autosaveCoordinator.markAutoSavedProfile, }); const enterWorldCoordinator = useRpgCreationEnterWorld({ isAgentDraftResultView: sessionController.isAgentDraftResultView, activeAgentSessionId: sessionController.activeAgentSessionId, generatedCustomWorldProfile: sessionController.generatedCustomWorldProfile, agentSessionProfile: sessionController.agentDraftResultProfile, agentSession: sessionController.agentSession, handleCustomWorldSelect, executePublishWorld: () => autosaveCoordinator.executeAgentActionAndWait({ action: 'publish_world', }), syncAgentDraftResultProfile: autosaveCoordinator.syncAgentDraftResultProfile, setGeneratedCustomWorldProfile: sessionController.setGeneratedCustomWorldProfile, }); const previewCustomWorldCharacters = useMemo( () => sessionController.generatedCustomWorldProfile ? buildCustomWorldPlayableCharacters( sessionController.generatedCustomWorldProfile, ) : [], [sessionController.generatedCustomWorldProfile], ); const agentResultPreview = sessionController.agentSession?.resultPreview ?? null; const agentResultPreviewBlockers = useMemo( () => agentResultPreview?.blockers ?? [], [agentResultPreview], ); const agentResultPublishGateView = useMemo( () => buildAgentResultPublishGateView( sessionController.generatedCustomWorldProfile, agentResultPreviewBlockers, Boolean(agentResultPreview?.publishReady), ), [ agentResultPreview?.publishReady, agentResultPreviewBlockers, sessionController.generatedCustomWorldProfile, ], ); const agentResultPreviewQualityFindings = useMemo( () => agentResultPreview?.qualityFindings ?? [], [agentResultPreview], ); const agentResultPreviewSourceLabel = useMemo(() => { if (!agentResultPreview?.source) { return null; } if (agentResultPreview.source === 'published_profile') { return '已发布世界'; } if (agentResultPreview.source === 'session_preview') { return '会话预览'; } return '服务端预览'; }, [agentResultPreview]); const featuredGalleryEntries = useMemo( () => platformBootstrap.publishedGalleryEntries.slice(0, 6), [platformBootstrap.publishedGalleryEntries], ); const creationHubItems = platformBootstrap.customWorldWorkEntries.length > 0 ? platformBootstrap.customWorldWorkEntries : buildCreationHubFallbackItems( platformBootstrap.savedCustomWorldEntries, ); const resultViewError = autosaveCoordinator.customWorldAutoSaveError ?? sessionController.customWorldError; useEffect(() => { if ( selectionStage === 'custom-world-result' && !sessionController.generatedCustomWorldProfile ) { setSelectionStage(selectedDetailEntry ? 'detail' : 'platform'); } }, [ selectedDetailEntry, selectionStage, sessionController.generatedCustomWorldProfile, setSelectionStage, ]); useEffect(() => { if (selectionStage === 'big-fish-result' && !bigFishSession?.draft) { setSelectionStage( bigFishSession ? 'big-fish-agent-workspace' : 'platform', ); } if (selectionStage === 'big-fish-runtime' && !bigFishRun) { setSelectionStage(bigFishSession?.draft ? 'big-fish-result' : 'platform'); } }, [bigFishRun, bigFishSession, selectionStage, setSelectionStage]); const runProtectedAction = useCallback( (action: () => void) => { if (!authUi?.requireAuth) { action(); return; } authUi.requireAuth(action); }, [authUi], ); const handlePublicCodeSearch = useCallback( async (keyword: string) => { const normalizedKeyword = keyword.trim(); if (!normalizedKeyword) { return; } setIsSearchingPublicCode(true); setPublicSearchError(null); setSearchedPublicUser(null); const upperKeyword = normalizedKeyword.toUpperCase(); const shouldSearchUserIdFirst = /^user[_-][a-z0-9_-]+$/iu.test(normalizedKeyword); const shouldSearchWorkFirst = !shouldSearchUserIdFirst && (upperKeyword.startsWith('CW') || /^\d{1,8}$/u.test(normalizedKeyword)); const shouldSearchUserFirst = shouldSearchUserIdFirst || upperKeyword.startsWith('SY') || !shouldSearchWorkFirst; const tryOpenGalleryEntry = async () => { const entry = await getRpgEntryWorldGalleryDetailByCode(normalizedKeyword); await detailNavigation.openGalleryDetail({ ownerUserId: entry.ownerUserId, profileId: entry.profileId, publicWorkCode: entry.publicWorkCode, authorPublicUserCode: entry.authorPublicUserCode, visibility: 'published', publishedAt: entry.publishedAt, updatedAt: entry.updatedAt, authorDisplayName: entry.authorDisplayName, worldName: entry.worldName, subtitle: entry.subtitle, summaryText: entry.summaryText, coverImageSrc: entry.coverImageSrc, themeMode: entry.themeMode, playableNpcCount: entry.playableNpcCount, landmarkCount: entry.landmarkCount, } satisfies CustomWorldGalleryCard); }; try { if (shouldSearchUserIdFirst) { const user = await getPublicAuthUserById(normalizedKeyword); setSearchedPublicUser(user); return; } if (shouldSearchWorkFirst) { try { await tryOpenGalleryEntry(); return; } catch {} } if (shouldSearchUserFirst) { try { const user = await getPublicAuthUserByCode(normalizedKeyword); setSearchedPublicUser(user); return; } catch {} } if (!shouldSearchWorkFirst) { await tryOpenGalleryEntry(); return; } const user = await getPublicAuthUserByCode(normalizedKeyword); setSearchedPublicUser(user); } catch (error) { setPublicSearchError( resolveRpgCreationErrorMessage(error, '未找到对应的叙世号或作品号。'), ); } finally { setIsSearchingPublicCode(false); } }, [detailNavigation], ); const prepareCreationLaunch = useCallback(() => { if (sessionController.isCreatingAgentSession) { return false; } if (!hasSavedGame) { handleStartNewGame(); } sessionController.setCreationTypeError(null); return true; }, [handleStartNewGame, hasSavedGame, sessionController]); const openCreationTypePicker = useCallback(() => { if (!prepareCreationLaunch()) { return; } setShowCreationTypeModal(true); }, [prepareCreationLaunch]); const resolveBigFishErrorMessage = useCallback( (error: unknown, fallback: string) => resolveRpgCreationErrorMessage(error, fallback), [], ); const resolvePuzzleErrorMessage = useCallback( (error: unknown, fallback: string) => resolveRpgCreationErrorMessage(error, fallback), [], ); const refreshBigFishShelf = useCallback(async () => { setIsBigFishLoadingLibrary(true); try { const worksResponse = await listBigFishWorks(); setBigFishWorks(worksResponse.items); setBigFishError(null); } catch (error) { setBigFishError( resolveBigFishErrorMessage(error, '读取大鱼吃小鱼作品列表失败。'), ); } finally { setIsBigFishLoadingLibrary(false); } }, [resolveBigFishErrorMessage]); const refreshPuzzleShelf = useCallback(async () => { setIsPuzzleLoadingLibrary(true); try { const worksResponse = await listPuzzleWorks(); setPuzzleWorks(worksResponse.items); setPuzzleError(null); } catch (error) { setPuzzleError( resolvePuzzleErrorMessage(error, '读取拼图作品列表失败。'), ); } finally { setIsPuzzleLoadingLibrary(false); } }, [resolvePuzzleErrorMessage]); const openBigFishAgentWorkspace = useCallback(async () => { if (isBigFishBusy) { return; } setIsBigFishBusy(true); setBigFishError(null); setBigFishRun(null); try { const { session } = await createBigFishCreationSession({}); setBigFishSession(session); enterCreateTab(); setShowCreationTypeModal(false); setSelectionStage('big-fish-agent-workspace'); } catch (error) { setBigFishError( resolveBigFishErrorMessage(error, '开启大鱼吃小鱼共创工作台失败。'), ); } finally { setIsBigFishBusy(false); } }, [ enterCreateTab, isBigFishBusy, resolveBigFishErrorMessage, setSelectionStage, ]); const openPuzzleAgentWorkspace = useCallback(async () => { if (isPuzzleBusy) { return; } setIsPuzzleBusy(true); setPuzzleError(null); setPuzzleRun(null); setPuzzleOperation(null); try { const { session } = await createPuzzleAgentSession({}); setPuzzleSession(session); enterCreateTab(); setShowCreationTypeModal(false); setSelectionStage('puzzle-agent-workspace'); } catch (error) { setPuzzleError( resolvePuzzleErrorMessage(error, '开启拼图共创工作台失败。'), ); } finally { setIsPuzzleBusy(false); } }, [ enterCreateTab, isPuzzleBusy, resolvePuzzleErrorMessage, setSelectionStage, ]); const handleCreationHubCreateType = useCallback( (type: PlatformCreationTypeId) => { if (type === 'airp' || type === 'visual-novel') { return; } if (!prepareCreationLaunch()) { return; } if (type === 'rpg') { runProtectedAction(() => { void sessionController.openRpgAgentWorkspace(); }); return; } if (type === 'big-fish') { runProtectedAction(() => { void openBigFishAgentWorkspace(); }); return; } if (type === 'puzzle') { runProtectedAction(() => { void openPuzzleAgentWorkspace(); }); } }, [ openBigFishAgentWorkspace, openPuzzleAgentWorkspace, prepareCreationLaunch, runProtectedAction, sessionController, ], ); const leaveBigFishFlow = useCallback(() => { setBigFishError(null); setBigFishRun(null); setStreamingBigFishReplyText(''); setIsStreamingBigFishReply(false); enterCreateTab(); setSelectionStage('platform'); }, [enterCreateTab, setSelectionStage]); const leavePuzzleFlow = useCallback(() => { setPuzzleError(null); setPuzzleOperation(null); setPuzzleRun(null); setStreamingPuzzleReplyText(''); setIsStreamingPuzzleReply(false); enterCreateTab(); setSelectionStage('platform'); }, [enterCreateTab, setSelectionStage]); const submitBigFishMessage = useCallback( async (payload: SendBigFishMessageRequest) => { if (!bigFishSession || isStreamingBigFishReply) { return; } const optimisticMessage = { id: payload.clientMessageId, role: 'user', kind: 'chat', text: payload.text.trim(), createdAt: new Date().toISOString(), }; setBigFishError(null); setStreamingBigFishReplyText(''); setIsStreamingBigFishReply(true); setBigFishSession((current) => current ? { ...current, messages: [...current.messages, optimisticMessage], updatedAt: optimisticMessage.createdAt, } : current, ); try { const nextSession = await streamBigFishCreationMessage( bigFishSession.sessionId, payload, { onUpdate: setStreamingBigFishReplyText, }, ); setBigFishSession(nextSession); setStreamingBigFishReplyText(''); } catch (error) { setBigFishError( resolveBigFishErrorMessage(error, '发送大鱼吃小鱼共创消息失败。'), ); } finally { setIsStreamingBigFishReply(false); } }, [bigFishSession, isStreamingBigFishReply, resolveBigFishErrorMessage], ); const submitPuzzleMessage = useCallback( async (payload: SendPuzzleAgentMessageRequest) => { if (!puzzleSession || isStreamingPuzzleReply) { return; } const optimisticMessage = { id: payload.clientMessageId, role: 'user', kind: 'chat', text: payload.text.trim(), createdAt: new Date().toISOString(), } satisfies PuzzleAgentSessionSnapshot['messages'][number]; setPuzzleError(null); setStreamingPuzzleReplyText(''); setIsStreamingPuzzleReply(true); setPuzzleSession((current) => current ? { ...current, messages: [...current.messages, optimisticMessage], updatedAt: optimisticMessage.createdAt, } : current, ); try { const nextSession = await streamPuzzleAgentMessage( puzzleSession.sessionId, payload, { onUpdate: setStreamingPuzzleReplyText, }, ); setPuzzleSession(nextSession); setStreamingPuzzleReplyText(''); } catch (error) { setPuzzleError( resolvePuzzleErrorMessage(error, '发送拼图共创消息失败。'), ); } finally { setIsStreamingPuzzleReply(false); } }, [isStreamingPuzzleReply, puzzleSession, resolvePuzzleErrorMessage], ); const executeBigFishAction = useCallback( async (payload: ExecuteBigFishActionRequest) => { if (!bigFishSession || isBigFishBusy) { return; } setIsBigFishBusy(true); setBigFishError(null); try { const { session } = await executeBigFishCreationAction( bigFishSession.sessionId, payload, ); setBigFishSession(session); if (payload.action === 'big_fish_compile_draft') { setSelectionStage('big-fish-result'); } } catch (error) { setBigFishError( resolveBigFishErrorMessage(error, '执行大鱼吃小鱼操作失败。'), ); } finally { setIsBigFishBusy(false); } }, [ bigFishSession, isBigFishBusy, resolveBigFishErrorMessage, setSelectionStage, ], ); const executePuzzleAction = useCallback( async (payload: PuzzleAgentActionRequest) => { if (!puzzleSession || isPuzzleBusy) { return; } setIsPuzzleBusy(true); setPuzzleError(null); try { const { operation } = await executePuzzleAgentAction( puzzleSession.sessionId, payload, ); setPuzzleOperation(operation); if (payload.action === 'publish_puzzle_work') { await refreshPuzzleShelf(); } const { session } = await getPuzzleAgentSession( puzzleSession.sessionId, ); setPuzzleSession(session); if (payload.action === 'compile_puzzle_draft') { setSelectionStage('puzzle-result'); } if ( payload.action === 'publish_puzzle_work' && session.publishedProfileId ) { const galleryDetail = await getPuzzleGalleryDetail( session.publishedProfileId, ); setSelectedPuzzleDetail(galleryDetail.item); setSelectionStage('puzzle-gallery-detail'); } } catch (error) { setPuzzleError(resolvePuzzleErrorMessage(error, '执行拼图操作失败。')); } finally { setIsPuzzleBusy(false); } }, [ isPuzzleBusy, puzzleSession, refreshPuzzleShelf, resolvePuzzleErrorMessage, setSelectionStage, ], ); const startBigFishRun = useCallback(async () => { if (!bigFishSession || isBigFishBusy) { return; } setIsBigFishBusy(true); setBigFishError(null); try { const { run } = await startBigFishRuntimeRun(bigFishSession.sessionId); setBigFishRun(run); setSelectionStage('big-fish-runtime'); } catch (error) { setBigFishError( resolveBigFishErrorMessage(error, '启动大鱼吃小鱼测试玩法失败。'), ); } finally { setIsBigFishBusy(false); } }, [ bigFishSession, isBigFishBusy, resolveBigFishErrorMessage, setSelectionStage, ]); const startPuzzleRunFromProfile = useCallback( async (profileId: string) => { if (isPuzzleBusy) { return; } setIsPuzzleBusy(true); setPuzzleError(null); try { const { item } = await getPuzzleGalleryDetail(profileId); setSelectedPuzzleDetail(item); setPuzzleRun(startLocalPuzzleRun(item)); setSelectionStage('puzzle-runtime'); } catch (error) { setPuzzleError(resolvePuzzleErrorMessage(error, '启动拼图玩法失败。')); } finally { setIsPuzzleBusy(false); } }, [isPuzzleBusy, resolvePuzzleErrorMessage, setSelectionStage], ); const submitBigFishInput = useCallback( (payload: SubmitBigFishInputRequest) => { if (!bigFishRun || bigFishInputInFlightRef.current) { return; } bigFishInputInFlightRef.current = true; void submitBigFishRuntimeInput(bigFishRun.runId, payload) .then(({ run }) => { setBigFishRun(run); }) .catch((error) => { setBigFishError( resolveBigFishErrorMessage(error, '同步大鱼吃小鱼输入失败。'), ); }) .finally(() => { bigFishInputInFlightRef.current = false; }); }, [bigFishRun, resolveBigFishErrorMessage], ); const swapPuzzlePiecesInRun = useCallback( (payload: { firstPieceId: string; secondPieceId: string }) => { if (!puzzleRun || isPuzzleBusy) { return; } setPuzzleError(null); setPuzzleRun(swapLocalPuzzlePieces(puzzleRun, payload)); }, [isPuzzleBusy, puzzleRun], ); const dragPuzzlePiece = useCallback( (payload: { pieceId: string; targetRow: number; targetCol: number; }) => { if (!puzzleRun || isPuzzleBusy) { return; } setPuzzleError(null); setPuzzleRun(dragLocalPuzzlePiece(puzzleRun, payload)); }, [isPuzzleBusy, puzzleRun], ); const advancePuzzleLevel = useCallback(async () => { if (!puzzleRun || isPuzzleBusy) { return; } setPuzzleError(null); setPuzzleRun(advanceLocalPuzzleLevel(puzzleRun)); }, [isPuzzleBusy, puzzleRun]); const leaveAgentWorkspace = useCallback(() => { enterCreateTab(); sessionController.resetSessionViewState(); sessionController.setGeneratedCustomWorldProfile(null); autosaveCoordinator.resetAutoSaveTrackingToIdle(); sessionController.persistAgentUiState( sessionController.activeAgentSessionId, null, ); setSelectionStage('platform'); }, [ autosaveCoordinator, enterCreateTab, sessionController, setSelectionStage, ]); const leaveAgentDraftGeneration = useCallback(() => { if (sessionController.isActiveGenerationRunning) { return; } sessionController.setAgentDraftGenerationStartedAt(null); sessionController.setCustomWorldGenerationViewSource(null); setSelectionStage('agent-workspace'); }, [sessionController, setSelectionStage]); const leaveAgentDraftResult = useCallback(() => { sessionController.suppressAgentDraftResultAutoOpen(); sessionController.setGeneratedCustomWorldProfile(null); sessionController.setCustomWorldError(null); autosaveCoordinator.resetAutoSaveTrackingToIdle(); sessionController.setCustomWorldGenerationViewSource(null); sessionController.setCustomWorldResultViewSource(null); enterCreateTab(); setSelectionStage('platform'); }, [ autosaveCoordinator, enterCreateTab, sessionController, setSelectionStage, ]); const leaveCustomWorldResult = useCallback(() => { sessionController.setGeneratedCustomWorldProfile(null); sessionController.setCustomWorldError(null); autosaveCoordinator.resetAutoSaveTrackingToIdle(); sessionController.setCustomWorldGenerationViewSource(null); sessionController.setCustomWorldResultViewSource(null); setSelectionStage(selectedDetailEntry ? 'detail' : 'platform'); }, [ autosaveCoordinator, selectedDetailEntry, sessionController, setSelectionStage, ]); const handleStartSelectedWorld = useCallback(() => { if (!selectedDetailEntry) { return; } runProtectedAction(() => { handleCustomWorldSelect(selectedDetailEntry.profile); }); }, [handleCustomWorldSelect, runProtectedAction, selectedDetailEntry]); const handleExperienceRpgWork = useCallback( (work: (typeof creationHubItems)[number]) => { if (!work.profileId) { return; } runProtectedAction(() => { const matchedEntry = platformBootstrap.savedCustomWorldEntries.find( (entry) => entry.profileId === work.profileId, ); if (!matchedEntry) { platformBootstrap.setPlatformError('未找到可体验的作品,请刷新后重试。'); return; } handleCustomWorldSelect(matchedEntry.profile); }); }, [ handleCustomWorldSelect, platformBootstrap, platformBootstrap.savedCustomWorldEntries, runProtectedAction, ], ); const handleDeleteLibraryEntry = useCallback( (entry: CustomWorldLibraryEntry) => { if (!entry.profileId || deletingCreationWorkId) { return; } runProtectedAction(() => { const confirmed = window.confirm( `确认删除作品《${entry.worldName}》吗?删除后会从你的作品列表和公开广场中移除。`, ); if (!confirmed) { return; } setDeletingCreationWorkId(entry.profileId); platformBootstrap.setPlatformError(null); void deleteRpgEntryWorldProfile(entry.profileId) .then(async (entries) => { platformBootstrap.setSavedCustomWorldEntries(entries); await platformBootstrap.refreshCustomWorldWorks().catch(() => []); await platformBootstrap.refreshPublishedGallery().catch(() => []); }) .catch((error) => { platformBootstrap.setPlatformError( resolveRpgCreationErrorMessage(error, '删除自定义世界失败。'), ); }) .finally(() => { setDeletingCreationWorkId(null); }); }); }, [deletingCreationWorkId, platformBootstrap, runProtectedAction], ); const handleDeletePublishedWork = useCallback( (work: (typeof creationHubItems)[number]) => { if (deletingCreationWorkId) { return; } runProtectedAction(() => { const confirmed = window.confirm( `确认删除作品《${work.title}》吗?删除后会从你的作品列表和公开广场中移除。`, ); if (!confirmed) { return; } setDeletingCreationWorkId(work.workId); platformBootstrap.setPlatformError(null); const deleteTask = work.sourceType === 'published_profile' && work.profileId ? deleteRpgEntryWorldProfile(work.profileId).then(async (entries) => { platformBootstrap.setSavedCustomWorldEntries(entries); await platformBootstrap.refreshCustomWorldWorks().catch(() => []); }) : work.sourceType === 'agent_session' && work.sessionId ? deleteRpgCreationAgentSession(work.sessionId).then((items) => { platformBootstrap.setCustomWorldWorkEntries(items); }) : Promise.reject(new Error('当前 RPG 作品缺少可删除 ID。')); void deleteTask .then(async () => { await platformBootstrap.refreshPublishedGallery().catch(() => []); }) .catch((error) => { platformBootstrap.setPlatformError( resolveRpgCreationErrorMessage(error, '删除自定义世界失败。'), ); }) .finally(() => { setDeletingCreationWorkId(null); }); }); }, [deletingCreationWorkId, platformBootstrap, runProtectedAction], ); const handleDeleteBigFishWork = useCallback( (work: BigFishWorkSummary) => { if (deletingCreationWorkId) { return; } runProtectedAction(() => { const confirmed = window.confirm( `确认删除作品《${work.title}》吗?删除后会从你的作品列表中移除。`, ); if (!confirmed) { return; } setDeletingCreationWorkId(work.workId); setBigFishError(null); void deleteBigFishWork(work.sourceSessionId) .then((response) => { setBigFishWorks(response.items); }) .catch((error) => { setBigFishError( resolveBigFishErrorMessage(error, '删除大鱼吃小鱼作品失败。'), ); }) .finally(() => { setDeletingCreationWorkId(null); }); }); }, [deletingCreationWorkId, resolveBigFishErrorMessage, runProtectedAction], ); const handleDeletePuzzleWork = useCallback( (work: PuzzleWorkSummary) => { if (deletingCreationWorkId) { return; } runProtectedAction(() => { const confirmed = window.confirm( `确认删除作品《${work.levelName}》吗?删除后会从你的作品列表和公开广场中移除。`, ); if (!confirmed) { return; } setDeletingCreationWorkId(work.workId); setPuzzleError(null); void deletePuzzleWork(work.profileId) .then((response) => { setPuzzleWorks(response.items); }) .catch((error) => { setPuzzleError(resolvePuzzleErrorMessage(error, '删除拼图作品失败。')); }) .finally(() => { setDeletingCreationWorkId(null); }); }); }, [deletingCreationWorkId, resolvePuzzleErrorMessage, runProtectedAction], ); const openPuzzleDetail = useCallback( async (profileId: string) => { setIsPuzzleBusy(true); setPuzzleError(null); try { const { item } = await getPuzzleGalleryDetail(profileId); setSelectedPuzzleDetail(item); enterCreateTab(); setSelectionStage('puzzle-gallery-detail'); } catch (error) { setPuzzleError(resolvePuzzleErrorMessage(error, '读取拼图详情失败。')); } finally { setIsPuzzleBusy(false); } }, [enterCreateTab, resolvePuzzleErrorMessage, setSelectionStage], ); const openPuzzleDraft = useCallback( async (item: PuzzleWorkSummary) => { const sessionId = item.sourceSessionId?.trim(); if (!sessionId) { setPuzzleError('这份拼图草稿缺少会话信息,请重新开始创作。'); return; } setIsPuzzleBusy(true); setPuzzleError(null); setPuzzleOperation(null); setPuzzleRun(null); setSelectedPuzzleDetail(null); setStreamingPuzzleReplyText(''); setIsStreamingPuzzleReply(false); try { const { session } = await getPuzzleAgentSession(sessionId); setPuzzleSession(session); enterCreateTab(); setSelectionStage(session.draft ? 'puzzle-result' : 'puzzle-agent-workspace'); } catch (error) { await refreshPuzzleShelf().catch(() => undefined); setPuzzleError(resolvePuzzleErrorMessage(error, '读取拼图创作草稿失败。')); enterCreateTab(); setSelectionStage('platform'); } finally { setIsPuzzleBusy(false); } }, [ enterCreateTab, refreshPuzzleShelf, resolvePuzzleErrorMessage, setSelectionStage, ], ); const openBigFishDraft = useCallback( async (item: BigFishWorkSummary) => { const sessionId = item.sourceSessionId?.trim(); if (!sessionId) { setBigFishError('这份大鱼吃小鱼草稿缺少会话信息,请重新开始创作。'); return; } setIsBigFishBusy(true); setBigFishError(null); setBigFishRun(null); setStreamingBigFishReplyText(''); setIsStreamingBigFishReply(false); try { const { session } = await getBigFishCreationSession(sessionId); setBigFishSession(session); enterCreateTab(); setSelectionStage( session.draft ? 'big-fish-result' : 'big-fish-agent-workspace', ); } catch (error) { await refreshBigFishShelf().catch(() => undefined); setBigFishError( resolveBigFishErrorMessage(error, '读取大鱼吃小鱼创作草稿失败。'), ); enterCreateTab(); setSelectionStage('platform'); } finally { setIsBigFishBusy(false); } }, [ enterCreateTab, refreshBigFishShelf, resolveBigFishErrorMessage, setSelectionStage, ], ); const startBigFishRunFromWork = useCallback( async (item: BigFishWorkSummary) => { const sessionId = item.sourceSessionId?.trim(); if (!sessionId) { setBigFishError('当前作品缺少会话信息,暂时无法进入玩法。'); return; } setIsBigFishBusy(true); setBigFishError(null); try { const { session } = await getBigFishCreationSession(sessionId); const { run } = await startBigFishRuntimeRun(sessionId); setBigFishSession(session); setBigFishRun(run); setSelectionStage('big-fish-runtime'); } catch (error) { setBigFishError( resolveBigFishErrorMessage(error, '启动大鱼吃小鱼玩法失败。'), ); } finally { setIsBigFishBusy(false); } }, [resolveBigFishErrorMessage, setSelectionStage], ); useEffect(() => { if ( (platformBootstrap.platformTab === 'create' || selectionStage === 'platform') && platformBootstrap.canReadProtectedData ) { void refreshPuzzleShelf(); } }, [ platformBootstrap.canReadProtectedData, platformBootstrap.platformTab, refreshPuzzleShelf, selectionStage, ]); useEffect(() => { if ( (platformBootstrap.platformTab === 'create' || selectionStage === 'platform') && platformBootstrap.canReadProtectedData ) { void refreshBigFishShelf(); } }, [ platformBootstrap.canReadProtectedData, platformBootstrap.platformTab, refreshBigFishShelf, selectionStage, ]); const creationHubContent = ( { platformBootstrap.setPlatformError(null); setBigFishError(null); setPuzzleError(null); void platformBootstrap.refreshCustomWorldWorks().catch((error) => { platformBootstrap.setPlatformError( resolveRpgCreationErrorMessage(error, '读取创作作品列表失败。'), ); }); void refreshBigFishShelf(); void refreshPuzzleShelf(); }} createError={ sessionController.creationTypeError ?? bigFishError ?? puzzleError } createBusy={ sessionController.isCreatingAgentSession || isBigFishBusy || isPuzzleBusy } onCreateType={handleCreationHubCreateType} onOpenDraft={(item) => { runProtectedAction(() => { void detailNavigation.handleOpenCreationWork(item); }); }} onEnterPublished={(profileId) => { runProtectedAction(() => { const matchedWork = creationHubItems.find( (entry) => entry.profileId === profileId, ); if (!matchedWork) { return; } void detailNavigation.handleOpenCreationWork(matchedWork); }); }} onDeletePublished={(item) => { handleDeletePublishedWork(item); }} deletingWorkId={deletingCreationWorkId} onExperienceRpg={(item) => { handleExperienceRpgWork(item); }} bigFishItems={bigFishWorks} onOpenBigFishDetail={(item) => { runProtectedAction(() => { void openBigFishDraft(item); }); }} onExperienceBigFish={(item) => { runProtectedAction(() => { void startBigFishRunFromWork(item); }); }} onDeleteBigFish={(item) => { handleDeleteBigFishWork(item); }} puzzleItems={puzzleWorks} onOpenPuzzleDetail={(item) => { runProtectedAction(() => { if (item.publicationStatus === 'draft') { void openPuzzleDraft(item); return; } void openPuzzleDetail(item.profileId); }); }} onExperiencePuzzle={(profileId) => { runProtectedAction(() => { void startPuzzleRunFromProfile(profileId); }); }} onDeletePuzzle={(item) => { handleDeletePuzzleWork(item); }} /> ); return ( <> {selectionStage === 'platform' && ( { void platformBootstrap.handleResumeSaveEntry(entry); }} onOpenCreateWorld={openCreationTypePicker} onOpenCreateTypePicker={openCreationTypePicker} onOpenGalleryDetail={(entry) => { runProtectedAction(() => { void detailNavigation.openGalleryDetail(entry); }); }} onOpenLibraryDetail={(entry) => { runProtectedAction(() => { detailNavigation.openLibraryDetail(entry); }); }} onDeleteLibraryEntry={(entry) => { handleDeleteLibraryEntry(entry); }} deletingLibraryEntryId={deletingCreationWorkId} onSearchPublicCode={(keyword) => { void handlePublicCodeSearch(keyword); }} isSearchingPublicCode={isSearchingPublicCode} onOpenProfileDashboardCard={() => { if (platformBootstrap.dashboardError) { void platformBootstrap.refreshProfileDashboard(); } }} /> )} {selectionStage === 'detail' && ( {detailNavigation.isDetailLoading || !selectedDetailEntry ? (
{detailNavigation.detailError || '正在读取作品详情...'}
) : ( { detailNavigation.setDetailError(null); entryNavigation.backToPlatformHome(); }} onStartGame={handleStartSelectedWorld} onContinueEdit={ detailNavigation.isSelectedWorldOwned ? () => { runProtectedAction(() => { detailNavigation.openSavedCustomWorldEditor( selectedDetailEntry, ); }); } : null } onPublish={ selectedDetailEntry.visibility === 'draft' && detailNavigation.isSelectedWorldOwned ? () => { runProtectedAction(() => { void detailNavigation.handlePublishSelectedWorld(); }); } : null } onUnpublish={ selectedDetailEntry.visibility === 'published' && detailNavigation.isSelectedWorldOwned ? () => { runProtectedAction(() => { void detailNavigation.handleUnpublishSelectedWorld(); }); } : null } onDelete={ detailNavigation.isSelectedWorldOwned ? () => { runProtectedAction(() => { void detailNavigation.handleDeleteSelectedWorld(); }); } : null } /> )}
)} {selectionStage === 'agent-workspace' && ( } > {sessionController.agentSession ? ( { void sessionController.submitAgentMessage(payload); }} onExecuteAction={(payload) => { void sessionController.executeAgentAction(payload); }} /> ) : (
{sessionController.isLoadingAgentSession ? '正在准备 Agent 共创工作区...' : sessionController.agentWorkspaceRestoreError || '正在恢复创作工作区...'}
)}
)} {selectionStage === 'big-fish-agent-workspace' && ( } > { void submitBigFishMessage(payload); }} onExecuteAction={(payload) => { void executeBigFishAction(payload); }} /> )} {selectionStage === 'big-fish-result' && bigFishSession?.draft && ( } > { setSelectionStage('big-fish-agent-workspace'); }} onExecuteAction={(payload) => { void executeBigFishAction(payload); }} onStartTestRun={() => { void startBigFishRun(); }} /> )} {selectionStage === 'big-fish-runtime' && ( } > { setSelectionStage('big-fish-result'); }} onSubmitInput={submitBigFishInput} /> )} {selectionStage === 'puzzle-agent-workspace' && ( { void submitPuzzleMessage(payload); }} onExecuteAction={(payload) => { void executePuzzleAction(payload); }} /> )} {selectionStage === 'puzzle-result' && puzzleSession?.draft && ( { setSelectionStage('puzzle-agent-workspace'); }} onExecuteAction={(payload) => { void executePuzzleAction(payload); }} /> )} {selectionStage === 'puzzle-gallery-detail' && selectedPuzzleDetail && ( { enterCreateTab(); setSelectionStage('platform'); }} onStartGame={() => { void startPuzzleRunFromProfile(selectedPuzzleDetail.profileId); }} /> )} {selectionStage === 'puzzle-runtime' && ( { setSelectionStage('puzzle-gallery-detail'); }} onSwapPieces={(payload) => { void swapPuzzlePiecesInRun(payload); }} onDragPiece={(payload) => { void dragPuzzlePiece(payload); }} onAdvanceNextLevel={() => { void advancePuzzleLevel(); }} /> )} {selectionStage === 'custom-world-generating' && ( } > { void sessionController.executeAgentAction({ action: 'draft_foundation', }); }} onInterrupt={undefined} backLabel="返回工作区" settingActionLabel={null} retryLabel="重新生成草稿" settingTitle="当前世界信息" settingDescription={null} progressTitle="世界草稿生成进度" activeBadgeLabel="草稿编译中" pausedBadgeLabel="草稿生成已暂停" idleBadgeLabel="等待返回工作区" /> )} {selectionStage === 'custom-world-result' && sessionController.generatedCustomWorldProfile && ( } > { sessionController.setGeneratedCustomWorldProfile( normalizeAgentBackedProfile(profile), ); }} onBack={ sessionController.isAgentDraftResultView ? () => { void (async () => { const currentProfile = sessionController.generatedCustomWorldProfile; if (!currentProfile) { leaveAgentDraftResult(); return; } await autosaveCoordinator.syncAgentDraftResultProfile( currentProfile, ); leaveAgentDraftResult(); })().catch((error) => { sessionController.setCustomWorldError( resolveRpgCreationErrorMessage( error, '返回创作前同步草稿失败。', ), ); }); } : leaveCustomWorldResult } onEditSetting={undefined} onRegenerate={undefined} onContinueExpand={undefined} onEnterWorld={() => { runProtectedAction(() => { void enterWorldCoordinator .enterWorldFromCurrentResult() .catch((error) => { sessionController.setCustomWorldError( resolveRpgCreationErrorMessage( error, '发布并进入世界失败。', ), ); }); }); }} onTestWorld={ sessionController.isAgentDraftResultView && sessionController.agentSession?.stage !== 'published' ? () => { runProtectedAction(() => { void enterWorldCoordinator .enterWorldForTestFromCurrentResult() .catch((error) => { sessionController.setCustomWorldError( resolveRpgCreationErrorMessage( error, '进入作品测试失败。', ), ); }); }); } : undefined } onPublishWorld={ sessionController.isAgentDraftResultView && sessionController.agentSession?.stage !== 'published' ? async () => { try { await enterWorldCoordinator.publishCurrentResult(); } catch (error) { sessionController.setCustomWorldError( resolveRpgCreationErrorMessage( error, '发布到广场失败。', ), ); throw error; } } : undefined } onGenerateEntity={ sessionController.isAgentDraftResultView ? async (kind) => { const action = kind === 'landmark' ? 'generate_landmarks' : 'generate_characters'; const latestSession = await autosaveCoordinator.executeAgentActionAndWait({ action, count: 1, ...(kind === 'playable' ? { roleType: 'playable' as const } : kind === 'story' ? { roleType: 'story' as const } : {}), }); const latestProfile = latestSession ? rpgCreationPreviewAdapter.buildPreviewFromSession( latestSession, ) : null; if (latestProfile) { sessionController.setGeneratedCustomWorldProfile( latestProfile, ); } return { profile: latestProfile }; } : undefined } onDeleteEntities={ sessionController.isAgentDraftResultView ? async (kind, ids) => { if (ids.length === 0) return; const latestSession = await autosaveCoordinator.executeAgentActionAndWait( kind === 'story' ? { action: 'delete_characters', roleIds: ids } : { action: 'delete_landmarks', sceneIds: ids }, ); const latestProfile = latestSession ? rpgCreationPreviewAdapter.buildPreviewFromSession( latestSession, ) : null; if (latestProfile) { sessionController.setGeneratedCustomWorldProfile( latestProfile, ); } } : undefined } readOnly={false} compactAgentResultMode={ sessionController.isAgentDraftResultView } backLabel={ sessionController.isAgentDraftResultView ? '返回创作' : undefined } editActionLabel="继续调整设定" enterWorldActionLabel={ sessionController.isAgentDraftResultView && sessionController.agentSession?.stage !== 'published' ? '发布并进入世界' : '进入世界' } publishReady={ sessionController.isAgentDraftResultView ? agentResultPublishGateView.publishReady : true } publishBlockers={ sessionController.isAgentDraftResultView ? agentResultPublishGateView.blockers : [] } qualityFindings={ sessionController.isAgentDraftResultView ? agentResultPreviewQualityFindings : [] } previewSourceLabel={ sessionController.isAgentDraftResultView ? agentResultPreviewSourceLabel : null } autoSaveState={autosaveCoordinator.customWorldAutoSaveState} /> )}
{ if ( sessionController.isCreatingAgentSession || isBigFishBusy || isPuzzleBusy ) { return; } setShowCreationTypeModal(false); }} onSelectRpg={() => { runProtectedAction(() => { void sessionController.openRpgAgentWorkspace(); }); }} onSelectBigFish={() => { runProtectedAction(() => { void openBigFishAgentWorkspace(); }); }} onSelectPuzzle={() => { runProtectedAction(() => { void openPuzzleAgentWorkspace(); }); }} /> {(searchedPublicUser || publicSearchError) && (
公开编号搜索
{publicSearchError ? '未找到结果' : '命中用户'}
{publicSearchError ? (
{publicSearchError}
) : searchedPublicUser ? (
{searchedPublicUser.displayName}
叙世号 {searchedPublicUser.publicUserCode}
) : null}
)}
); } export default PlatformEntryFlowShellImpl;