219 lines
6.1 KiB
TypeScript
219 lines
6.1 KiB
TypeScript
import type {
|
|
CustomWorldAgentActionRequest,
|
|
CustomWorldAgentOperationRecord,
|
|
CustomWorldAgentSessionSnapshot,
|
|
SendCustomWorldAgentMessageRequest,
|
|
} from '../../../packages/shared/src/contracts/customWorldAgent';
|
|
import {
|
|
buildCreationAgentChatMessage,
|
|
createCreationAgentChatQuickActions,
|
|
createCreationAgentClientMessageId,
|
|
isCreationAgentOperationBusy,
|
|
resolveCreationAgentQuickActionMessage,
|
|
} from '../../services/creation-agent';
|
|
import {
|
|
type CreationAgentAnchorView,
|
|
type CreationAgentOperationView,
|
|
type CreationAgentSessionView,
|
|
type CreationAgentTheme,
|
|
CreationAgentWorkspace,
|
|
} from '../creation-agent';
|
|
|
|
type CustomWorldAgentWorkspaceProps = {
|
|
session: CustomWorldAgentSessionSnapshot | null;
|
|
activeOperation: CustomWorldAgentOperationRecord | null;
|
|
streamingReplyText?: string;
|
|
isStreamingReply?: boolean;
|
|
onBack: () => void;
|
|
onSubmitMessage: (payload: SendCustomWorldAgentMessageRequest) => void;
|
|
onExecuteAction: (payload: CustomWorldAgentActionRequest) => void;
|
|
};
|
|
|
|
const CUSTOM_WORLD_AGENT_THEME: CreationAgentTheme = {
|
|
accentTextClass: 'text-emerald-100/86',
|
|
accentBgClass: 'bg-emerald-300',
|
|
accentButtonClass: 'bg-emerald-200 shadow-emerald-950/20',
|
|
userBubbleClass:
|
|
'border border-[var(--platform-cool-border)] bg-[var(--platform-cool-bg)] text-[var(--platform-text-strong)]',
|
|
heroClass:
|
|
'border border-emerald-100/18 bg-[radial-gradient(circle_at_top_left,rgba(52,211,153,0.2),transparent_32%),linear-gradient(135deg,rgba(6,78,59,0.95),rgba(24,33,39,0.96))]',
|
|
anchorGridClass: 'grid gap-2 sm:grid-cols-2 xl:grid-cols-4',
|
|
};
|
|
|
|
function stringifyAnchorValue(value: unknown): string {
|
|
if (!value) {
|
|
return '';
|
|
}
|
|
|
|
if (typeof value === 'string') {
|
|
return value;
|
|
}
|
|
|
|
if (Array.isArray(value)) {
|
|
return value
|
|
.map((item): string => stringifyAnchorValue(item))
|
|
.filter((item): item is string => Boolean(item))
|
|
.join(' / ');
|
|
}
|
|
|
|
if (typeof value !== 'object') {
|
|
return String(value);
|
|
}
|
|
|
|
return Object.values(value as Record<string, unknown>)
|
|
.map((item): string => stringifyAnchorValue(item))
|
|
.filter((item): item is string => Boolean(item))
|
|
.join(' / ');
|
|
}
|
|
|
|
function buildCustomWorldAnchor(
|
|
key: string,
|
|
label: string,
|
|
value: unknown,
|
|
): CreationAgentAnchorView {
|
|
const text = stringifyAnchorValue(value);
|
|
|
|
return {
|
|
key,
|
|
label,
|
|
value: text,
|
|
status: text ? 'confirmed' : 'missing',
|
|
};
|
|
}
|
|
|
|
function mapCustomWorldSession(
|
|
session: CustomWorldAgentSessionSnapshot,
|
|
): CreationAgentSessionView {
|
|
return {
|
|
sessionId: session.sessionId,
|
|
// 自定义世界 Agent 聊天页顶部只保留操作与进度,不展示标题和引导副文案。
|
|
title: null,
|
|
assistantSummary: null,
|
|
currentTurn: session.currentTurn,
|
|
progressPercent: session.progressPercent,
|
|
anchors: [
|
|
buildCustomWorldAnchor(
|
|
'worldPromise',
|
|
'世界承诺',
|
|
session.anchorContent.worldPromise,
|
|
),
|
|
buildCustomWorldAnchor(
|
|
'playerFantasy',
|
|
'玩家幻想',
|
|
session.anchorContent.playerFantasy,
|
|
),
|
|
buildCustomWorldAnchor(
|
|
'themeBoundary',
|
|
'主题边界',
|
|
session.anchorContent.themeBoundary,
|
|
),
|
|
buildCustomWorldAnchor(
|
|
'playerEntryPoint',
|
|
'开局切入',
|
|
session.anchorContent.playerEntryPoint,
|
|
),
|
|
buildCustomWorldAnchor(
|
|
'coreConflict',
|
|
'核心冲突',
|
|
session.anchorContent.coreConflict,
|
|
),
|
|
buildCustomWorldAnchor(
|
|
'keyRelationships',
|
|
'关键关系',
|
|
session.anchorContent.keyRelationships,
|
|
),
|
|
buildCustomWorldAnchor(
|
|
'hiddenLines',
|
|
'暗线',
|
|
session.anchorContent.hiddenLines,
|
|
),
|
|
buildCustomWorldAnchor(
|
|
'iconicElements',
|
|
'标志元素',
|
|
session.anchorContent.iconicElements,
|
|
),
|
|
],
|
|
messages: session.messages,
|
|
recommendedReplies: session.recommendedReplies,
|
|
};
|
|
}
|
|
|
|
function mapCustomWorldOperation(
|
|
operation: CustomWorldAgentOperationRecord | null,
|
|
): CreationAgentOperationView | null {
|
|
if (!operation || operation.type === 'process_message') {
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
operationId: operation.operationId,
|
|
type: operation.type,
|
|
status: operation.status,
|
|
phaseLabel: operation.phaseLabel,
|
|
phaseDetail: operation.phaseDetail,
|
|
progress: operation.progress,
|
|
error: operation.error,
|
|
};
|
|
}
|
|
|
|
export function CustomWorldAgentWorkspace({
|
|
session,
|
|
activeOperation,
|
|
streamingReplyText = '',
|
|
isStreamingReply = false,
|
|
onBack,
|
|
onSubmitMessage,
|
|
onExecuteAction,
|
|
}: CustomWorldAgentWorkspaceProps) {
|
|
const isBusy =
|
|
isCreationAgentOperationBusy(activeOperation) || isStreamingReply;
|
|
|
|
const submitMessage = (text: string, quickFillRequested = false) => {
|
|
onSubmitMessage(
|
|
buildCreationAgentChatMessage({
|
|
clientMessageId: createCreationAgentClientMessageId('custom-world'),
|
|
text,
|
|
quickFillRequested,
|
|
extraPayload: {
|
|
focusCardId: null,
|
|
selectedCardIds: [],
|
|
},
|
|
}),
|
|
);
|
|
};
|
|
|
|
return (
|
|
<CreationAgentWorkspace
|
|
session={session ? mapCustomWorldSession(session) : null}
|
|
theme={CUSTOM_WORLD_AGENT_THEME}
|
|
loadingText="正在恢复"
|
|
composerPlaceholder="输入消息"
|
|
primaryActionLabel="生成游戏设定草稿"
|
|
activeOperation={mapCustomWorldOperation(activeOperation)}
|
|
streamingReplyText={streamingReplyText}
|
|
isStreamingReply={isStreamingReply}
|
|
isBusy={isBusy}
|
|
quickActions={createCreationAgentChatQuickActions()}
|
|
onBack={onBack}
|
|
onSubmitText={(text) => {
|
|
submitMessage(text);
|
|
}}
|
|
onPrimaryAction={() => {
|
|
onExecuteAction({
|
|
action: 'draft_foundation',
|
|
});
|
|
}}
|
|
onQuickAction={(action) => {
|
|
const quickActionMessage = resolveCreationAgentQuickActionMessage(
|
|
action.key,
|
|
'请总结一下当前已经成形的世界设定。',
|
|
);
|
|
submitMessage(
|
|
quickActionMessage.text,
|
|
quickActionMessage.quickFillRequested,
|
|
);
|
|
}}
|
|
/>
|
|
);
|
|
}
|