diff --git a/apps/ai-game-creator-shell/src/features/project-workspace/GddApprovalCard.tsx b/apps/ai-game-creator-shell/src/features/project-workspace/GddApprovalCard.tsx index 3018200fb..1273bb017 100644 --- a/apps/ai-game-creator-shell/src/features/project-workspace/GddApprovalCard.tsx +++ b/apps/ai-game-creator-shell/src/features/project-workspace/GddApprovalCard.tsx @@ -1,5 +1,6 @@ import { useState } from 'react'; +import { formatElapsedDuration } from '../../../../../packages/shared/src/lib/formatElapsedDuration'; import { resolveTauriInvoke } from '../../app/tauri'; import type { PlanGddDecisionAction, @@ -171,7 +172,7 @@ export function PlanGddStageProgress({ : `当前版本:v${latestVersion}`} {processingSeconds > 0 ? ( - {`处理耗时:${processingSeconds.toFixed(1)} 秒`} + {`处理耗时:${formatElapsedDuration(processingSeconds * 1000) ?? '—'}`} ) : null} {deliveredGdd ? ( 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 8e10c1b89..8c6312681 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,4 +1,12 @@ -import { ArrowUp, AtSign, Loader2, Settings } from 'lucide-react'; +import { + ArrowUp, + AtSign, + Brain, + ChevronDown, + Loader2, + Settings, + Wrench, +} from 'lucide-react'; import type { ComponentProps, FormEventHandler, @@ -12,6 +20,7 @@ import { AgentMessageContent, type AgentMessageTone, } from '../../../../../packages/shared/src/components/AgentMessageContent'; +import { AgentProcessSummary } from '../../../../../packages/shared/src/components/AgentProcessSummary'; import type { AgentStatusCard, ChatMessage, @@ -41,6 +50,7 @@ import { import type { DirectCodexTurnAttachment } from '../app-shell/directCodexTurnAttachments'; import { formatAgentCardRuntimeStatus } from '../project-summary/agentPresentation'; import { taskStatusLabels } from '../project-summary/projectSummary'; +import { agentProcessPreview } from './agentProcessPreview'; import type { QueuedChatTurn } from './chatComposerQueue'; import { ComposerPendingAttachments, @@ -81,6 +91,7 @@ import type { ChatComposerDraft, ChatReference } from './resourceReferences'; import { ToolCallGroup } from './ToolCallGroup'; import { formatClockTime, + resolveToolGroupTiming, resolveTurnTiming, } from './toolCallGroupPresentation'; import { useLiveNow } from './useLiveNow'; @@ -114,6 +125,8 @@ function AgentReasoning({ label?: string; testId?: string; }) { + // 折叠态:单行纯文本预览(走 Markdown AST 取文字,链接只留字面文字、不含目标)。 + const preview = agentProcessPreview(text); return ( - 思考过程 -
{text}
+ + + {/* 展开态复用助手正文的安全 Markdown 链路(内部 skipHtml,不用 innerHTML)。 */} +
); } @@ -486,6 +506,15 @@ export function ProjectSupervisorView({ .reverse() .find((block) => block.kind === 'assistant')?.key ?? null) : null; + // 外层"执行过程"汇总**这一轮全部工具调用**(不是过程段落数,也不含思考段): + // 计数 = 所有组的 calls 之和;耗时 = 首工具开始 → 末工具完成(各组的并集跨度, + // 不是整轮总耗时,也不与整轮那处重复);边界不完整时隐藏。 + const turnToolCalls = turn.process.flatMap((block) => + block.kind === 'tools' ? block.calls : [], + ); + const turnToolSpan = resolveToolGroupTiming(turnToolCalls, { + running: false, + }); const renderBlock = ( block: DirectChatBlock, tone: AgentMessageTone = 'body', @@ -553,7 +582,24 @@ export function ProjectSupervisorView({ className="message-turn-process" data-testid="turn-process" > - 执行过程 + +
{turn.process.map((block) => renderBlock(block, 'process'), diff --git a/apps/ai-game-creator-shell/src/features/project-workspace/ToolCallGroup.tsx b/apps/ai-game-creator-shell/src/features/project-workspace/ToolCallGroup.tsx index f62c66b23..dd97487df 100644 --- a/apps/ai-game-creator-shell/src/features/project-workspace/ToolCallGroup.tsx +++ b/apps/ai-game-creator-shell/src/features/project-workspace/ToolCallGroup.tsx @@ -9,6 +9,7 @@ import { import { useId, useState } from 'react'; import { AgentMessageContent } from '../../../../../packages/shared/src/components/AgentMessageContent'; +import { AgentProcessSummary } from '../../../../../packages/shared/src/components/AgentProcessSummary'; import type { DirectChatToolCard } from './directThreadChat'; import { formatToolCallDuration, @@ -78,13 +79,16 @@ export function ToolCallGroup({ : orderedCalls.some((call) => call.status === 'failed') ? 'failed' : 'completed'; - const headLabel = [ - summary, + // 用户口径:`执行了 X 个操作,耗时 XXX`。耗时属于**这一组**(不是整轮),可见文本里用 + // 中文逗号连起来,所以分隔符跟着 meta 一起进 DOM。 + // 顺序按用户口径:`执行了 X 个操作,耗时 XXX`,运行状态挂到最后,不插在中间。 + const headMeta = [ + timing.durationText ? `耗时 ${timing.durationText}` : '', toolRunning ? '进行中' : '', - timing.durationText ? `本组用时 ${timing.durationText}` : '', ] .filter(Boolean) .join(','); + const headLabel = [summary, headMeta].filter(Boolean).join(','); return ( setExpanded((current) => !current)} > - - {summary} - - {toolRunning ? ( - 进行中 - ) : null} - {timing.durationText ? ( - - {`本组用时 ${timing.durationText}`} - - ) : null} - -