1
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
2026-04-20 09:54:17 +08:00
parent 67c584b4df
commit 50759f3c1e
159 changed files with 16938 additions and 16925 deletions

View File

@@ -32,12 +32,13 @@ import { parseApiErrorMessage } from '../../packages/shared/src/http';
import type {
AIResponse,
Character,
CharacterChatTurn,
CustomWorldLandmark,
CustomWorldNpc,
CustomWorldPlayableNpc,
CharacterChatTurn,
CustomWorldProfile,
Encounter,
GameState,
SceneHostileNpc,
StoryMoment,
WorldType,
@@ -48,7 +49,7 @@ import type {
StoryGenerationContext,
StoryRequestOptions,
TextStreamOptions,
} from './ai';
} from './aiTypes';
import { fetchWithApiAuth, requestJson } from './apiClient';
import { type CharacterChatTargetStatus } from './characterChatPrompt';
import { parseLineListContent } from './llmParsers';
@@ -365,13 +366,18 @@ export async function generateCustomWorldProfile(
: {
settingText: input.settingText,
creatorIntent: input.creatorIntent ?? null,
generationMode: input.generationMode === 'fast' ? 'fast' as const : 'full' as const,
generationMode:
input.generationMode === 'fast'
? ('fast' as const)
: ('full' as const),
};
const session = await createCustomWorldSession({
settingText: normalizedInput.settingText,
creatorIntent:
normalizedInput.creatorIntent as Record<string, unknown> | null,
creatorIntent: normalizedInput.creatorIntent as Record<
string,
unknown
> | null,
generationMode: normalizedInput.generationMode,
});
@@ -380,7 +386,8 @@ export async function generateCustomWorldProfile(
typeof normalizedInput.creatorIntent?.worldHook === 'string' &&
normalizedInput.creatorIntent.worldHook.trim()
? normalizedInput.creatorIntent.worldHook.trim()
: normalizedInput.settingText.trim().slice(0, 120) || '这是一个围绕失衡秩序展开的世界。',
: normalizedInput.settingText.trim().slice(0, 120) ||
'这是一个围绕失衡秩序展开的世界。',
player_premise:
typeof normalizedInput.creatorIntent?.playerPremise === 'string' &&
normalizedInput.creatorIntent.playerPremise.trim()
@@ -395,9 +402,9 @@ export async function generateCustomWorldProfile(
Array.isArray(normalizedInput.creatorIntent?.coreConflicts) &&
normalizedInput.creatorIntent.coreConflicts.length > 0
? normalizedInput.creatorIntent.coreConflicts
.map((item) => (typeof item === 'string' ? item.trim() : ''))
.filter(Boolean)
.join('')
.map((item) => (typeof item === 'string' ? item.trim() : ''))
.filter(Boolean)
.join('')
: '旧秩序与新威胁正在同时逼近,各方都在争夺主动权。',
};
@@ -406,7 +413,8 @@ export async function generateCustomWorldProfile(
continue;
}
const answer = fallbackAnswerMap[question.id] || normalizedInput.settingText.trim();
const answer =
fallbackAnswerMap[question.id] || normalizedInput.settingText.trim();
await answerCustomWorldSessionQuestion(session.sessionId, {
questionId: question.id,
answer,
@@ -475,20 +483,30 @@ export async function streamCustomWorldSessionGeneration(
const payload = JSON.parse(payloadText) as Record<string, unknown>;
if (eventName === 'progress') {
if (
typeof payload.phaseId === 'string'
&& typeof payload.phaseLabel === 'string'
&& typeof payload.phaseDetail === 'string'
&& typeof payload.overallProgress === 'number'
&& Array.isArray(payload.steps)
typeof payload.phaseId === 'string' &&
typeof payload.phaseLabel === 'string' &&
typeof payload.phaseDetail === 'string' &&
typeof payload.overallProgress === 'number' &&
Array.isArray(payload.steps)
) {
options.onProgress?.(payload as unknown as CustomWorldGenerationProgress);
options.onProgress?.(
payload as unknown as CustomWorldGenerationProgress,
);
} else {
options.onProgress?.({
phaseId: 'finalize',
phaseLabel: typeof payload.phase === 'string' ? payload.phase : 'generating',
phaseDetail: typeof payload.phase === 'string' ? payload.phase : 'generating',
phaseLabel:
typeof payload.phase === 'string'
? payload.phase
: 'generating',
phaseDetail:
typeof payload.phase === 'string'
? payload.phase
: 'generating',
overallProgress:
typeof payload.progress === 'number' ? payload.progress / 100 : 0,
typeof payload.progress === 'number'
? payload.progress / 100
: 0,
completedWeight:
typeof payload.progress === 'number' ? payload.progress : 0,
totalWeight: 100,
@@ -499,7 +517,11 @@ export async function streamCustomWorldSessionGeneration(
});
}
}
if (eventName === 'result' && payload.profile && typeof payload.profile === 'object') {
if (
eventName === 'result' &&
payload.profile &&
typeof payload.profile === 'object'
) {
latestProfile = payload.profile as Record<string, unknown>;
}
if (eventName === 'error') {
@@ -521,10 +543,17 @@ export async function streamCustomWorldSessionGeneration(
}
export async function generateCustomWorldSceneImage(
...args: [CustomWorldSceneImageRequest]
payload: CustomWorldSceneImageRequest,
) {
const aiClient = await loadLegacyAiModule();
return aiClient.generateCustomWorldSceneImage(...args);
return requestJson<CustomWorldSceneImageResult>(
`${CUSTOM_WORLD_API_BASE}/custom-world/scene-image`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
},
'生成自定义世界场景图失败',
);
}
export async function generateCustomWorldSceneNpc(payload: {
@@ -779,10 +808,12 @@ export async function getCustomWorldAgentOperation(
sessionId: string,
operationId: string,
): Promise<CustomWorldAgentOperationRecord> {
const response = await requestJson<{
operation?: CustomWorldAgentOperationRecord;
data?: CustomWorldAgentOperationRecord;
} & Partial<CustomWorldAgentOperationRecord>>(
const response = await requestJson<
{
operation?: CustomWorldAgentOperationRecord;
data?: CustomWorldAgentOperationRecord;
} & Partial<CustomWorldAgentOperationRecord>
>(
`${RUNTIME_API_BASE}/custom-world/agent/sessions/${encodeURIComponent(sessionId)}/operations/${encodeURIComponent(operationId)}`,
{
method: 'GET',
@@ -790,7 +821,9 @@ export async function getCustomWorldAgentOperation(
'读取共创操作状态失败',
);
return (response.operation ?? response.data ?? response) as CustomWorldAgentOperationRecord;
return (response.operation ??
response.data ??
response) as CustomWorldAgentOperationRecord;
}
export async function getCustomWorldAgentCardDetail(
@@ -827,7 +860,9 @@ export async function answerCustomWorldSessionQuestion(
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload satisfies AnswerCustomWorldSessionQuestionRequest),
body: JSON.stringify(
payload satisfies AnswerCustomWorldSessionQuestionRequest,
),
},
'提交自定义世界补充设定失败',
);
@@ -938,6 +973,10 @@ export async function streamNpcChatTurn(
npcState: Record<string, unknown>,
options: {
onReplyUpdate?: (text: string) => void;
questOfferContext?: {
state: GameState;
turnCount: number;
} | null;
} = {},
) {
const payload = {
@@ -952,13 +991,23 @@ export async function streamNpcChatTurn(
dialogue: conversationHistory ?? [],
playerMessage,
npcState,
questOfferContext: options.questOfferContext
? {
state: options.questOfferContext.state,
encounter,
turnCount: options.questOfferContext.turnCount,
}
: null,
} satisfies NpcChatTurnRequest;
const response = await fetchWithApiAuth(`${RUNTIME_API_BASE}/chat/npc/turn/stream`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
});
const response = await fetchWithApiAuth(
`${RUNTIME_API_BASE}/chat/npc/turn/stream`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
},
);
if (!response.ok) {
const responseText = await response.text();
@@ -998,7 +1047,10 @@ export async function streamNpcChatTurn(
}
if (parsedEvent.event === 'reply_delta') {
const payloadRecord = JSON.parse(parsedEvent.data) as Record<string, unknown>;
const payloadRecord = JSON.parse(parsedEvent.data) as Record<
string,
unknown
>;
const nextText =
typeof payloadRecord.text === 'string' ? payloadRecord.text : '';
accumulatedReply = nextText;
@@ -1014,7 +1066,10 @@ export async function streamNpcChatTurn(
}
if (parsedEvent.event === 'error') {
const payloadRecord = JSON.parse(parsedEvent.data) as Record<string, unknown>;
const payloadRecord = JSON.parse(parsedEvent.data) as Record<
string,
unknown
>;
throw new Error(
typeof payloadRecord.message === 'string'
? payloadRecord.message