抓大鹅B3实现
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
2026-04-30 21:29:36 +08:00
parent 08815d98bc
commit 2f76367108
16 changed files with 279 additions and 81 deletions

View File

@@ -2,8 +2,8 @@ import { useState } from 'react';
import type {
ExecuteMatch3DActionRequest,
Match3DAnchorItemResponse,
Match3DAgentSessionSnapshot,
Match3DAnchorItemResponse,
SendMatch3DMessageRequest,
} from '../../../packages/shared/src/contracts/match3dAgent';
import {

View File

@@ -60,10 +60,10 @@ export function Match3DDraftReadyView({
</div>
<div className="rounded-[1rem] border border-[var(--platform-subpanel-border)] bg-white/68 px-3 py-3">
<div className="text-[11px] font-bold tracking-[0.16em] text-[var(--platform-text-soft)]">
</div>
<div className="mt-1 text-sm font-semibold text-[var(--platform-text-strong)]">
{draft.clearCount}
{draft.totalItemCount ?? draft.clearCount * 3}
</div>
</div>
<div className="rounded-[1rem] border border-[var(--platform-subpanel-border)] bg-white/68 px-3 py-3">

View File

@@ -1264,9 +1264,13 @@ export function PlatformEntryFlowShellImpl({
const match3dSession = match3dFlow.session;
const match3dError = match3dFlow.error;
const setMatch3DSession = match3dFlow.setSession;
const setMatch3DError = match3dFlow.setError;
const isMatch3DBusy = match3dFlow.isBusy;
const streamingMatch3DReplyText = match3dFlow.streamingReplyText;
const setStreamingMatch3DReplyText = match3dFlow.setStreamingReplyText;
const isStreamingMatch3DReply = match3dFlow.isStreamingReply;
const setIsStreamingMatch3DReply = match3dFlow.setIsStreamingReply;
const puzzleSession = puzzleFlow.session;
const puzzleError = puzzleFlow.error;
@@ -1292,12 +1296,18 @@ export function PlatformEntryFlowShellImpl({
}, [bigFishFlow]);
const openMatch3DAgentWorkspace = useCallback(async () => {
match3dFlow.setSession(null);
match3dFlow.setError(null);
match3dFlow.setStreamingReplyText('');
match3dFlow.setIsStreamingReply(false);
setMatch3DSession(null);
setMatch3DError(null);
setStreamingMatch3DReplyText('');
setIsStreamingMatch3DReply(false);
await match3dFlow.openWorkspace();
}, [match3dFlow]);
}, [
match3dFlow,
setIsStreamingMatch3DReply,
setMatch3DError,
setMatch3DSession,
setStreamingMatch3DReplyText,
]);
const openPuzzleAgentWorkspace = useCallback(async () => {
setPuzzleRun(null);
@@ -1356,10 +1366,10 @@ export function PlatformEntryFlowShellImpl({
setBigFishRuntimeReturnStage('platform');
setBigFishGenerationState(null);
setBigFishError(null);
match3dFlow.setSession(null);
match3dFlow.setError(null);
match3dFlow.setStreamingReplyText('');
match3dFlow.setIsStreamingReply(false);
setMatch3DSession(null);
setMatch3DError(null);
setStreamingMatch3DReplyText('');
setIsStreamingMatch3DReply(false);
setPuzzleOperation(null);
setPuzzleWorks([]);
setSelectedPuzzleDetail(null);
@@ -1388,17 +1398,20 @@ export function PlatformEntryFlowShellImpl({
}
}, [
authUi?.user,
match3dFlow,
platformBootstrap.canReadProtectedData,
persistRpgAgentUiState,
resetAutoSaveTrackingToIdle,
resetRpgSessionViewState,
selectionStage,
setBigFishError,
setIsStreamingMatch3DReply,
setMatch3DError,
setMatch3DSession,
setPuzzleError,
setRpgCustomWorldError,
setRpgGeneratedCustomWorldProfile,
setSelectionStage,
setStreamingMatch3DReplyText,
]);
const handleCreationHubCreateType = useCallback(
@@ -1492,6 +1505,14 @@ export function PlatformEntryFlowShellImpl({
}
}, [bigFishRun, bigFishSession, selectionStage, setSelectionStage]);
useEffect(() => {
if (selectionStage === 'match3d-result' && !match3dSession?.draft) {
setSelectionStage(
match3dSession ? 'match3d-agent-workspace' : 'platform',
);
}
}, [match3dSession, selectionStage, setSelectionStage]);
const startBigFishRun = useCallback(() => {
if (!bigFishSession) {
return;
@@ -2897,11 +2918,13 @@ export function PlatformEntryFlowShellImpl({
: (platformBootstrap.platformError ??
sessionController.agentWorkspaceRestoreError ??
bigFishError ??
match3dError ??
puzzleError)
}
onRetry={() => {
platformBootstrap.setPlatformError(null);
setBigFishError(null);
setMatch3DError(null);
setPuzzleError(null);
void platformBootstrap.refreshCustomWorldWorks().catch((error) => {
platformBootstrap.setPlatformError(
@@ -2914,11 +2937,15 @@ export function PlatformEntryFlowShellImpl({
void refreshPuzzleShelf();
}}
createError={
sessionController.creationTypeError ?? bigFishError ?? puzzleError
sessionController.creationTypeError ??
bigFishError ??
match3dError ??
puzzleError
}
createBusy={
sessionController.isCreatingAgentSession ||
isBigFishBusy ||
isMatch3DBusy ||
isPuzzleBusy
}
onCreateType={handleCreationHubCreateType}
@@ -3078,7 +3105,12 @@ export function PlatformEntryFlowShellImpl({
<PlatformWorkDetailView
entry={selectedPublicWorkDetail}
authorAvatarUrl={selectedPublicWorkAuthor?.avatarUrl ?? null}
isBusy={isPublicWorkDetailBusy || isPuzzleBusy || isBigFishBusy}
isBusy={
isPublicWorkDetailBusy ||
isPuzzleBusy ||
isBigFishBusy ||
isMatch3DBusy
}
error={publicWorkDetailError}
onBack={() => {
setPublicWorkDetailError(null);

View File

@@ -2,9 +2,9 @@ import type {
CreateMatch3DSessionRequest,
ExecuteMatch3DActionRequest,
Match3DActionResponse,
Match3DAnchorItemResponse,
Match3DAgentMessageResponse,
Match3DAgentSessionSnapshot,
Match3DAnchorItemResponse,
Match3DCreatorConfig,
Match3DSessionResponse,
SendMatch3DMessageRequest,
@@ -24,7 +24,7 @@ let match3dSessionCounter = 0;
const mockSessions = new Map<string, Match3DAgentSessionSnapshot>();
function delay(ms = MOCK_RESPONSE_DELAY_MS) {
return new Promise<void>((resolve) => window.setTimeout(resolve, ms));
return new Promise<void>((resolve) => globalThis.setTimeout(resolve, ms));
}
function nowIso() {
@@ -189,7 +189,7 @@ function updateSessionConfig(
return {
...session,
progressPercent,
stage: progressPercent >= 100 ? 'ready_to_compile' : 'collecting',
stage: 'collecting_config',
anchorPack: buildAnchorPack(partialConfig),
config,
updatedAt: nowIso(),
@@ -237,7 +237,7 @@ export async function createMatch3DCreationSession(
sessionId,
currentTurn: 0,
progressPercent: 0,
stage: 'collecting',
stage: 'collecting_config',
anchorPack: buildAnchorPack(partialConfig),
config: null,
draft: null,
@@ -271,7 +271,7 @@ export async function streamMatch3DCreationMessage(
await delay(120);
const session = ensureMockSession(sessionId);
const text = payload.text.trim();
const currentConfig = session.config ?? {
const currentConfig: Partial<Match3DCreatorConfig> = session.config ?? {
themeText: session.anchorPack.theme.value,
clearCount: Number(session.anchorPack.clearCount.value) || undefined,
difficulty: Number(session.anchorPack.difficulty.value) || undefined,
@@ -337,7 +337,7 @@ export async function executeMatch3DCreationAction(
const nextSession = {
...session,
stage: 'draft_compiled',
stage: 'draft_ready',
progressPercent: 100,
config,
draft: buildDraft(config),