1
This commit is contained in:
@@ -4,9 +4,9 @@ import type {
|
||||
CustomWorldAgentOperationRecord,
|
||||
CustomWorldAgentSessionSnapshot,
|
||||
} from '../../../packages/shared/src/contracts/customWorldAgent';
|
||||
import type {
|
||||
CustomWorldLibraryEntry,
|
||||
} from '../../../packages/shared/src/contracts/runtime';
|
||||
import type { RpgCreationResultView } from '../../../packages/shared/src/contracts/rpgCreationResultView';
|
||||
import type { CustomWorldLibraryEntry } from '../../../packages/shared/src/contracts/runtime';
|
||||
import { normalizeCustomWorldProfileRecord } from '../../data/customWorldLibrary';
|
||||
import {
|
||||
executeRpgCreationAction,
|
||||
getRpgCreationOperation,
|
||||
@@ -14,7 +14,6 @@ import {
|
||||
} from '../../services/rpg-creation';
|
||||
import type { CustomWorldProfile } from '../../types';
|
||||
import {
|
||||
normalizeAgentBackedProfile,
|
||||
resolveRpgCreationErrorMessage,
|
||||
stringifyAgentBackedProfile,
|
||||
} from './rpgEntryShared';
|
||||
@@ -27,7 +26,6 @@ import type {
|
||||
type UseRpgCreationResultAutosaveParams = {
|
||||
selectionStage: SelectionStage;
|
||||
activeAgentSessionId: string | null;
|
||||
agentSession: CustomWorldAgentSessionSnapshot | null;
|
||||
generatedCustomWorldProfile: CustomWorldProfile | null;
|
||||
isAgentDraftResultView: boolean;
|
||||
userId: string | null | undefined;
|
||||
@@ -55,8 +53,11 @@ type UseRpgCreationResultAutosaveParams = {
|
||||
syncAgentSessionSnapshot: (
|
||||
sessionId: string,
|
||||
) => Promise<CustomWorldAgentSessionSnapshot | null>;
|
||||
syncAgentCreationResultView: (
|
||||
sessionId: string,
|
||||
) => Promise<RpgCreationResultView | null>;
|
||||
buildDraftResultProfile: (
|
||||
session: CustomWorldAgentSessionSnapshot | null,
|
||||
view: RpgCreationResultView | null,
|
||||
) => CustomWorldProfile | null;
|
||||
};
|
||||
|
||||
@@ -70,7 +71,6 @@ export function useRpgCreationResultAutosave(
|
||||
const {
|
||||
selectionStage,
|
||||
activeAgentSessionId,
|
||||
agentSession,
|
||||
generatedCustomWorldProfile,
|
||||
isAgentDraftResultView,
|
||||
userId,
|
||||
@@ -81,6 +81,7 @@ export function useRpgCreationResultAutosave(
|
||||
refreshCustomWorldWorks,
|
||||
persistAgentUiState,
|
||||
syncAgentSessionSnapshot,
|
||||
syncAgentCreationResultView,
|
||||
buildDraftResultProfile,
|
||||
} = params;
|
||||
|
||||
@@ -118,29 +119,33 @@ export function useRpgCreationResultAutosave(
|
||||
return null;
|
||||
}
|
||||
|
||||
const normalizedProfile = normalizeAgentBackedProfile(profile);
|
||||
const profileSignature = stringifyAgentBackedProfile(normalizedProfile);
|
||||
const requestId = latestAutoSaveRequestIdRef.current + 1;
|
||||
latestAutoSaveRequestIdRef.current = requestId;
|
||||
setCustomWorldAutoSaveState('saving');
|
||||
setCustomWorldAutoSaveError(null);
|
||||
|
||||
try {
|
||||
const mutation =
|
||||
await upsertRpgWorldProfile(
|
||||
normalizedProfile,
|
||||
{
|
||||
sourceAgentSessionId:
|
||||
isAgentDraftResultView && activeAgentSessionId
|
||||
? activeAgentSessionId
|
||||
: null,
|
||||
},
|
||||
);
|
||||
const mutation = await upsertRpgWorldProfile(profile, {
|
||||
sourceAgentSessionId:
|
||||
isAgentDraftResultView && activeAgentSessionId
|
||||
? activeAgentSessionId
|
||||
: null,
|
||||
});
|
||||
if (latestAutoSaveRequestIdRef.current !== requestId) {
|
||||
return mutation;
|
||||
}
|
||||
|
||||
lastAutoSavedProfileSignatureRef.current = profileSignature;
|
||||
const canonicalProfile =
|
||||
normalizeCustomWorldProfileRecord(mutation.entry.profile) ??
|
||||
mutation.entry.profile;
|
||||
// Agent 结果页的界面真相来自 result-view;作品库响应只用于列表与签名回写,
|
||||
// 避免旧兼容响应缺字段时覆盖当前完整编辑态。
|
||||
lastAutoSavedProfileSignatureRef.current = stringifyAgentBackedProfile(
|
||||
isAgentDraftResultView ? profile : canonicalProfile,
|
||||
);
|
||||
if (!isAgentDraftResultView) {
|
||||
setGeneratedCustomWorldProfile(canonicalProfile);
|
||||
}
|
||||
setSavedCustomWorldEntries(mutation.entries);
|
||||
if (userId) {
|
||||
void refreshCustomWorldWorks().catch(() => {});
|
||||
@@ -174,73 +179,8 @@ export function useRpgCreationResultAutosave(
|
||||
refreshCustomWorldWorks,
|
||||
setSavedCustomWorldEntries,
|
||||
setSelectedDetailEntry,
|
||||
userId,
|
||||
],
|
||||
);
|
||||
|
||||
const syncAgentDraftResultProfile = useCallback(
|
||||
async (profile: CustomWorldProfile) => {
|
||||
if (!activeAgentSessionId) {
|
||||
return {
|
||||
session: null,
|
||||
profile: null,
|
||||
} satisfies SyncedAgentDraftResult;
|
||||
}
|
||||
|
||||
const normalizedProfile = normalizeAgentBackedProfile(profile);
|
||||
const profileSignature = stringifyAgentBackedProfile(normalizedProfile);
|
||||
const latestSessionProfile = buildDraftResultProfile(agentSession);
|
||||
const latestSessionProfileSignature = latestSessionProfile
|
||||
? stringifyAgentBackedProfile(latestSessionProfile)
|
||||
: '';
|
||||
const shouldRefreshPublishGate = Boolean(
|
||||
agentSession?.resultPreview && !agentSession.resultPreview.publishReady,
|
||||
);
|
||||
|
||||
if (
|
||||
latestSessionProfileSignature === profileSignature &&
|
||||
!shouldRefreshPublishGate
|
||||
) {
|
||||
latestAgentResultSyncSignatureRef.current = profileSignature;
|
||||
return {
|
||||
session: agentSession,
|
||||
profile: normalizeAgentBackedProfile(latestSessionProfile ?? profile),
|
||||
} satisfies SyncedAgentDraftResult;
|
||||
}
|
||||
|
||||
if (
|
||||
latestAgentResultSyncSignatureRef.current === profileSignature &&
|
||||
!shouldRefreshPublishGate
|
||||
) {
|
||||
return {
|
||||
session: agentSession,
|
||||
profile: normalizeAgentBackedProfile(latestSessionProfile ?? profile),
|
||||
} satisfies SyncedAgentDraftResult;
|
||||
}
|
||||
|
||||
// Agent 结果页不再把前端 profile 回写到 session。
|
||||
// 这里只刷新后端结果页快照,避免在采集/生成早期误触 sync_result_profile。
|
||||
const latestSession = await syncAgentSessionSnapshot(activeAgentSessionId);
|
||||
const latestProfile = normalizeAgentBackedProfile(
|
||||
buildDraftResultProfile(latestSession) ?? profile,
|
||||
);
|
||||
if (latestProfile) {
|
||||
setGeneratedCustomWorldProfile(latestProfile);
|
||||
}
|
||||
latestAgentResultSyncSignatureRef.current =
|
||||
stringifyAgentBackedProfile(latestProfile);
|
||||
|
||||
return {
|
||||
session: latestSession,
|
||||
profile: latestProfile,
|
||||
} satisfies SyncedAgentDraftResult;
|
||||
},
|
||||
[
|
||||
activeAgentSessionId,
|
||||
agentSession,
|
||||
buildDraftResultProfile,
|
||||
setGeneratedCustomWorldProfile,
|
||||
syncAgentSessionSnapshot,
|
||||
userId,
|
||||
],
|
||||
);
|
||||
|
||||
@@ -290,6 +230,65 @@ export function useRpgCreationResultAutosave(
|
||||
],
|
||||
);
|
||||
|
||||
const syncAgentDraftResultProfile = useCallback(
|
||||
async (profile: CustomWorldProfile) => {
|
||||
if (!activeAgentSessionId) {
|
||||
return {
|
||||
session: null,
|
||||
profile: null,
|
||||
} satisfies SyncedAgentDraftResult;
|
||||
}
|
||||
|
||||
const profileSignature = stringifyAgentBackedProfile(profile);
|
||||
const currentView =
|
||||
await syncAgentCreationResultView(activeAgentSessionId);
|
||||
if (!currentView?.canSyncResultProfile) {
|
||||
const latestProfile = buildDraftResultProfile(currentView) ?? profile;
|
||||
if (latestProfile) {
|
||||
setGeneratedCustomWorldProfile(latestProfile);
|
||||
}
|
||||
latestAgentResultSyncSignatureRef.current =
|
||||
stringifyAgentBackedProfile(latestProfile);
|
||||
|
||||
return {
|
||||
session: currentView?.session ?? null,
|
||||
profile: latestProfile,
|
||||
view: currentView,
|
||||
} satisfies SyncedAgentDraftResult;
|
||||
}
|
||||
|
||||
if (latestAgentResultSyncSignatureRef.current !== profileSignature) {
|
||||
await executeAgentActionAndWait({
|
||||
action: 'sync_result_profile',
|
||||
profile: profile as unknown as Record<string, unknown>,
|
||||
});
|
||||
latestAgentResultSyncSignatureRef.current = profileSignature;
|
||||
}
|
||||
|
||||
const latestView =
|
||||
await syncAgentCreationResultView(activeAgentSessionId);
|
||||
const latestProfile = buildDraftResultProfile(latestView) ?? profile;
|
||||
if (latestProfile) {
|
||||
setGeneratedCustomWorldProfile(latestProfile);
|
||||
}
|
||||
latestAgentResultSyncSignatureRef.current =
|
||||
stringifyAgentBackedProfile(latestProfile);
|
||||
|
||||
return {
|
||||
session: latestView?.session ?? null,
|
||||
profile: latestProfile,
|
||||
view: latestView,
|
||||
} satisfies SyncedAgentDraftResult;
|
||||
},
|
||||
[
|
||||
activeAgentSessionId,
|
||||
buildDraftResultProfile,
|
||||
executeAgentActionAndWait,
|
||||
setGeneratedCustomWorldProfile,
|
||||
syncAgentCreationResultView,
|
||||
],
|
||||
);
|
||||
|
||||
useEffect(
|
||||
() => () => {
|
||||
if (customWorldAutoSaveTimeoutRef.current !== null) {
|
||||
@@ -313,7 +312,9 @@ export function useRpgCreationResultAutosave(
|
||||
return;
|
||||
}
|
||||
|
||||
const nextSignature = stringifyAgentBackedProfile(generatedCustomWorldProfile);
|
||||
const nextSignature = stringifyAgentBackedProfile(
|
||||
generatedCustomWorldProfile,
|
||||
);
|
||||
if (nextSignature === lastAutoSavedProfileSignatureRef.current) {
|
||||
return;
|
||||
}
|
||||
@@ -328,14 +329,16 @@ export function useRpgCreationResultAutosave(
|
||||
void (async () => {
|
||||
isCustomWorldAutoSaveBusyRef.current = true;
|
||||
try {
|
||||
let latestProfileToSave = normalizeAgentBackedProfile(profileToSave);
|
||||
let latestProfileToSave = profileToSave;
|
||||
if (isAgentDraftResultView) {
|
||||
const syncedResult =
|
||||
await syncAgentDraftResultProfile(profileToSave);
|
||||
if (syncedResult.view && !syncedResult.view.canAutosaveLibrary) {
|
||||
setCustomWorldAutoSaveState('idle');
|
||||
return;
|
||||
}
|
||||
// 作品库自动保存优先落同步后 session 重编译出的结果,避免继续保存旧的前端内存态。
|
||||
latestProfileToSave = normalizeAgentBackedProfile(
|
||||
syncedResult.profile ?? profileToSave,
|
||||
);
|
||||
latestProfileToSave = syncedResult.profile ?? profileToSave;
|
||||
}
|
||||
await saveGeneratedCustomWorld(latestProfileToSave);
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user