From a0f6b7c67d4758a976b355aed882d4507b77cbbf Mon Sep 17 00:00:00 2001 From: Suzumiya Date: Fri, 18 Sep 2026 14:34:10 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E6=80=9D=E8=80=83=E4=B8=8E?= =?UTF-8?q?=E6=89=A7=E8=A1=8C=E8=BF=87=E7=A8=8B=E6=8A=98=E5=8F=A0=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F=E5=8F=8A=E4=B8=AD=E6=96=87=E8=80=97=E6=97=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 思考展开复用安全Markdown渲染,折叠显示浅色单行纯文本预览与右侧箭头。 共享过程摘要组件,执行过程按真实操作数显示统计并保留各组独立计时。 工具、整轮、生成任务和策划耗时统一为中文时分秒格式。 补齐格式与Markdown回归、更新已有界面断言并验证窄屏键盘操作。 --- .../project-workspace/GddApprovalCard.tsx | 3 +- .../ProjectSupervisorView.tsx | 54 +++++++- .../project-workspace/ToolCallGroup.tsx | 39 +++--- .../project-workspace/agentProcessPreview.ts | 73 +++++++++++ .../toolCallGroupPresentation.ts | 87 +++---------- .../resourceCanvasAssetGenerationTaskModel.ts | 6 +- apps/ai-game-creator-shell/src/styles.css | 121 ++++++++++++++++++ .../tests/agentProcessPreview.test.ts | 51 ++++++++ .../tests/appSurface/design-agent.suite.ts | 31 +++-- .../appSurface/project-development.suite.ts | 29 +++-- .../tests/appSurface/tool-call-group.suite.ts | 76 +++++------ .../tests/elapsedDuration.test.ts | 33 +++++ ...resourceCanvasAssetGenerationQueue.test.ts | 8 +- ...ceCanvasAssetGenerationTasksPanel.test.tsx | 2 +- .../shared-memory/team-conventions.md | 2 + ...方案】GameAgent对话工具调用卡片-2026-09-14.md | 25 ++-- .../src/components/AgentProcessSummary.css | 65 ++++++++++ .../src/components/AgentProcessSummary.tsx | 48 +++++++ packages/shared/src/components/index.ts | 1 + .../shared/src/lib/formatElapsedDuration.ts | 26 ++++ packages/shared/src/lib/index.ts | 1 + 21 files changed, 604 insertions(+), 177 deletions(-) create mode 100644 apps/ai-game-creator-shell/src/features/project-workspace/agentProcessPreview.ts create mode 100644 apps/ai-game-creator-shell/tests/agentProcessPreview.test.ts create mode 100644 apps/ai-game-creator-shell/tests/elapsedDuration.test.ts create mode 100644 packages/shared/src/components/AgentProcessSummary.css create mode 100644 packages/shared/src/components/AgentProcessSummary.tsx create mode 100644 packages/shared/src/lib/formatElapsedDuration.ts 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} - -