功能:DirectProject 回合块标记 data-turn-key 供滚动锚点定位

- DirectProjectTurn 的正文块、执行过程折叠块与终态文案块写上 data-turn-key
- ToolCallGroup 与 AgentReasoning 新增可选 turnKey 透传,工具组与思考块也带回合身份
- 锚点按「回合 key + 块内序号 + 偏移」定位,不新增 DOM 包裹层

Co-authored-by: Junie <junie@jetbrains.com>
This commit is contained in:
2026-10-02 17:53:53 +08:00
parent 72ad9b8cdb
commit 1653a2be6e
3 changed files with 32 additions and 3 deletions
@@ -18,10 +18,16 @@ function AgentReasoningImpl({
text,
label = '思考过程',
testId,
turnKey,
}: {
text: string;
label?: string;
testId?: string;
/**
* 所属回合的 `DirectChatTurn.key`:写进 `data-turn-key`,供会话滚动的前插锚点按
* 「回合 key + 块序号」定位这一块(见 `DirectProjectConversation/conversationScrollAnchor.ts`)。
*/
turnKey?: string;
}) {
const [expanded, setExpanded] = useState(false);
/*
@@ -37,6 +43,7 @@ function AgentReasoningImpl({
className="design-agent-reasoning"
aria-label={label}
data-testid={testId}
data-turn-key={turnKey}
onToggle={(event) =>
setExpanded((event.currentTarget as HTMLDetailsElement).open)
}
@@ -58,7 +58,11 @@ function renderTurnProcess(turn: DirectChatTurn, streamingKey: string | null) {
);
if (turn.state !== 'finished') return blocks;
return (
<details className="message-turn-process" data-testid="turn-process">
<details
className="message-turn-process"
data-testid="turn-process"
data-turn-key={turn.key}
>
<summary>执行过程</summary>
<div className="message-turn-process-body">{blocks}</div>
</details>
@@ -78,6 +82,7 @@ function DirectProjectTurnUsage({ turn }: { turn: DirectChatTurn }) {
className="message-turn-usage"
data-testid="turn-usage"
data-turn-running="false"
data-turn-key={turn.key}
>
{`本轮结束于 ${new Date(endedAt).toLocaleTimeString('zh-CN', {
hour12: false,
@@ -99,17 +104,27 @@ function renderBlock(
calls={block.calls}
active={turn.state === 'running'}
className="message-tool-call"
turnKey={turn.key}
/>
);
}
if (block.kind === 'reasoning') {
return (
<AgentReasoning key={block.key} text={block.text} label="思考过程" />
<AgentReasoning
key={block.key}
text={block.text}
label="思考过程"
turnKey={turn.key}
/>
);
}
const role = block.kind === 'user' ? 'user' : 'assistant';
return (
<div key={block.key} className={`message message--${role}`}>
<div
key={block.key}
className={`message message--${role}`}
data-turn-key={turn.key}
>
<AgentMessageContent tone={tone}>
<ChatMarkdownMessage
role={role}
@@ -42,6 +42,7 @@ export function ToolCallGroup({
calls,
active = false,
className,
turnKey,
}: {
calls: DirectChatToolCard[];
/**
@@ -51,6 +52,11 @@ export function ToolCallGroup({
*/
active?: boolean;
className?: string;
/**
* 所属回合的 `DirectChatTurn.key`:写进 `data-turn-key`,供会话滚动的前插锚点按
* 「回合 key + 块序号」定位这一块(见 `DirectProjectConversation/conversationScrollAnchor.ts`)。
*/
turnKey?: string;
}) {
const [expanded, setExpanded] = useState(false);
const bodyId = useId();
@@ -98,6 +104,7 @@ export function ToolCallGroup({
}
data-testid="agent-tool-call-group"
aria-label="陶泥儿执行过程"
data-turn-key={turnKey}
data-status={status}
data-has-failure={hasFailure ? 'true' : undefined}
data-duration-ms={timing.durationMs ?? ''}