|
|
@@ -25,7 +25,6 @@ import type {
|
|
|
import type { SnapshotSelectorHook } from '@deepseek-ai/dsh-client-ui-slots'
|
|
|
import { IconChevronDownOutline14 } from '@deepseek-ai/dsh-client-ui-primitives'
|
|
|
import type { ChatViewSlotProps } from '../contract/slots.ts'
|
|
|
-import type { SelectionTarget } from '../contract/views.ts'
|
|
|
import { deriveChatFlow, type ChatFlowItem } from './chat-flow.ts'
|
|
|
import { AssistantMarkdown } from './AssistantMarkdown.tsx'
|
|
|
import { GenericToolCard } from './GenericToolCard.tsx'
|
|
|
@@ -36,7 +35,7 @@ import css from './ChatView.module.css'
|
|
|
|
|
|
const FOLLOW_THRESHOLD = 24
|
|
|
|
|
|
-type OpenDetails = (target: SelectionTarget) => void
|
|
|
+type OpenFile = (path: string) => void
|
|
|
|
|
|
/** The declared toolview hole's render share (stable framework binding, passed through memoized rows). */
|
|
|
type RenderToolRow = ChatViewSlotProps['renderSlot']
|
|
|
@@ -49,20 +48,18 @@ type UseConversation = SnapshotSelectorHook<ConversationSnapshot>
|
|
|
* top-level call (same registrations, same fallback), nested by the parent.
|
|
|
* A started-but-unsettled sub-call arrives as the RunningToolCall shape and
|
|
|
* renders the running state exactly as a native in-flight row. */
|
|
|
-const SubCallRow = memo(function SubCallRow({ renderSlot, node, onOpenDetails, selected, cwd }: {
|
|
|
+const SubCallRow = memo(function SubCallRow({ renderSlot, node, openFile, selected, cwd }: {
|
|
|
renderSlot: RenderToolRow
|
|
|
node: CodeSubCall
|
|
|
- onOpenDetails: OpenDetails
|
|
|
+ openFile: OpenFile
|
|
|
selected: boolean
|
|
|
cwd: string | undefined
|
|
|
}) {
|
|
|
const settled = 'kind' in node
|
|
|
const toolName = settled ? node.call?.name ?? '' : node.name
|
|
|
- const seq = settled ? node.seq : node.time
|
|
|
const owner = useMemo(() => ({
|
|
|
- callId: node.callId, toolName, block: node, cwd,
|
|
|
- openDetails: () => { onOpenDetails({ turnSeq: seq, callId: node.callId, toolName }) },
|
|
|
- }), [node, toolName, seq, cwd, onOpenDetails])
|
|
|
+ callId: node.callId, toolName, block: node, openFile, cwd,
|
|
|
+ }), [node, toolName, openFile, cwd])
|
|
|
return (
|
|
|
<div className={css.callRow} data-selected={selected || undefined}>
|
|
|
{renderSlot('conversation.chat.toolview', owner, {
|
|
|
@@ -79,15 +76,13 @@ const SubCallRow = memo(function SubCallRow({ renderSlot, node, onOpenDetails, s
|
|
|
* renders its logged sub-dispatches as always-visible indented rows —
|
|
|
* each one the same keyed-slot dispatch as a native top-level call. */
|
|
|
const CallRow = memo(function CallRow({
|
|
|
- renderSlot, callId, toolName, block, seq, onOpenDetails, selected, subCalls, selectedCallId, cwd,
|
|
|
+ renderSlot, callId, toolName, block, openFile, selected, subCalls, selectedCallId, cwd,
|
|
|
}: {
|
|
|
renderSlot: RenderToolRow
|
|
|
callId: string
|
|
|
toolName: string
|
|
|
block: ToolResultNode | RunningToolCall
|
|
|
- /** Surface seq for finalized results; the call's turn for running calls. */
|
|
|
- seq: number
|
|
|
- onOpenDetails: OpenDetails
|
|
|
+ openFile: OpenFile
|
|
|
selected: boolean
|
|
|
/** `run_code` sub-dispatches in dispatch order (reference-stable per
|
|
|
* parent; running entries settle in place); undefined for ordinary calls. */
|
|
|
@@ -98,9 +93,8 @@ const CallRow = memo(function CallRow({
|
|
|
cwd: string | undefined
|
|
|
}) {
|
|
|
const owner = useMemo(() => ({
|
|
|
- callId, toolName, block, cwd,
|
|
|
- openDetails: () => { onOpenDetails({ turnSeq: seq, callId, toolName }) },
|
|
|
- }), [callId, toolName, block, seq, cwd, onOpenDetails])
|
|
|
+ callId, toolName, block, openFile, cwd,
|
|
|
+ }), [callId, toolName, block, openFile, cwd])
|
|
|
return (
|
|
|
<div className={css.callRow} data-selected={selected || undefined}>
|
|
|
{renderSlot('conversation.chat.toolview', owner, {
|
|
|
@@ -114,7 +108,7 @@ const CallRow = memo(function CallRow({
|
|
|
key={node.callId}
|
|
|
renderSlot={renderSlot}
|
|
|
node={node}
|
|
|
- onOpenDetails={onOpenDetails}
|
|
|
+ openFile={openFile}
|
|
|
selected={node.callId === selectedCallId}
|
|
|
cwd={cwd}
|
|
|
/>
|
|
|
@@ -126,10 +120,10 @@ const CallRow = memo(function CallRow({
|
|
|
})
|
|
|
|
|
|
/** Consecutive tool results as one step-run group (uniform 16px rhythm). */
|
|
|
-const ToolGroup = memo(function ToolGroup({ renderSlot, results, onOpenDetails, selectedCallId, codeDispatches, cwd }: {
|
|
|
+const ToolGroup = memo(function ToolGroup({ renderSlot, results, openFile, selectedCallId, codeDispatches, cwd }: {
|
|
|
renderSlot: RenderToolRow
|
|
|
results: readonly ToolResultNode[]
|
|
|
- onOpenDetails: OpenDetails
|
|
|
+ openFile: OpenFile
|
|
|
/** Only set when the selected call lives in THIS group, top-level or nested (memo economy). */
|
|
|
selectedCallId: string | undefined
|
|
|
/** Sub-dispatch index off the snapshot (map reference is chunk-storm stable). */
|
|
|
@@ -146,8 +140,7 @@ const ToolGroup = memo(function ToolGroup({ renderSlot, results, onOpenDetails,
|
|
|
callId={node.callId}
|
|
|
toolName={node.call?.name ?? ''}
|
|
|
block={node}
|
|
|
- seq={node.seq}
|
|
|
- onOpenDetails={onOpenDetails}
|
|
|
+ openFile={openFile}
|
|
|
selected={node.callId === selectedCallId}
|
|
|
subCalls={codeDispatches.get(node.callId)}
|
|
|
selectedCallId={selectedCallId}
|
|
|
@@ -210,7 +203,7 @@ function StreamingTail({ useSession, onGrow }: {
|
|
|
* The chat view slot entry: pure component over the composed props (tool rows
|
|
|
* render through the declared keyed hole's renderSlot share).
|
|
|
*/
|
|
|
-export function ChatView({ useSession, useSessions, useStore, renderSlot, sessionId, openDetails, loadOlder }: ChatViewSlotProps) {
|
|
|
+export function ChatView({ useSession, useSessions, useStore, renderSlot, sessionId, openFile, loadOlder }: ChatViewSlotProps) {
|
|
|
const nodes = useSession(s => s.nodes)
|
|
|
// Workspace root off the session list row: path summaries display relative to it.
|
|
|
const cwd = useSessions(s => s.byId[sessionId]?.cwd)
|
|
|
@@ -311,7 +304,7 @@ export function ChatView({ useSession, useSessions, useStore, renderSlot, sessio
|
|
|
key={item.key}
|
|
|
renderSlot={renderSlot}
|
|
|
results={item.results}
|
|
|
- onOpenDetails={openDetails}
|
|
|
+ openFile={openFile}
|
|
|
selectedCallId={inGroup ? selectedCallId : undefined}
|
|
|
codeDispatches={codeDispatches}
|
|
|
cwd={cwd}
|
|
|
@@ -351,8 +344,7 @@ export function ChatView({ useSession, useSessions, useStore, renderSlot, sessio
|
|
|
callId={call.callId}
|
|
|
toolName={call.name}
|
|
|
block={call}
|
|
|
- seq={call.turn}
|
|
|
- onOpenDetails={openDetails}
|
|
|
+ openFile={openFile}
|
|
|
selected={call.callId === selectedCallId}
|
|
|
subCalls={codeDispatches.get(call.callId)}
|
|
|
selectedCallId={selectedCallId}
|