feat: restore agent sessions from creation drafts

This commit is contained in:
2026-04-23 21:23:46 +08:00
parent 349a397888
commit 53a9cdd791
11 changed files with 949 additions and 18 deletions

View File

@@ -16,6 +16,7 @@ import type {
SendBigFishMessageRequest,
SubmitBigFishInputRequest,
} from '../../../packages/shared/src/contracts/bigFish';
import type { BigFishWorkSummary } from '../../../packages/shared/src/contracts/bigFishWorkSummary';
import type {
PuzzleAgentActionRequest,
PuzzleAgentOperationRecord,
@@ -31,8 +32,10 @@ import { buildCustomWorldPlayableCharacters } from '../../data/characterPresets'
import {
createBigFishCreationSession,
executeBigFishCreationAction,
getBigFishCreationSession,
streamBigFishCreationMessage,
} from '../../services/big-fish-creation';
import { listBigFishWorks } from '../../services/big-fish-works';
import {
startBigFishRuntimeRun,
submitBigFishRuntimeInput,
@@ -149,10 +152,12 @@ export function PlatformEntryFlowShellImpl({
useState<CustomWorldLibraryEntry<CustomWorldProfile> | null>(null);
const [bigFishSession, setBigFishSession] =
useState<BigFishSessionSnapshotResponse | null>(null);
const [bigFishWorks, setBigFishWorks] = useState<BigFishWorkSummary[]>([]);
const [bigFishRun, setBigFishRun] =
useState<BigFishRuntimeSnapshotResponse | null>(null);
const [bigFishError, setBigFishError] = useState<string | null>(null);
const [isBigFishBusy, setIsBigFishBusy] = useState(false);
const [isBigFishLoadingLibrary, setIsBigFishLoadingLibrary] = useState(false);
const [streamingBigFishReplyText, setStreamingBigFishReplyText] =
useState('');
const [isStreamingBigFishReply, setIsStreamingBigFishReply] = useState(false);
@@ -404,6 +409,22 @@ export function PlatformEntryFlowShellImpl({
[],
);
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);
@@ -1007,6 +1028,112 @@ export function PlatformEntryFlowShellImpl({
[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' ||
@@ -1022,24 +1149,50 @@ export function PlatformEntryFlowShellImpl({
selectionStage,
]);
useEffect(() => {
if (
(platformBootstrap.platformTab === 'create' ||
selectionStage === 'platform') &&
platformBootstrap.canReadProtectedData
) {
void refreshBigFishShelf();
}
}, [
platformBootstrap.canReadProtectedData,
platformBootstrap.platformTab,
refreshBigFishShelf,
selectionStage,
]);
const creationHubContent = (
<CustomWorldCreationHub
items={creationHubItems}
loading={platformBootstrap.isLoadingPlatform || isPuzzleLoadingLibrary}
loading={
platformBootstrap.isLoadingPlatform ||
isBigFishLoadingLibrary ||
isPuzzleLoadingLibrary
}
error={
platformBootstrap.isLoadingPlatform || isPuzzleLoadingLibrary
platformBootstrap.isLoadingPlatform ||
isBigFishLoadingLibrary ||
isPuzzleLoadingLibrary
? null
: (platformBootstrap.platformError ??
sessionController.agentWorkspaceRestoreError ??
bigFishError ??
puzzleError)
}
onRetry={() => {
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
@@ -1073,10 +1226,25 @@ export function PlatformEntryFlowShellImpl({
onExperienceRpg={(item) => {
handleExperienceRpgWork(item);
}}
puzzleItems={puzzleWorks}
onOpenPuzzleDetail={(profileId) => {
bigFishItems={bigFishWorks}
onOpenBigFishDetail={(item) => {
runProtectedAction(() => {
void openPuzzleDetail(profileId);
void openBigFishDraft(item);
});
}}
onExperienceBigFish={(item) => {
runProtectedAction(() => {
void startBigFishRunFromWork(item);
});
}}
puzzleItems={puzzleWorks}
onOpenPuzzleDetail={(item) => {
runProtectedAction(() => {
if (item.publicationStatus === 'draft') {
void openPuzzleDraft(item);
return;
}
void openPuzzleDetail(item.profileId);
});
}}
onExperiencePuzzle={(profileId) => {