@deepseek-ai/dsh-client-ui-chat 0.1.6-alpha.2 → 0.1.7-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.i18n.yaml +2 -2
  2. package/README.md +62 -10
  3. package/README.zh.md +60 -10
  4. package/lib/client.js +4808 -1393
  5. package/lib/index.js +37 -10
  6. package/lib/types/chat-settings.d.ts +41 -8
  7. package/lib/types/client/chat/AssistantMarkdown.d.ts +15 -12
  8. package/lib/types/client/chat/AssistantNodeView.d.ts +5 -2
  9. package/lib/types/client/chat/ChatGroupSeat.d.ts +14 -0
  10. package/lib/types/client/chat/ChatNodeSeat.d.ts +11 -5
  11. package/lib/types/client/chat/ChatView.d.ts +1 -1
  12. package/lib/types/client/chat/GenericCommandCard.d.ts +6 -1
  13. package/lib/types/client/chat/ReasoningRow.d.ts +11 -5
  14. package/lib/types/client/chat/StatsPills.d.ts +4 -4
  15. package/lib/types/client/chat/TurnNavigator.d.ts +11 -9
  16. package/lib/types/client/chat/TurnTailNodeView.d.ts +4 -4
  17. package/lib/types/client/chat/TurnTriggerNodeView.d.ts +4 -0
  18. package/lib/types/client/chat/TurnUsagePanel.d.ts +1 -16
  19. package/lib/types/client/chat/message-chrome.d.ts +9 -6
  20. package/lib/types/client/chat/register-node-renderers.d.ts +8 -1
  21. package/lib/types/client/chat/render-entry.d.ts +9 -0
  22. package/lib/types/client/chat/step-process.d.ts +11 -0
  23. package/lib/types/client/chat/turn-trigger.d.ts +15 -0
  24. package/lib/types/client/chat/use-chat-navigation.d.ts +69 -0
  25. package/lib/types/client/chat/use-chat-reading.d.ts +95 -0
  26. package/lib/types/client/chat/use-chat-scroll.d.ts +35 -0
  27. package/lib/types/client/chat/use-chat-viewport.d.ts +147 -0
  28. package/lib/types/client/chat/use-disclosure.d.ts +15 -0
  29. package/lib/types/client/contract/chat-nodes.d.ts +0 -2
  30. package/lib/types/client/contract/chat-visibility.d.ts +9 -0
  31. package/lib/types/client/contract/process-groups.d.ts +23 -0
  32. package/lib/types/client/contract/slots.d.ts +55 -11
  33. package/lib/types/client/contract/snapshot.d.ts +14 -1
  34. package/lib/types/client/contract/turn-metrics.d.ts +1 -20
  35. package/lib/types/client/contract/turn-process.d.ts +7 -0
  36. package/lib/types/client/conversation-nodes/assistant.d.ts +1 -2
  37. package/lib/types/client/conversation-nodes/chat-snapshot-builder.d.ts +9 -2
  38. package/lib/types/client/conversation-nodes/inbox.d.ts +16 -6
  39. package/lib/types/client/conversation-nodes/message.d.ts +5 -1
  40. package/lib/types/client/conversation-nodes/process-activity.d.ts +10 -0
  41. package/lib/types/client/conversation-nodes/process-groups.d.ts +27 -0
  42. package/lib/types/client/index.d.ts +3 -1
  43. package/lib/types/client/locale.d.ts +106 -12
  44. package/lib/types/client/performance-usage.d.ts +19 -0
  45. package/lib/types/client/presentation-policy.d.ts +35 -0
  46. package/lib/types/client/settings/LinkOpeningRow.d.ts +24 -0
  47. package/lib/types/client/settings/PerformanceUsageRow.d.ts +18 -0
  48. package/lib/types/client/settings/PreferenceRow.d.ts +17 -0
  49. package/lib/types/client/settings/TranscriptViewRow.d.ts +6 -6
  50. package/lib/types/client/transcript-view.d.ts +8 -5
  51. package/lib/types/index.d.ts +26 -4
  52. package/package.json +40 -37
@@ -0,0 +1,95 @@
1
+ import type { ChatScrollPosition, ChatViewSlotProps } from '../contract/slots.ts';
2
+ import type { ChatViewport, ViewportLanding, ViewportScroll } from './use-chat-viewport.ts';
3
+ /** Reading facts that affect Chat chrome and initial rail placement. */
4
+ export interface ChatReadingState {
5
+ readonly initialized: boolean;
6
+ readonly followingTail: boolean;
7
+ readonly activeTurn: number | null;
8
+ }
9
+ /** Settled reader position delivered to history-navigation policy. */
10
+ export interface ReadingSample {
11
+ readonly position: ChatScrollPosition | null;
12
+ readonly movedByReader: boolean;
13
+ readonly followingTail: boolean;
14
+ }
15
+ type PositionStore = ChatViewSlotProps['chatScroll'];
16
+ /** Owns reading policy and its cancellable sampling work, without DOM access. */
17
+ export declare class ChatReading {
18
+ private readonly viewport;
19
+ private store;
20
+ private state;
21
+ private readonly onChange;
22
+ private sampleTimer;
23
+ private probeFrame;
24
+ private sampled;
25
+ constructor(viewport: ChatViewport, store: PositionStore, state: ChatReadingState, onChange: (state: ChatReadingState) => void);
26
+ /**
27
+ * Expose pending reader ownership to navigation and resize handlers.
28
+ * @returns whether reader input still awaits interval or scrollend sampling.
29
+ */
30
+ get pending(): boolean;
31
+ /**
32
+ * Expose the active follow policy.
33
+ * @returns whether content growth retains bottom-follow ownership.
34
+ */
35
+ get followingTail(): boolean;
36
+ /**
37
+ * Adopt the committed Session's scroll memory.
38
+ * @param store - scroll memory for the current Session.
39
+ */
40
+ setStore(store: PositionStore): void;
41
+ /**
42
+ * Connect history policy to settled reading observations.
43
+ * @param sampled - receives settled reader positions.
44
+ * @returns a disposer that disconnects only this listener.
45
+ */
46
+ connect(sampled: (sample: ReadingSample) => void): () => void;
47
+ /** Cancel timers and animation frames and detach the sample listener. */
48
+ dispose(): void;
49
+ /** Release bottom follow and pending sampling for an explicit navigation. */
50
+ pauseFollowing(): void;
51
+ /** Land at the current floor and clear saved reader position. */
52
+ followTail(): void;
53
+ /** Restore the Session's semantic position, or follow the tail when none is saved. */
54
+ restore(): void;
55
+ /**
56
+ * Adopt a known landing without rediscovering its anchor.
57
+ * @param landing - measured navigation result that replaces pending reader input.
58
+ */
59
+ acceptNavigation(landing: ViewportLanding): void;
60
+ /**
61
+ * Retain reading policy while history changes the anchor's geometry.
62
+ * @param landing - compensated position that retains the current reading policy.
63
+ */
64
+ preservePosition(landing: ViewportLanding): void;
65
+ /**
66
+ * Handle pinned layout movement and reader arrivals at the floor immediately.
67
+ * @param scroll - attributed scroll delivery; other reader movement remains pending until sampled.
68
+ */
69
+ readonly onScroll: (scroll: ViewportScroll) => void;
70
+ /** Settle pending reader movement at the browser's scrollend. */
71
+ readonly onScrollEnd: () => void;
72
+ /** Reconcile a layout change without overriding unsampled reader input. */
73
+ onResize(): void;
74
+ /** Resolve the active turn from tail ownership or a coalesced reading-line probe. */
75
+ refreshActiveTurn(): void;
76
+ private nearBottom;
77
+ private commit;
78
+ private publish;
79
+ private cancelPending;
80
+ private readonly probe;
81
+ private readonly flushSample;
82
+ }
83
+ /**
84
+ * Retain reading policy and expose only changes in visible reading state.
85
+ * @param viewport - turn-aware DOM operations.
86
+ * @param store - Session-owned semantic scroll memory.
87
+ * @param initialTurn - latest loaded turn before the first landing.
88
+ * @returns the reading owner and its React-visible state.
89
+ */
90
+ export declare function useChatReading(viewport: ChatViewport, store: PositionStore, initialTurn: number | null): {
91
+ reading: ChatReading;
92
+ state: ChatReadingState;
93
+ };
94
+ export {};
95
+ //# sourceMappingURL=use-chat-reading.d.ts.map
@@ -0,0 +1,35 @@
1
+ /** Composes viewport operations, reading policy, and history navigation for Chat. */
2
+ import { type RefObject } from 'react';
3
+ import type { ChatSnapshot } from '../contract/snapshot.ts';
4
+ import type { ChatViewSlotProps } from '../contract/slots.ts';
5
+ import { type ChatNavigation, type ChatNavigationInput } from './use-chat-navigation.ts';
6
+ import { type ChatReadingState } from './use-chat-reading.ts';
7
+ /** Committed content and Session operations used to reconcile scroll ownership. */
8
+ export interface ChatScrollInput extends ChatNavigationInput {
9
+ readonly chatScroll: ChatViewSlotProps['chatScroll'];
10
+ readonly ready: boolean;
11
+ readonly order: readonly string[];
12
+ readonly lastKey: string | null;
13
+ readonly lastIsUser: boolean;
14
+ readonly steeringId: string | null;
15
+ readonly submissionId: string | null;
16
+ readonly running: boolean;
17
+ readonly loadedTurns: ReturnType<ChatSnapshot['navigation']['items']>;
18
+ }
19
+ interface ChatScrollState extends ChatReadingState {
20
+ readonly listRef: RefObject<HTMLDivElement>;
21
+ readonly columnRef: RefObject<HTMLDivElement>;
22
+ readonly busyTurn: number | null;
23
+ readonly navigateToTurn: ChatNavigation['navigateToTurn'];
24
+ readonly loadEarlier: ChatNavigation['loadEarlier'];
25
+ readonly returnToBottom: () => void;
26
+ }
27
+ /**
28
+ * Coordinate scroll policy after Chat content commits.
29
+ * New submitted input supersedes pending reader sampling.
30
+ * @param input - current Chat content, scroll memory, and history operations.
31
+ * @returns element refs, visible reading state, and navigation callbacks.
32
+ */
33
+ export declare function useChatScroll(input: ChatScrollInput): ChatScrollState;
34
+ export {};
35
+ //# sourceMappingURL=use-chat-scroll.d.ts.map
@@ -0,0 +1,147 @@
1
+ /** Turn-aware DOM scrolling and geometry, without history-loading or follow policy. */
2
+ import { type RefObject } from 'react';
3
+ import type { ChatScrollPosition } from '../contract/slots.ts';
4
+ import type { ChatSnapshot } from '../contract/snapshot.ts';
5
+ /** Scroll position, maximum top, and viewport height from one geometry read. */
6
+ export interface ViewportMetrics {
7
+ readonly top: number;
8
+ readonly floor: number;
9
+ readonly height: number;
10
+ }
11
+ /** Scroll geometry attributed against the last acknowledged position. */
12
+ export interface ViewportScroll {
13
+ readonly metrics: ViewportMetrics;
14
+ readonly movedByReader: boolean;
15
+ }
16
+ /** Actual clamped scroll result, including any known semantic anchor and turn. */
17
+ export interface ViewportLanding {
18
+ readonly metrics: ViewportMetrics;
19
+ readonly position: ChatScrollPosition | null;
20
+ readonly turn: number | null;
21
+ }
22
+ interface ViewportEvents {
23
+ scroll: (event: ViewportScroll) => void;
24
+ scrollEnd: () => void;
25
+ resize: () => void;
26
+ interact: () => void;
27
+ }
28
+ /** Owns one Chat scrollport's DOM operations, event listeners, and size observer. */
29
+ export declare class ChatViewport {
30
+ private elements;
31
+ private observer;
32
+ private events;
33
+ private turns;
34
+ private observation;
35
+ private paging;
36
+ /**
37
+ * Bind to the containing scrollport and observe content and viewport sizes.
38
+ * @param list - Chat root inside an optional shared conversation scrollport.
39
+ * @param column - ordered outer Node/Group boxes; its size changes invalidate cached landings.
40
+ */
41
+ attach(list: HTMLElement, column: HTMLElement): void;
42
+ /** Disconnect DOM resources and clear observations for the detached view. */
43
+ detach(): void;
44
+ /**
45
+ * Connect business policy without changing DOM listener ownership.
46
+ * @param events - business handlers for scroll and layout changes.
47
+ * @returns a disposer that disconnects only these handlers.
48
+ */
49
+ connect(events: ViewportEvents): () => void;
50
+ /**
51
+ * Adopt the loaded turn anchors without querying the DOM.
52
+ * @param turns - ordered loaded turns from the committed Chat snapshot.
53
+ */
54
+ updateTurns(turns: ReturnType<ChatSnapshot['navigation']['items']>): void;
55
+ /**
56
+ * Resolve the tail from the committed turn index.
57
+ * @returns the latest loaded turn, or null for an empty window.
58
+ */
59
+ get latestTurn(): number | null;
60
+ /** Discard geometry-dependent landing knowledge while retaining scroll attribution. */
61
+ invalidate(): void;
62
+ /**
63
+ * Accept a sampled reader position without retaining a known landing.
64
+ * @param metrics - settled reader position used as the next attribution baseline.
65
+ */
66
+ acknowledge(metrics: ViewportMetrics): void;
67
+ /**
68
+ * Compare the current scroll geometry with the last acknowledged position.
69
+ * @returns current metrics and movement attribution, or null while detached.
70
+ */
71
+ readScroll(): ViewportScroll | null;
72
+ private metrics;
73
+ private anchor;
74
+ /**
75
+ * Capture visible transcript content, excluding Turn controls that relocate when history expands.
76
+ * @returns a visible semantic anchor, or null when no anchor can be resolved.
77
+ */
78
+ capturePosition(): ChatScrollPosition | null;
79
+ /**
80
+ * Approximate the active Turn by binary-searching outer Node/Group boxes.
81
+ * Gaps retain the last visited Turn candidate, not necessarily the immediate predecessor.
82
+ * A known landing bypasses measurement while its position is unchanged.
83
+ * @param metrics - reusable scroll metrics; omitted callers request a fresh read.
84
+ * @returns the Turn near the reading line, or null while detached or empty.
85
+ */
86
+ readVisibleTurn(metrics?: ViewportMetrics | null): number | null;
87
+ /**
88
+ * Align a known loaded turn and return its actual clamped position.
89
+ * A split Node anchor selects its first visible part.
90
+ * @param turn - loaded turn to align below the scrollport's top edge.
91
+ * @returns the actual landing, or null when its anchor is unavailable.
92
+ */
93
+ scrollToTurn(turn: number): ViewportLanding | null;
94
+ /**
95
+ * Align the nearest available fallback for an unavailable turn anchor.
96
+ * @param turn - minimum turn number for a mounted fallback row.
97
+ * @returns the fallback landing, or null when no eligible row exists.
98
+ */
99
+ scrollToTurnAtOrAfter(turn: number): ViewportLanding | null;
100
+ /**
101
+ * Restore a semantic anchor with a raw-position fallback.
102
+ * @param position - semantic scroll memory; raw top is used only if its row is absent.
103
+ * @returns the actual landing, or null while detached.
104
+ */
105
+ restore(position: ChatScrollPosition): ViewportLanding | null;
106
+ /** Retain the first eligible transcript seat in DOM order; selection reads no geometry. */
107
+ beginPaging(): void;
108
+ /**
109
+ * Retain one old row and its inner/outer offsets for paging and later content growth.
110
+ * @param position - an explicit landing to retain; omitted callers capture the current reading position.
111
+ */
112
+ beginPreserving(position?: ChatScrollPosition | null): void;
113
+ private retain;
114
+ /** Release paging ownership and its content-size observation. */
115
+ stopPreserving(): void;
116
+ /**
117
+ * Expose retained paging ownership to navigation and resize policy.
118
+ * @returns whether a paging row is retained for subsequent layout changes.
119
+ */
120
+ get preserving(): boolean;
121
+ /**
122
+ * Compensate inner scrolling first, then the outer scrollport, within their actual scroll ranges.
123
+ * @returns the actual landing, or null when no visible retained row remains.
124
+ */
125
+ preserve(): ViewportLanding | null;
126
+ /**
127
+ * Align the scrollport with its current floor.
128
+ * @returns the actual floor landing, or null while detached.
129
+ */
130
+ scrollToBottom(): ViewportLanding | null;
131
+ private align;
132
+ private write;
133
+ private readonly onScroll;
134
+ private readonly onScrollEnd;
135
+ private readonly onIntent;
136
+ }
137
+ /**
138
+ * Bind viewport resource ownership to the component's layout lifetime.
139
+ * @returns one viewport owner and the element refs attached for this mount.
140
+ */
141
+ export declare function useChatViewport(): {
142
+ viewport: ChatViewport;
143
+ listRef: RefObject<HTMLDivElement>;
144
+ columnRef: RefObject<HTMLDivElement>;
145
+ };
146
+ export {};
147
+ //# sourceMappingURL=use-chat-viewport.d.ts.map
@@ -0,0 +1,15 @@
1
+ import type { ObservableSnapshot } from '@deepseek-ai/dsh-client-store';
2
+ import type { UseDisclosure } from '../contract/slots.ts';
3
+ /**
4
+ * Own one initially collapsed disclosure without an external subscription.
5
+ * @param version - reset generation; unchanged generations retain local open state.
6
+ * @returns the open state, an explicit setter, and a toggle action.
7
+ */
8
+ export declare function useDisclosure(version?: number): ReturnType<UseDisclosure>;
9
+ /**
10
+ * Bind a Hook without subscribing until a component calls it.
11
+ * @param reset - stable source whose version advances when the seat is hidden by its Turn.
12
+ * @returns a Hook with independent open state for each invocation.
13
+ */
14
+ export declare function bindDisclosure(reset: ObservableSnapshot<number>): UseDisclosure;
15
+ //# sourceMappingURL=use-disclosure.d.ts.map
@@ -76,8 +76,6 @@ export interface TurnTailChatData {
76
76
  readonly closing: FinalAssistantChatData | null;
77
77
  /** Whether non-rendered later evidence makes the closing seq non-tail. */
78
78
  readonly branchUnavailable: boolean;
79
- readonly ttftMs?: number;
80
- readonly tokensPerSecond?: number;
81
79
  /** Exact per-Turn accounting; absent when the loaded evidence is incomplete. */
82
80
  readonly tokenUsage?: TurnTokenUsage;
83
81
  }
@@ -0,0 +1,9 @@
1
+ /** Chat-only row visibility; durable events and trajectory inspection remain intact. */
2
+ import type { ChatNode } from './chat-nodes.ts';
3
+ /**
4
+ * Exclude system prompts, ordinary Context, and permission commands from visible Chat rows.
5
+ * @param node - projected Chat node.
6
+ * @returns whether the node contributes a visible Chat row.
7
+ */
8
+ export declare function isVisibleChatNode(node: ChatNode): boolean;
9
+ //# sourceMappingURL=chat-visibility.d.ts.map
@@ -0,0 +1,23 @@
1
+ /** Business data for Chat process groups; source Nodes remain in the Chat store. */
2
+ export type ProcessActivity = 'read' | 'search' | 'edit' | 'commands' | 'code' | 'webSearch' | 'webFetch' | 'subagents' | 'plan' | 'questions' | 'tools';
3
+ /** Distinct-call category ranking and the current live task detail. */
4
+ export interface ProcessActivitySummary {
5
+ readonly counts: readonly {
6
+ readonly kind: ProcessActivity;
7
+ readonly count: number;
8
+ }[];
9
+ readonly running: ProcessActivity | undefined;
10
+ readonly runningDetail: string;
11
+ }
12
+ /** Presentation facts for one group between independent replies or input. */
13
+ export interface ProcessGroupData {
14
+ readonly turn: number;
15
+ readonly closed: boolean;
16
+ readonly summary: ProcessActivitySummary;
17
+ }
18
+ declare module '@deepseek-ai/dsh-client-ui-conversation/client' {
19
+ interface ConversationGroupDataMap {
20
+ chat: ProcessGroupData;
21
+ }
22
+ }
23
+ //# sourceMappingURL=process-groups.d.ts.map
@@ -1,22 +1,29 @@
1
1
  /** Chat-owned Slot declarations and composed component props. */
2
2
  import type { MessageId } from '@deepseek-ai/dsh-llm/brand';
3
3
  import type { SessionId, SessionSeq } from '@deepseek-ai/dsh-session/types';
4
- import type { CommandNode, CompactionSummaryNode, ConversationLocationDataStore, ConversationTurnDataMap, MessageImageLoader, MessageImagesOwnerProps, RenderMessageImages, TurnLocation } from '@deepseek-ai/dsh-client-ui-conversation/client';
4
+ import type { CommandNode, CompactionSummaryNode, ConversationLocationDataStore, ConversationTurnDataMap, ConversationGroupData, GroupSnapshot, MessageImageLoader, MessageImagesOwnerProps, RenderMessageImages, TurnLocation } from '@deepseek-ai/dsh-client-ui-conversation/client';
5
5
  import type { InjectFace, KeyedSnapshotSelectorHook, PropsLocale, PropsRenderSlots, PropsRuntime, PropsStore, SlotHookFactory, SnapshotSelectorHook } from '@deepseek-ai/dsh-client-ui-slots';
6
- import type { SnapshotStore } from '@deepseek-ai/dsh-client-store';
6
+ import type { ObservableSnapshot } from '@deepseek-ai/dsh-client-store';
7
7
  import type { MarkdownFileMentions } from '@deepseek-ai/dsh-client-ui-primitives';
8
8
  import type { createChatStore } from '../stores.ts';
9
+ import type { ChatPresentationPolicy } from '../presentation-policy.ts';
9
10
  import type { ToolCallId } from './store.ts';
10
11
  import type { ChatConversationViewNode, ChatNode, ChatNodeKind } from './chat-nodes.ts';
11
12
  import type { ChatNodeProcessSource, ChatNodeSource, ChatSnapshot, ChatTurnProcessPresentation } from './snapshot.ts';
12
13
  import type { TurnProcessSpec } from './turn-process.ts';
13
- import type { TranscriptViewMode } from '../../chat-settings.ts';
14
+ import type { PerformanceUsageMode } from '../../chat-settings.ts';
14
15
  /** Selector hook over the current Conversation binding's Chat target. */
15
16
  export type UseChat = SnapshotSelectorHook<ChatSnapshot>;
16
17
  /** Per-key selector hook over one Chat Node. */
17
18
  export type UseChatNode = KeyedSnapshotSelectorHook<ChatConversationViewNode | undefined>;
18
19
  /** Per-key selector hook over one Chat Node's Turn-process presentation. */
19
20
  export type UseChatNodeProcess = KeyedSnapshotSelectorHook<ChatTurnProcessPresentation | undefined>;
21
+ /**
22
+ * Selector hook over the live presentation policy. Callers select one field or
23
+ * a derived conclusion, never the whole policy, so a mode change re-renders
24
+ * only components whose selected value changed.
25
+ */
26
+ export type UsePresentation = SnapshotSelectorHook<ChatPresentationPolicy>;
20
27
  /** Where in a file an open should land. */
21
28
  export interface OpenFileOptions {
22
29
  /** 1-based line to reveal; absent = the file's beginning. */
@@ -50,19 +57,38 @@ declare module '@deepseek-ai/cordis' {
50
57
  }
51
58
  /** Hook constrained to business data published on the current Chat Node's Turn. */
52
59
  export type UseChatNodeTurnData = <Key extends Extract<keyof ConversationTurnDataMap, string>>(key: Key) => Readonly<ConversationTurnDataMap[Key]> | undefined;
53
- /** Slot-level Hook factory for keyed Chat renderers. */
54
- export interface ChatNodeTurnDataInjected {
60
+ /**
61
+ * Subscribe to enclosing-Turn resets and own one initially collapsed disclosure.
62
+ * Each invocation has independent open state; display-mode changes do not reset it.
63
+ * @returns the current open state, explicit setter, and toggle action.
64
+ */
65
+ export type UseDisclosure = () => {
66
+ readonly expanded: boolean;
67
+ /** @param open - whether this disclosure is expanded. */
68
+ readonly setExpanded: (open: boolean) => void;
69
+ readonly toggle: () => void;
70
+ };
71
+ /** Stable sources bound to one rendered Chat Node. */
72
+ export interface ChatNodeHookContext {
73
+ readonly turnData: ConversationLocationDataStore<ConversationTurnDataMap> | undefined;
74
+ readonly disclosureReset: ObservableSnapshot<number>;
75
+ }
76
+ /** Slot-level Hook factories for keyed Chat renderers. */
77
+ export interface ChatNodeInjected {
55
78
  hooks: {
56
79
  turnData: SlotHookFactory<'conversation.chat.node', UseChatNodeTurnData>;
80
+ disclosure: SlotHookFactory<'conversation.chat.node', UseDisclosure>;
57
81
  };
58
82
  }
59
83
  /** Stable owner currency delivered to a keyed Chat renderer. */
60
84
  export interface ChatNodeOwnerProps {
85
+ /** Renderer-owned Node portion selected by the grouping Definition. */
86
+ groupPart?: string;
61
87
  cwd?: string | undefined;
62
88
  /** Open the current source file of a skill referenced by a sent message. */
63
89
  openSkill: (name: string) => void;
64
90
  openFile: (path: string, options?: OpenFileOptions) => void;
65
- inspectCall: (callId: ToolCallId) => void;
91
+ inspectCall: ((callId: ToolCallId) => void) | undefined;
66
92
  forkAt: (seq: number) => void;
67
93
  /**
68
94
  * Session-authorized image loader, down-threaded from the Chat view so a
@@ -78,11 +104,20 @@ export interface ChatNodeOwnerProps {
78
104
  }
79
105
  /** Shared presentation state for one Turn-process answer generation. */
80
106
  export interface TurnProcessOwnerProps {
107
+ /** Process content eligible to share one Turn-level disclosure. */
108
+ readonly hasContent: boolean;
81
109
  readonly spec: TurnProcessSpec;
82
110
  readonly foldable: boolean;
83
111
  readonly open: boolean;
84
112
  setOpen(open: boolean): void;
85
113
  }
114
+ /** Shared presentation policy source for renderers that depend on the work-details mode. */
115
+ export interface PresentationInjected {
116
+ hooks: {
117
+ /** Live presentation policy derived from the accepted work-details mode. */
118
+ presentation: ObservableSnapshot<ChatPresentationPolicy>;
119
+ };
120
+ }
86
121
  /** Full props of one keyed Chat renderer. */
87
122
  export type ChatNodeViewProps<Kind extends ChatNodeKind = ChatNodeKind> = PropsRuntime<'conversation.chat.node', Kind> & PropsLocale<'chat'>;
88
123
  /** Command-row owner share. */
@@ -100,21 +135,30 @@ export interface ChatScrollPosition {
100
135
  readonly anchorTop: number;
101
136
  readonly scrollTop: number;
102
137
  }
138
+ /** Shared settings source for the performance row, composer, and turn tail. */
139
+ export interface PerformanceUsageInjected {
140
+ hooks: {
141
+ /** Accepted performance and usage detail preference. */
142
+ performanceUsage: ObservableSnapshot<PerformanceUsageMode>;
143
+ };
144
+ }
103
145
  /** Business callbacks injected into the Chat view. */
104
146
  export interface ChatViewInjected {
105
147
  hooks: {
106
- /** Persisted completed-Turn transcript presentation. */
107
- transcriptView: SnapshotStore<TranscriptViewMode>;
148
+ /** Live presentation policy derived from the accepted work-details mode. */
149
+ presentation: ObservableSnapshot<ChatPresentationPolicy>;
108
150
  };
109
151
  keyedHooks: {
110
152
  /** Resolve the stable source for one Chat Node key. */
111
153
  chatNode: (key: string) => ChatNodeSource;
112
154
  /** Resolve the stable Turn-process source for one Chat Node key. */
113
155
  chatNodeProcess: (key: string) => ChatNodeProcessSource;
156
+ /** Resolve one optional group without subscribing the root View to its data. */
157
+ chatGroup: (key: string) => ObservableSnapshot<GroupSnapshot<ConversationGroupData<'chat'>> | undefined> | undefined;
114
158
  };
115
159
  /** Open the current source file of a skill referenced by a sent message. */
116
160
  openSkill: (name: string) => void;
117
- /** Open one HTTP(S) message link in a Sidebar Browser tab. */
161
+ /** Open one HTTP(S) message link at the selected destination, using an external tab if Sidebar Browser is unavailable. */
118
162
  openExternalLink: (url: string) => void;
119
163
  openFile: (path: string, options?: OpenFileOptions) => Promise<void>;
120
164
  loadOlder: () => void;
@@ -156,8 +200,8 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
156
200
  node: ChatNode<Kind>;
157
201
  };
158
202
  };
159
- hookContext: ConversationLocationDataStore<ConversationTurnDataMap> | undefined;
160
- inject: ChatNodeTurnDataInjected;
203
+ hookContext: ChatNodeHookContext;
204
+ inject: ChatNodeInjected;
161
205
  };
162
206
  /**
163
207
  * Renderer for one consecutive group of durable message images. The owner
@@ -1,5 +1,6 @@
1
1
  import type { ConversationNode, ConversationTimelineSnapshot, PartialAssistant, RunningToolCall } from '@deepseek-ai/dsh-client-ui-conversation/client';
2
- import type { ChatConversationViewNode } from './chat-nodes.ts';
2
+ import type { ChatConversationViewNode, ChatNodeDataMap, ChatNodeKind } from './chat-nodes.ts';
3
+ import type { ObservableSnapshot } from '@deepseek-ai/dsh-client-store';
3
4
  import type { TurnProcessSpec } from './turn-process.ts';
4
5
  export type { AssistantBlock, AssistantMessageNode, AssistantProviderMetadataView, AssistantRequestConfig, AssistantTiming, CommandNode, CompactionSummaryNode, ContextMessageNode, ConversationNode, ModelRetryNode, PartialAssistant, RunningToolCall, SteeringMessageNode, TodoItem, ToolCallBlock, ToolResultNode, TurnErrorNode, TurnMaxTokensNode, UnknownSurfaceNode, UserMessageNode, } from '@deepseek-ai/dsh-client-ui-conversation/client';
5
6
  /** Per-key observable used by one mounted Chat Node Seat. */
@@ -22,6 +23,14 @@ export interface ChatNodeStore {
22
23
  get(key: string): ChatConversationViewNode | undefined;
23
24
  /** @param key - stable Conversation Context key. @returns its identity-stable observable source. */
24
25
  source(key: string): ChatNodeSource;
26
+ /**
27
+ * Observe one Turn's data for a single Node kind, including hidden Nodes, in anchor order.
28
+ * Other Turns and kinds do not notify this source.
29
+ * @param turn - resolved owning Turn.
30
+ * @param kind - business Node kind.
31
+ * @returns an identity-stable source whose array changes only with its members.
32
+ */
33
+ turnDataSource<Kind extends ChatNodeKind>(turn: number, kind: Kind): ObservableSnapshot<readonly ChatNodeDataMap[Kind][]>;
25
34
  /** @param key - stable Conversation Context key. @returns its Turn-process presentation source. */
26
35
  processSource(key: string): ChatNodeProcessSource;
27
36
  /** @returns all currently materialized Nodes without imposing render order. */
@@ -58,8 +67,12 @@ export interface ChatLocationNodeIndex {
58
67
  export interface ChatTurnProcessPresentation {
59
68
  readonly turn: number;
60
69
  readonly spec: TurnProcessSpec;
70
+ /** Whether the loaded window contains this Turn's `turn/start`; folding is decided per Turn on this fact. */
71
+ readonly turnStarted: boolean;
61
72
  readonly turnClosed: boolean;
62
73
  readonly hasExternalProcess: boolean;
74
+ /** A visible input after process output prevents one disclosure from hiding its surrounding groups. */
75
+ readonly hasInterleavedInput: boolean;
63
76
  readonly compactAnswer: boolean;
64
77
  }
65
78
  /** Compatibility projection backing StatsPills and the legacy top-level snapshot fields. */
@@ -1,11 +1,4 @@
1
- import type { AssistantMessageNode, ConversationNode } from '@deepseek-ai/dsh-client-ui-conversation/client';
2
- /** Latency and decode-throughput readings for one turn's footer. */
3
- export interface TurnMetrics {
4
- /** First-step TTFT in ms; absent when that step carries no recorded timing. */
5
- ttftMs?: number;
6
- /** Decode throughput over steps carrying both timing and provider usage. */
7
- tokensPerSecond?: number;
8
- }
1
+ import type { AssistantMessageNode } from '@deepseek-ai/dsh-client-ui-conversation/client';
9
2
  /** One assistant step's derivable latency facts; null marks an unrecorded part. */
10
3
  export interface StepReading {
11
4
  /** step/start → first token delta, in ms. */
@@ -22,17 +15,5 @@ type AssistantNode = AssistantMessageNode;
22
15
  * @returns Per-part readings with `null` for unrecorded values.
23
16
  */
24
17
  export declare function assistantStepReading(node: AssistantNode): StepReading;
25
- /**
26
- * Fold assistant nodes into per-turn footer metrics.
27
- *
28
- * TTFT is the turn's lowest-step request-dispatch-to-first-token reading, so
29
- * it is only meaningful when the turn's start is inside
30
- * the loaded window (the caller gates on `turnTimings`, which shares that
31
- * window). Throughput divides summed output tokens by summed decode wall time,
32
- * counting only steps that carry both.
33
- * @param nodes - Snapshot nodes of the loaded window.
34
- * @returns Turn number → available metrics; turns with none are absent.
35
- */
36
- export declare function deriveTurnMetrics(nodes: readonly ConversationNode[]): Map<number, TurnMetrics>;
37
18
  export {};
38
19
  //# sourceMappingURL=turn-metrics.d.ts.map
@@ -1,3 +1,4 @@
1
+ import type { ChatNode } from './chat-nodes.ts';
1
2
  /** Current process range and finalized answer boundary derived from one Turn. */
2
3
  export interface TurnProcessSpec {
3
4
  readonly turn: number;
@@ -30,4 +31,10 @@ export declare function sameTurnProcessSpec(left: TurnProcessSpec, right: TurnPr
30
31
  * @returns whether the call creates or forks a subagent.
31
32
  */
32
33
  export declare function isSubagentDelegationTool(name: string): boolean;
34
+ /**
35
+ * Keep live, stopped, and failed Turns open.
36
+ * @param node - Node carrying the owning Turn.
37
+ * @returns whether whole-Turn collapse is unavailable.
38
+ */
39
+ export declare function turnProcessAlwaysOpen(node: ChatNode | undefined): boolean;
33
40
  //# sourceMappingURL=turn-process.d.ts.map
@@ -21,11 +21,10 @@ interface AssistantState {
21
21
  readonly firstVisibleSeq: number | undefined;
22
22
  readonly firstVisibleTime: number | undefined;
23
23
  readonly firstTokenTime: number | undefined;
24
- readonly hidden: boolean;
25
24
  readonly final: ConversationMatch | undefined;
26
25
  readonly usage: unknown;
27
26
  }
28
- /** Per-step Assistant streaming/final/interruption Definition. */
27
+ /** Per-step Assistant lifecycle; materialized keys survive cleared stream content as hidden Nodes. */
29
28
  export declare const assistantDefinition: ConversationNodeDefinition<AssistantState>;
30
29
  /**
31
30
  * Register the Assistant lifecycle business contribution.
@@ -1,10 +1,10 @@
1
1
  import type { Context } from '@deepseek-ai/cordis';
2
- import type { ConversationTimelineSnapshot, ConversationViewBuilder, ConversationViewDefinition } from '@deepseek-ai/dsh-client-ui-conversation/client';
2
+ import type { ConversationTimelineSnapshot, ConversationViewBuilder, ConversationViewDefinition, ConversationGroupInput } from '@deepseek-ai/dsh-client-ui-conversation/client';
3
3
  import type { ChatConversationViewNode } from '../contract/chat-nodes.ts';
4
4
  import type { ChatNodeStore, ChatSnapshot } from '../contract/snapshot.ts';
5
5
  /**
6
6
  * Order visible Chat Nodes without changing existing relative order as process
7
- * eligibility changes. Opening human input precedes process candidates, while
7
+ * eligibility changes. Opening input precedes process candidates, while
8
8
  * each synthetic process control sits between them.
9
9
  * @param nodes - currently materialized Chat Nodes.
10
10
  * @returns visible Nodes in presentation order.
@@ -72,6 +72,10 @@ export declare class ChatSnapshotBuilder implements ConversationViewBuilder<Chat
72
72
  private readonly referenceLabels;
73
73
  private readonly skillNames;
74
74
  private order;
75
+ private latestGroupInput;
76
+ private readonly readGroupNode;
77
+ private readonly readGroupTurn;
78
+ private readonly readGroupPosition;
75
79
  /** Last published timeline: a Turn boundary can land without a new node. */
76
80
  private timeline;
77
81
  readonly empty: ChatSnapshot;
@@ -83,7 +87,10 @@ export declare class ChatSnapshotBuilder implements ConversationViewBuilder<Chat
83
87
  apply(input: {
84
88
  readonly upserts: readonly ChatConversationViewNode[];
85
89
  readonly timeline: ConversationTimelineSnapshot;
90
+ readonly changedTurns?: readonly number[];
86
91
  }): ChatSnapshot;
92
+ groupInput(): ConversationGroupInput<ChatConversationViewNode>;
93
+ publish(): void;
87
94
  private snapshot;
88
95
  }
89
96
  /** Chat target factory contributed to the Conversation view registry. */
@@ -1,28 +1,38 @@
1
1
  import type { Context } from '@deepseek-ai/cordis';
2
2
  import type { ConversationNodeDefinition } from '@deepseek-ai/dsh-client-ui-conversation/client';
3
+ interface InboxIdentity {
4
+ readonly id: string;
5
+ readonly source: {
6
+ readonly kind: string;
7
+ };
8
+ }
3
9
  interface PendingSnapshot {
4
10
  readonly kind: 'snapshot';
5
- readonly ids: readonly string[];
11
+ readonly ids: readonly InboxIdentity[];
6
12
  }
7
13
  interface PendingSplice {
8
14
  readonly kind: 'splice';
9
15
  readonly previous: PendingState;
10
16
  readonly start: number;
11
17
  readonly removedCount: number;
12
- readonly inserted: readonly string[];
18
+ readonly inserted: readonly InboxIdentity[];
13
19
  }
14
20
  type PendingState = PendingSnapshot | PendingSplice;
15
- /** Persistent next-step state after one durable Inbox splice. */
21
+ /** Persistent Inbox state after one durable Inbox splice. */
16
22
  export interface InboxState {
17
- /** Persistent splice chain materialized only when a next-step batch is claimed. */
23
+ /** Persistent splice chain materialized only when a batch is claimed. */
18
24
  readonly pending: PendingState;
19
25
  /** Message ids in the current claim, shared until the next claim. */
20
26
  readonly currentClaimed: ReadonlySet<string>;
27
+ readonly claimSeq: number;
28
+ readonly claimedHuman: boolean;
21
29
  }
22
- /** Persistent next-step Inbox state used to classify the current claimed batch as steering. */
30
+ /** Persistent next-step claims identify messages admitted into a running Turn. */
23
31
  export declare const nextStepInboxDefinition: ConversationNodeDefinition<InboxState>;
32
+ /** Persistent next-turn claims identify messages that wake a new Turn. */
33
+ export declare const nextTurnInboxDefinition: ConversationNodeDefinition<InboxState>;
24
34
  /**
25
- * Register the next-step Inbox state used by Chat message classification.
35
+ * Register the Inbox state used by Chat message classification.
26
36
  * @param ctx - owning UI Conversation context.
27
37
  */
28
38
  export declare function registerInboxConversationNodes(ctx: Context): void;