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

This commit is contained in:
2026-04-20 21:06:48 +08:00
parent 1c72066bab
commit 75944b1f1f
102 changed files with 9648 additions and 1540 deletions

View File

@@ -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];