fix(client): address tool tree review

This commit is contained in:
imccyu
2026-08-08 17:12:54 +08:00
parent 3b31b2eba1
commit 871c59c3bc
4 changed files with 20 additions and 15 deletions
@@ -45,6 +45,7 @@ export function GenericCommandCard({ node, t, runningSummary }: GenericCommandCa
const open = expanded && body !== null
return (
<div className={css.root} data-variant="others" data-state={state}>
{state === 'running' && <span className={a11yCss.visuallyHidden}>{t('row.running')}</span>}
{state === 'error' && <span className={a11yCss.visuallyHidden}>{t('row.failed')}</span>}
<DisclosureRow
rowClassName={css.row}
@@ -1278,6 +1278,7 @@ describe('ChatView', () => {
const xv = render(<executing.ChatView {...executing.props} />)
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({
@@ -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<ToolTreeProps, 'renderSlot' | 'openFile' | 'cwd' | 'inspectCall' | 't'> & {
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: <GenericToolCard {...owner} t={t} />,
})}
{children}
</div>
)
})
@@ -53,18 +55,17 @@ export function ToolCallTree({
}: ToolTreeProps) {
const subCalls = useSession(snapshot => snapshot.codeDispatches.get(callId))
return (
<>
<ToolCall
renderSlot={renderSlot}
callId={callId}
toolName={toolName}
block={block}
openFile={openFile}
selected={callId === selectedCallId}
cwd={cwd}
inspectCall={inspectCall}
t={t}
/>
<ToolCall
renderSlot={renderSlot}
callId={callId}
toolName={toolName}
block={block}
openFile={openFile}
selected={callId === selectedCallId}
cwd={cwd}
inspectCall={inspectCall}
t={t}
>
{subCalls !== undefined && subCalls.length > 0 ? (
<div className={css.subCalls} data-subcalls>
{subCalls.map(node => (
@@ -83,6 +84,6 @@ export function ToolCallTree({
))}
</div>
) : null}
</>
</ToolCall>
)
}
@@ -57,6 +57,8 @@ describe('ToolCallTree', () => {
const view = render(
<ToolCallTree {...props(block, new Map([['parent', [child]]]), child.callId)} />,
)
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')
})