Files
Genarrative/src/components/rpg-entry/rpgEntryShared.ts
2026-05-08 11:44:42 +08:00

122 lines
4.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type {
CustomWorldAgentMessage,
CustomWorldAgentOperationRecord,
CustomWorldWorkSummary,
} from '../../../packages/shared/src/contracts/customWorldAgent';
import type { CustomWorldLibraryEntry } from '../../../packages/shared/src/contracts/runtime';
import { ApiClientError, isTimeoutError } from '../../services/apiClient';
import type { CustomWorldProfile } from '../../types';
export function resolveRpgEntryErrorMessage(error: unknown, fallback: string) {
if (isTimeoutError(error)) {
if (//u.test(fallback)) {
return '开启智能创作工作区超时,请确认运行时后端已启动后重试。';
}
if (//u.test(fallback)) {
return '开启拼图创作工作台超时,请确认运行时后端已启动后重试。';
}
if (//u.test(fallback)) {
return '开启大鱼吃小鱼创作工作台超时,请确认运行时后端已启动后重试。';
}
if (//u.test(fallback)) {
return '开启创作工作台超时,请确认运行时后端已启动后重试。';
}
return '请求超时,请稍后重试。';
}
if (
error instanceof ApiClientError &&
error.status === 401 &&
(error.code === 'UNAUTHORIZED' ||
error.message.includes('Authorization Bearer Token'))
) {
return '当前登录状态已失效,请重新登录后继续。';
}
return error instanceof Error ? error.message : fallback;
}
export function createFailedRpgEntryAgentOperation(params: {
type: CustomWorldAgentOperationRecord['type'];
phaseLabel: string;
error: string;
}): CustomWorldAgentOperationRecord {
return {
operationId: `local-failed-${Date.now()}`,
type: params.type,
status: 'failed',
phaseLabel: params.phaseLabel,
phaseDetail: params.error,
progress: 0,
error: params.error,
startedAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
};
}
export function buildOptimisticRpgEntryAgentMessage(
payload: Pick<CustomWorldAgentMessage, 'id' | 'role' | 'kind' | 'text'>,
): CustomWorldAgentMessage {
return {
...payload,
createdAt: new Date().toISOString(),
relatedOperationId: null,
};
}
export function normalizeRpgEntryAgentBackedProfile(
profile: CustomWorldProfile,
) {
// 中文注释:保存前 canonicalize 已迁到 server-rs
// 这里保留透传函数只为了兼容旧导入,不再改写正式 profile 字段。
return profile;
}
export function stringifyRpgEntryAgentBackedProfile(
profile: CustomWorldProfile,
) {
return JSON.stringify(profile);
}
export function buildRpgEntryCreationHubFallbackItems(
entries: CustomWorldLibraryEntry<CustomWorldProfile>[],
): CustomWorldWorkSummary[] {
return entries
.filter((entry) => entry.visibility === 'published')
.map((entry) => ({
workId: `fallback:${entry.profileId}`,
sourceType: 'published_profile',
status: 'published',
title: entry.worldName,
subtitle: entry.subtitle || '已发布作品',
summary: entry.summaryText || '继续补完这个世界的设定与游玩入口。',
coverImageSrc: entry.coverImageSrc,
coverRenderMode: 'image',
coverCharacterImageSrcs: [],
updatedAt: entry.updatedAt,
publishedAt: entry.publishedAt,
stage: null,
stageLabel: '已发布',
playableNpcCount: entry.playableNpcCount,
landmarkCount: entry.landmarkCount,
roleVisualReadyCount: 0,
roleAnimationReadyCount: 0,
roleAssetSummaryLabel: null,
sessionId: null,
profileId: entry.profileId,
canResume: false,
canEnterWorld: true,
}));
}
/**
* 兼容创作链工作包已经接入的旧 helper 命名,避免本轮迁移波及其他并行改动。
*/
export const resolveRpgCreationErrorMessage = resolveRpgEntryErrorMessage;
export const createFailedAgentOperation = createFailedRpgEntryAgentOperation;
export const buildOptimisticAgentMessage = buildOptimisticRpgEntryAgentMessage;
export const normalizeAgentBackedProfile = normalizeRpgEntryAgentBackedProfile;
export const stringifyAgentBackedProfile = stringifyRpgEntryAgentBackedProfile;
export const buildCreationHubFallbackItems =
buildRpgEntryCreationHubFallbackItems;