@@ -193,32 +193,120 @@ export function buildAgentDraftFoundationAnchorEntries(
|
||||
].filter((entry) => entry.value.trim());
|
||||
}
|
||||
|
||||
type AgentDraftFoundationStepDefinition = {
|
||||
id: string;
|
||||
label: string;
|
||||
detail: string;
|
||||
matchers: string[];
|
||||
minProgress: number;
|
||||
};
|
||||
|
||||
type AgentDraftFoundationFailedStep = {
|
||||
id: string;
|
||||
label: string;
|
||||
detail: string;
|
||||
};
|
||||
|
||||
// 这里按真实服务端 phaseLabel 归并步骤,避免把草稿生成硬折成 4 个失真的阶段。
|
||||
const AGENT_DRAFT_FOUNDATION_STEP_DEFINITIONS = [
|
||||
{
|
||||
id: 'queue',
|
||||
label: '接收生成请求',
|
||||
detail: '正在锁定当前已确认的世界锚点与草稿范围。',
|
||||
detail: '正在校验当前锚点并准备底稿编译链路。',
|
||||
matchers: ['已接收请求'],
|
||||
minProgress: 0,
|
||||
},
|
||||
{
|
||||
id: 'foundation',
|
||||
label: '生成世界底稿',
|
||||
detail: '正在根据世界核心、关系种子与冲突线编排第一版世界结构。',
|
||||
id: 'framework',
|
||||
label: '整理世界骨架',
|
||||
detail: '正在生成第一版世界框架、主题与核心冲突。',
|
||||
matchers: ['整理世界骨架', '生成世界底稿'],
|
||||
minProgress: 12,
|
||||
},
|
||||
{
|
||||
id: 'playable-outline',
|
||||
label: '生成可扮演角色',
|
||||
detail: '正在补出玩家视角角色的首轮名单与定位。',
|
||||
matchers: ['生成可扮演角色'],
|
||||
minProgress: 16,
|
||||
},
|
||||
{
|
||||
id: 'story-outline',
|
||||
label: '生成场景角色',
|
||||
detail: '正在整理关键 NPC、势力接口人与关系入口。',
|
||||
matchers: ['生成场景角色'],
|
||||
minProgress: 30,
|
||||
},
|
||||
{
|
||||
id: 'landmark-seed',
|
||||
label: '生成关键场景',
|
||||
detail: '正在补出第一批关键场景与地点骨架。',
|
||||
matchers: ['生成关键场景'],
|
||||
minProgress: 44,
|
||||
},
|
||||
{
|
||||
id: 'landmark-network',
|
||||
label: '建立场景连接',
|
||||
detail: '正在串联地点关系、线程挂钩与角色分布。',
|
||||
matchers: ['建立场景连接'],
|
||||
minProgress: 56,
|
||||
},
|
||||
{
|
||||
id: 'playable-detail',
|
||||
label: '补全可扮演角色细节',
|
||||
detail: '正在补全可扮演角色的叙事基础与档案细节。',
|
||||
matchers: ['补全可扮演角色'],
|
||||
minProgress: 66,
|
||||
},
|
||||
{
|
||||
id: 'story-detail',
|
||||
label: '补全场景角色细节',
|
||||
detail: '正在补全场景角色的叙事基础与档案细节。',
|
||||
matchers: ['补全场景角色'],
|
||||
minProgress: 84,
|
||||
},
|
||||
{
|
||||
id: 'finalize',
|
||||
label: '编译世界底稿',
|
||||
detail: '正在把分批生成结果汇总成第一版可浏览的世界底稿。',
|
||||
matchers: ['编译世界底稿'],
|
||||
minProgress: 97,
|
||||
},
|
||||
{
|
||||
id: 'role-visuals',
|
||||
label: '生成角色主形象',
|
||||
detail: '正在为关键角色补主形象预览资源。',
|
||||
matchers: ['生成角色主形象'],
|
||||
minProgress: 97,
|
||||
},
|
||||
{
|
||||
id: 'act-backgrounds',
|
||||
label: '生成幕背景图',
|
||||
detail: '正在为场景章节的每一幕补背景图预览资源。',
|
||||
matchers: ['生成幕背景图'],
|
||||
minProgress: 98,
|
||||
},
|
||||
{
|
||||
id: 'cards',
|
||||
label: '编译草稿卡',
|
||||
detail: '正在整理世界卡、角色卡与地点卡的摘要和详情。',
|
||||
detail: '正在整理世界卡、角色卡、地点卡与详情结构。',
|
||||
matchers: ['编译草稿卡'],
|
||||
minProgress: 99,
|
||||
},
|
||||
{
|
||||
id: 'workspace',
|
||||
label: '准备精修工作区',
|
||||
detail: '正在写回草稿数据,并切回可继续精修的工作区。',
|
||||
matchers: ['世界底稿已生成'],
|
||||
minProgress: 100,
|
||||
},
|
||||
] as const satisfies ReadonlyArray<{
|
||||
id: string;
|
||||
label: string;
|
||||
detail: string;
|
||||
}>;
|
||||
] as const satisfies ReadonlyArray<AgentDraftFoundationStepDefinition>;
|
||||
|
||||
const AGENT_DRAFT_FOUNDATION_FAILED_STEP = {
|
||||
id: 'failed',
|
||||
label: '生成失败',
|
||||
detail: '这一轮世界草稿没有编译完成,可以返回工作区补充设定后重试。',
|
||||
} as const satisfies AgentDraftFoundationFailedStep;
|
||||
|
||||
function clampProgress(progress: number | null | undefined) {
|
||||
if (typeof progress !== 'number' || Number.isNaN(progress)) {
|
||||
@@ -228,29 +316,68 @@ function clampProgress(progress: number | null | undefined) {
|
||||
return Math.max(0, Math.min(100, Math.round(progress)));
|
||||
}
|
||||
|
||||
function resolveAgentDraftFoundationStepIndexByProgress(progress: number) {
|
||||
let matchedIndex = 0;
|
||||
|
||||
for (
|
||||
let index = 0;
|
||||
index < AGENT_DRAFT_FOUNDATION_STEP_DEFINITIONS.length - 1;
|
||||
index += 1
|
||||
) {
|
||||
if (progress >= AGENT_DRAFT_FOUNDATION_STEP_DEFINITIONS[index].minProgress) {
|
||||
matchedIndex = index;
|
||||
}
|
||||
}
|
||||
|
||||
return matchedIndex;
|
||||
}
|
||||
|
||||
function resolveAgentDraftFoundationStepIndex(
|
||||
operation: CustomWorldAgentOperationRecord,
|
||||
) {
|
||||
const progress = clampProgress(operation.progress);
|
||||
const phaseLabel = operation.phaseLabel.trim();
|
||||
|
||||
if (
|
||||
operation.status === 'completed' ||
|
||||
phaseLabel.includes('世界底稿已生成') ||
|
||||
progress >= 90
|
||||
if (operation.status === 'completed' || phaseLabel.includes('世界底稿已生成')) {
|
||||
return AGENT_DRAFT_FOUNDATION_STEP_DEFINITIONS.length - 1;
|
||||
}
|
||||
|
||||
for (
|
||||
let index = AGENT_DRAFT_FOUNDATION_STEP_DEFINITIONS.length - 2;
|
||||
index >= 0;
|
||||
index -= 1
|
||||
) {
|
||||
return 3;
|
||||
const step = AGENT_DRAFT_FOUNDATION_STEP_DEFINITIONS[index];
|
||||
if (step.matchers.some((matcher) => phaseLabel.includes(matcher))) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
if (phaseLabel.includes('编译草稿卡') || progress >= 60) {
|
||||
return 2;
|
||||
return resolveAgentDraftFoundationStepIndexByProgress(progress);
|
||||
}
|
||||
|
||||
function resolveAgentDraftFoundationFailedStep(
|
||||
operation: CustomWorldAgentOperationRecord,
|
||||
) {
|
||||
if (operation.status !== 'failed') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (phaseLabel.includes('生成世界底稿') || progress >= 25) {
|
||||
return 1;
|
||||
}
|
||||
const phaseLabel = operation.phaseLabel.trim();
|
||||
const phaseDetail = operation.phaseDetail.trim();
|
||||
const error = operation.error?.trim() ?? '';
|
||||
|
||||
return 0;
|
||||
return {
|
||||
id: AGENT_DRAFT_FOUNDATION_FAILED_STEP.id,
|
||||
label:
|
||||
phaseLabel ||
|
||||
error ||
|
||||
AGENT_DRAFT_FOUNDATION_FAILED_STEP.label,
|
||||
detail:
|
||||
phaseDetail ||
|
||||
error ||
|
||||
AGENT_DRAFT_FOUNDATION_FAILED_STEP.detail,
|
||||
} satisfies AgentDraftFoundationFailedStep;
|
||||
}
|
||||
|
||||
function buildAgentDraftFoundationSteps(
|
||||
@@ -259,8 +386,12 @@ function buildAgentDraftFoundationSteps(
|
||||
) {
|
||||
return AGENT_DRAFT_FOUNDATION_STEP_DEFINITIONS.map((step, index) => {
|
||||
const isCompleted =
|
||||
operation.status === 'completed' || index < activeStepIndex;
|
||||
const isActive = !isCompleted && index === activeStepIndex;
|
||||
operation.status === 'completed' ||
|
||||
(operation.status === 'failed'
|
||||
? index < activeStepIndex
|
||||
: index < activeStepIndex);
|
||||
const isActive =
|
||||
operation.status !== 'failed' && !isCompleted && index === activeStepIndex;
|
||||
|
||||
return {
|
||||
id: step.id,
|
||||
@@ -326,7 +457,9 @@ export function buildAgentDraftFoundationGenerationProgress(
|
||||
nowMs,
|
||||
operation.status,
|
||||
);
|
||||
const failedStep = resolveAgentDraftFoundationFailedStep(operation);
|
||||
const activeStep =
|
||||
failedStep ??
|
||||
AGENT_DRAFT_FOUNDATION_STEP_DEFINITIONS[activeStepIndex] ??
|
||||
AGENT_DRAFT_FOUNDATION_STEP_DEFINITIONS[0];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user