diff --git a/apps/ai-game-creator-shell/src/features/project-workspace/ProjectSupervisorView.tsx b/apps/ai-game-creator-shell/src/features/project-workspace/ProjectSupervisorView.tsx index 8c6312681..4a21a7550 100644 --- a/apps/ai-game-creator-shell/src/features/project-workspace/ProjectSupervisorView.tsx +++ b/apps/ai-game-creator-shell/src/features/project-workspace/ProjectSupervisorView.tsx @@ -1,8 +1,8 @@ import { ArrowUp, AtSign, - Brain, ChevronDown, + Lightbulb, Loader2, Settings, Wrench, @@ -125,6 +125,7 @@ function AgentReasoning({ label?: string; testId?: string; }) { + const [expanded, setExpanded] = useState(false); // 折叠态:单行纯文本预览(走 Markdown AST 取文字,链接只留字面文字、不含目标)。 const preview = agentProcessPreview(text); return ( @@ -134,11 +135,14 @@ function AgentReasoning({ className="design-agent-reasoning" aria-label={label} data-testid={testId} + onToggle={(event) => + setExpanded((event.currentTarget as HTMLDetailsElement).open) + } > @@ -319,6 +323,16 @@ export function ProjectSupervisorView({ : []; const activeTurnStartedAt = directTurns.find((turn) => turn.active)?.startedAt ?? 0; + const latestDirectTurn = directTurns.at(-1); + // 仅是首个响应到达前的临时提示,不创建聊天条目或第二套回合状态。 + const awaitingFirstResponse = + directCodex && + (runBusy || directTurnRunning) && + !turnCancelling && + !runtimePanelProps.error && + Boolean(latestDirectTurn?.users.length) && + latestDirectTurn?.process.length === 0 && + latestDirectTurn?.finals.length === 0; // 初始占位气泡只是"最初那条消息还没有正式条目"时的顶位,两种情况下不再渲染: // - 已经翻出更早的历史(`hasEarlierConversationMessages`):这里不是对话开头,不补占位; // - Direct 模式已经有了正式用户条目:正式气泡自己会显示,占位再渲染就是同一条消息出现两次。 @@ -648,6 +662,18 @@ export function ProjectSupervisorView({ ) : null} + {awaitingFirstResponse ? ( + + + ) : null} {directCodex ? null : planningSurfaceActive ? ( call.status === 'failed') - ? 'failed' - : 'completed'; + const hasFailure = orderedCalls.some((call) => call.status === 'failed'); + const status = toolRunning ? 'running' : hasFailure ? 'failed' : 'completed'; // 用户口径:`执行了 X 个操作,耗时 XXX`。耗时属于**这一组**(不是整轮),可见文本里用 // 中文逗号连起来,所以分隔符跟着 meta 一起进 DOM。 // 顺序按用户口径:`执行了 X 个操作,耗时 XXX`,运行状态挂到最后,不插在中间。 const headMeta = [ timing.durationText ? `耗时 ${timing.durationText}` : '', + hasFailure ? '有操作失败' : '', toolRunning ? '进行中' : '', ] .filter(Boolean) @@ -101,6 +99,7 @@ export function ToolCallGroup({ data-testid="agent-tool-call-group" aria-label="陶泥儿执行过程" data-status={status} + data-has-failure={hasFailure ? 'true' : undefined} data-duration-ms={timing.durationMs ?? ''} >