From 871c59c3bcfd0f76e671f9eba4ca1a49451db272 Mon Sep 17 00:00:00 2001 From: imccyu <276526105+imccyu@users.noreply.github.com> Date: Sat, 8 Aug 2026 17:12:54 +0800 Subject: [PATCH] fix(client): address tool tree review --- .../src/client/chat/GenericCommandCard.tsx | 1 + .../ui-conversation/tests/chat-view.spec.tsx | 1 + .../ui-tool/src/client/tool/ToolCallTree.tsx | 31 ++++++++++--------- .../ui-tool/tests/tool-call-tree.spec.tsx | 2 ++ 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/packages/client/ui-conversation/src/client/chat/GenericCommandCard.tsx b/packages/client/ui-conversation/src/client/chat/GenericCommandCard.tsx index 9137181265..676e433fa5 100644 --- a/packages/client/ui-conversation/src/client/chat/GenericCommandCard.tsx +++ b/packages/client/ui-conversation/src/client/chat/GenericCommandCard.tsx @@ -45,6 +45,7 @@ export function GenericCommandCard({ node, t, runningSummary }: GenericCommandCa const open = expanded && body !== null return (
+ {state === 'running' && {t('row.running')}} {state === 'error' && {t('row.failed')}} { const xv = render() expect(xv.container.querySelector('[data-state="running"]')).not.toBeNull() expect(xv.getByText('执行中…')).toBeTruthy() + expect(xv.getByText('运行中')).toBeTruthy() // Cross-window soft-fall (run page truncated): generic title, outcome preserved. const orphan = makeHarness({ diff --git a/packages/client/ui-tool/src/client/tool/ToolCallTree.tsx b/packages/client/ui-tool/src/client/tool/ToolCallTree.tsx index 8091f26dff..3c71e2f4d4 100644 --- a/packages/client/ui-tool/src/client/tool/ToolCallTree.tsx +++ b/packages/client/ui-tool/src/client/tool/ToolCallTree.tsx @@ -1,5 +1,5 @@ /** Root/subcall Tool composition with one keyed atomic dispatch path. */ -import { memo, useMemo } from 'react' +import { memo, useMemo, type ReactNode } from 'react' import type { CodeSubCall, ToolCallBlock } from '@deepseek-ai/dsh-client-runtime/client' import type { ToolCallOwnerProps, ToolTreeProps } from '../contract/slots.ts' import { GenericToolCard } from './toolviews/GenericToolCard.tsx' @@ -12,12 +12,13 @@ function subCallName(node: CodeSubCall): string { /** One atomic call dispatched through the Tool-owned keyed slot. */ const ToolCall = memo(function ToolCall({ - renderSlot, callId, toolName, block, openFile, selected, cwd, inspectCall, t, + renderSlot, callId, toolName, block, openFile, selected, cwd, inspectCall, t, children, }: Pick & { callId: string toolName: string block: ToolCallBlock selected: boolean + children?: ReactNode }) { const owner: ToolCallOwnerProps = useMemo(() => ({ callId, @@ -38,6 +39,7 @@ const ToolCall = memo(function ToolCall({ entryKey: toolName, fallback: , })} + {children}
) }) @@ -53,18 +55,17 @@ export function ToolCallTree({ }: ToolTreeProps) { const subCalls = useSession(snapshot => snapshot.codeDispatches.get(callId)) return ( - <> - + {subCalls !== undefined && subCalls.length > 0 ? (
{subCalls.map(node => ( @@ -83,6 +84,6 @@ export function ToolCallTree({ ))}
) : null} - +
) } diff --git a/packages/client/ui-tool/tests/tool-call-tree.spec.tsx b/packages/client/ui-tool/tests/tool-call-tree.spec.tsx index 0720ba5642..c8c31ad365 100644 --- a/packages/client/ui-tool/tests/tool-call-tree.spec.tsx +++ b/packages/client/ui-tool/tests/tool-call-tree.spec.tsx @@ -57,6 +57,8 @@ describe('ToolCallTree', () => { const view = render( , ) + expect(view.container.querySelector('[data-subcalls]')?.parentElement) + .toBe(view.container.querySelector('[data-chat-call-id="parent"]')) expect(view.container.querySelector('[data-chat-call-id="parent"]')?.hasAttribute('data-selected')).toBe(false) expect(view.container.querySelector('[data-chat-call-id="parent:code:1"]')?.getAttribute('data-selected')).toBe('true') })