fix(client): address tool tree review
This commit is contained in:
@@ -45,6 +45,7 @@ export function GenericCommandCard({ node, t, runningSummary }: GenericCommandCa
|
|||||||
const open = expanded && body !== null
|
const open = expanded && body !== null
|
||||||
return (
|
return (
|
||||||
<div className={css.root} data-variant="others" data-state={state}>
|
<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>}
|
{state === 'error' && <span className={a11yCss.visuallyHidden}>{t('row.failed')}</span>}
|
||||||
<DisclosureRow
|
<DisclosureRow
|
||||||
rowClassName={css.row}
|
rowClassName={css.row}
|
||||||
|
|||||||
@@ -1278,6 +1278,7 @@ describe('ChatView', () => {
|
|||||||
const xv = render(<executing.ChatView {...executing.props} />)
|
const xv = render(<executing.ChatView {...executing.props} />)
|
||||||
expect(xv.container.querySelector('[data-state="running"]')).not.toBeNull()
|
expect(xv.container.querySelector('[data-state="running"]')).not.toBeNull()
|
||||||
expect(xv.getByText('执行中…')).toBeTruthy()
|
expect(xv.getByText('执行中…')).toBeTruthy()
|
||||||
|
expect(xv.getByText('运行中')).toBeTruthy()
|
||||||
|
|
||||||
// Cross-window soft-fall (run page truncated): generic title, outcome preserved.
|
// Cross-window soft-fall (run page truncated): generic title, outcome preserved.
|
||||||
const orphan = makeHarness({
|
const orphan = makeHarness({
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/** Root/subcall Tool composition with one keyed atomic dispatch path. */
|
/** 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 { CodeSubCall, ToolCallBlock } from '@deepseek-ai/dsh-client-runtime/client'
|
||||||
import type { ToolCallOwnerProps, ToolTreeProps } from '../contract/slots.ts'
|
import type { ToolCallOwnerProps, ToolTreeProps } from '../contract/slots.ts'
|
||||||
import { GenericToolCard } from './toolviews/GenericToolCard.tsx'
|
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. */
|
/** One atomic call dispatched through the Tool-owned keyed slot. */
|
||||||
const ToolCall = memo(function ToolCall({
|
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'> & {
|
}: Pick<ToolTreeProps, 'renderSlot' | 'openFile' | 'cwd' | 'inspectCall' | 't'> & {
|
||||||
callId: string
|
callId: string
|
||||||
toolName: string
|
toolName: string
|
||||||
block: ToolCallBlock
|
block: ToolCallBlock
|
||||||
selected: boolean
|
selected: boolean
|
||||||
|
children?: ReactNode
|
||||||
}) {
|
}) {
|
||||||
const owner: ToolCallOwnerProps = useMemo(() => ({
|
const owner: ToolCallOwnerProps = useMemo(() => ({
|
||||||
callId,
|
callId,
|
||||||
@@ -38,6 +39,7 @@ const ToolCall = memo(function ToolCall({
|
|||||||
entryKey: toolName,
|
entryKey: toolName,
|
||||||
fallback: <GenericToolCard {...owner} t={t} />,
|
fallback: <GenericToolCard {...owner} t={t} />,
|
||||||
})}
|
})}
|
||||||
|
{children}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -53,7 +55,6 @@ export function ToolCallTree({
|
|||||||
}: ToolTreeProps) {
|
}: ToolTreeProps) {
|
||||||
const subCalls = useSession(snapshot => snapshot.codeDispatches.get(callId))
|
const subCalls = useSession(snapshot => snapshot.codeDispatches.get(callId))
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
<ToolCall
|
<ToolCall
|
||||||
renderSlot={renderSlot}
|
renderSlot={renderSlot}
|
||||||
callId={callId}
|
callId={callId}
|
||||||
@@ -64,7 +65,7 @@ export function ToolCallTree({
|
|||||||
cwd={cwd}
|
cwd={cwd}
|
||||||
inspectCall={inspectCall}
|
inspectCall={inspectCall}
|
||||||
t={t}
|
t={t}
|
||||||
/>
|
>
|
||||||
{subCalls !== undefined && subCalls.length > 0 ? (
|
{subCalls !== undefined && subCalls.length > 0 ? (
|
||||||
<div className={css.subCalls} data-subcalls>
|
<div className={css.subCalls} data-subcalls>
|
||||||
{subCalls.map(node => (
|
{subCalls.map(node => (
|
||||||
@@ -83,6 +84,6 @@ export function ToolCallTree({
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</>
|
</ToolCall>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ describe('ToolCallTree', () => {
|
|||||||
const view = render(
|
const view = render(
|
||||||
<ToolCallTree {...props(block, new Map([['parent', [child]]]), child.callId)} />,
|
<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"]')?.hasAttribute('data-selected')).toBe(false)
|
||||||
expect(view.container.querySelector('[data-chat-call-id="parent:code:1"]')?.getAttribute('data-selected')).toBe('true')
|
expect(view.container.querySelector('[data-chat-call-id="parent:code:1"]')?.getAttribute('data-selected')).toBe('true')
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user