Auto-open draft result after foundation completes

This commit is contained in:
2026-04-25 10:52:39 +08:00
parent 35c2bce6f1
commit 03acbc5cb1
31 changed files with 36472 additions and 232 deletions

View File

@@ -28,7 +28,6 @@ import {
buildCustomWorldRoleBatchPrompt,
buildCustomWorldRoleOutlineBatchJsonRepairPrompt,
buildCustomWorldRoleOutlineBatchPrompt,
buildCustomWorldSceneImagePrompt,
buildCustomWorldStoryGraphJsonRepairPrompt,
buildCustomWorldStoryGraphPrompt,
buildCustomWorldThemePackJsonRepairPrompt,
@@ -1951,11 +1950,7 @@ export async function generateCustomWorldSceneImage({
size = '1280*720',
referenceImageSrc,
}: CustomWorldSceneImageRequest): Promise<CustomWorldSceneImageResult> {
const resolvedPrompt =
prompt?.trim() ||
buildCustomWorldSceneImagePrompt(profile, landmark, userPrompt, {
hasReferenceImage: Boolean(referenceImageSrc?.trim()),
});
const resolvedPrompt = prompt?.trim() || userPrompt?.trim() || '';
const resolvedNegativePrompt =
negativePrompt?.trim() || DEFAULT_CUSTOM_WORLD_SCENE_IMAGE_NEGATIVE_PROMPT;
const controller = new AbortController();
@@ -1975,9 +1970,25 @@ export async function generateCustomWorldSceneImage({
worldName: profile.name,
landmarkId: landmark.id,
landmarkName: landmark.name,
prompt: resolvedPrompt,
...(prompt?.trim() ? { prompt: prompt.trim() } : {}),
userPrompt: resolvedPrompt,
negativePrompt: resolvedNegativePrompt,
size,
profile: {
id: profile.id,
name: profile.name,
subtitle: profile.subtitle,
summary: profile.summary,
tone: profile.tone,
playerGoal: profile.playerGoal,
settingText: profile.settingText,
},
landmark: {
id: landmark.id,
name: landmark.name,
description: landmark.description,
dangerLevel: landmark.dangerLevel,
},
...(referenceImageSrc?.trim()
? { referenceImageSrc: referenceImageSrc.trim() }
: {}),

View File

@@ -45,6 +45,7 @@ test('custom world agent ui state reads from query first and persists to session
{
activeSessionId: 'session-1',
activeOperationId: 'operation-1',
customWorldGenerationSource: 'agent-draft-foundation',
ownerUserId: 'user-1',
},
env,
@@ -52,15 +53,20 @@ test('custom world agent ui state reads from query first and persists to session
expect(currentUrl).toContain('customWorldSessionId=session-1');
expect(currentUrl).toContain('customWorldOperationId=operation-1');
expect(currentUrl).toContain(
'customWorldGenerationSource=agent-draft-foundation',
);
expect(readCustomWorldAgentUiState(env)).toEqual({
activeSessionId: 'session-1',
activeOperationId: 'operation-1',
customWorldGenerationSource: 'agent-draft-foundation',
});
currentUrl = '/play';
expect(readCustomWorldAgentUiState(env)).toEqual({
activeSessionId: 'session-1',
activeOperationId: 'operation-1',
customWorldGenerationSource: 'agent-draft-foundation',
ownerUserId: 'user-1',
});

View File

@@ -2,6 +2,8 @@ import type { CustomWorldAgentUiState } from '../types';
export const CUSTOM_WORLD_AGENT_SESSION_QUERY_KEY = 'customWorldSessionId';
export const CUSTOM_WORLD_AGENT_OPERATION_QUERY_KEY = 'customWorldOperationId';
export const CUSTOM_WORLD_GENERATION_SOURCE_QUERY_KEY =
'customWorldGenerationSource';
export const CUSTOM_WORLD_AGENT_UI_STATE_STORAGE_KEY =
'genarrative.custom-world-agent-ui.v1';
@@ -50,6 +52,10 @@ function normalizeValue(value: unknown) {
return typeof value === 'string' && value.trim() ? value.trim() : null;
}
function normalizeGenerationSource(value: unknown) {
return value === 'agent-draft-foundation' ? value : null;
}
export function readCustomWorldAgentUiState(
env?: CustomWorldAgentUiEnvironment,
): CustomWorldAgentUiState {
@@ -62,9 +68,16 @@ export function readCustomWorldAgentUiState(
activeOperationId: normalizeValue(
params.get(CUSTOM_WORLD_AGENT_OPERATION_QUERY_KEY),
),
customWorldGenerationSource: normalizeGenerationSource(
params.get(CUSTOM_WORLD_GENERATION_SOURCE_QUERY_KEY),
),
};
if (stateFromQuery.activeSessionId || stateFromQuery.activeOperationId) {
if (
stateFromQuery.activeSessionId ||
stateFromQuery.activeOperationId ||
stateFromQuery.customWorldGenerationSource
) {
return stateFromQuery;
}
@@ -80,6 +93,9 @@ export function readCustomWorldAgentUiState(
return {
activeSessionId: normalizeValue(parsed.activeSessionId),
activeOperationId: normalizeValue(parsed.activeOperationId),
customWorldGenerationSource: normalizeGenerationSource(
parsed.customWorldGenerationSource,
),
ownerUserId: normalizeValue(parsed.ownerUserId),
};
} catch {
@@ -95,10 +111,14 @@ export function writeCustomWorldAgentUiState(
const resolved = resolveEnvironment(env);
const activeSessionId = normalizeValue(state.activeSessionId);
const activeOperationId = normalizeValue(state.activeOperationId);
const customWorldGenerationSource = normalizeGenerationSource(
state.customWorldGenerationSource,
);
const ownerUserId = normalizeValue(state.ownerUserId);
const nextState: CustomWorldAgentUiState = {
activeSessionId,
activeOperationId,
customWorldGenerationSource,
ownerUserId,
};
@@ -116,6 +136,15 @@ export function writeCustomWorldAgentUiState(
params.delete(CUSTOM_WORLD_AGENT_OPERATION_QUERY_KEY);
}
if (customWorldGenerationSource) {
params.set(
CUSTOM_WORLD_GENERATION_SOURCE_QUERY_KEY,
customWorldGenerationSource,
);
} else {
params.delete(CUSTOM_WORLD_GENERATION_SOURCE_QUERY_KEY);
}
const search = params.toString();
const nextUrl = search
? `${resolved.location.pathname}?${search}`
@@ -124,7 +153,7 @@ export function writeCustomWorldAgentUiState(
}
if (resolved.sessionStorage) {
if (activeSessionId || activeOperationId) {
if (activeSessionId || activeOperationId || customWorldGenerationSource) {
resolved.sessionStorage.setItem(
CUSTOM_WORLD_AGENT_UI_STATE_STORAGE_KEY,
JSON.stringify(nextState),