@huanlin/dsh-focus-chat 0.1.23
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.
- package/README.md +73 -0
- package/README.zh.md +71 -0
- package/cordis.patch.yml +7 -0
- package/lib/client.js +6051 -0
- package/lib/index.js +6 -0
- package/lib/types/client/apply.d.ts +12 -0
- package/lib/types/client/contract/props.d.ts +78 -0
- package/lib/types/client/index.d.ts +10 -0
- package/lib/types/client/locales.d.ts +437 -0
- package/lib/types/client/model/feedback-controller.d.ts +161 -0
- package/lib/types/client/model/flow.d.ts +76 -0
- package/lib/types/client/model/index.d.ts +5 -0
- package/lib/types/client/model/text.d.ts +42 -0
- package/lib/types/client/model/todo.d.ts +38 -0
- package/lib/types/client/model/tools.d.ts +35 -0
- package/lib/types/client/model/turn-slice.d.ts +38 -0
- package/lib/types/client/model/types.d.ts +289 -0
- package/lib/types/client/view/FocusView.d.ts +9 -0
- package/lib/types/client/view/chrome/ImageLightbox.d.ts +26 -0
- package/lib/types/client/view/chrome/MessageActions.d.ts +24 -0
- package/lib/types/client/view/chrome/MessageFeedbackActions.d.ts +46 -0
- package/lib/types/client/view/chrome/MessageImage.d.ts +46 -0
- package/lib/types/client/view/chrome/NavRail.d.ts +21 -0
- package/lib/types/client/view/chrome/ReferenceIcon.d.ts +17 -0
- package/lib/types/client/view/chrome/RunningStatus.d.ts +7 -0
- package/lib/types/client/view/chrome/TurnNavigator.d.ts +14 -0
- package/lib/types/client/view/helpers/format.d.ts +30 -0
- package/lib/types/client/view/helpers/icons.d.ts +9 -0
- package/lib/types/client/view/helpers/image-labels.d.ts +13 -0
- package/lib/types/client/view/helpers/message.d.ts +13 -0
- package/lib/types/client/view/helpers/terminal.d.ts +20 -0
- package/lib/types/client/view/rows/CommandRow.d.ts +12 -0
- package/lib/types/client/view/rows/CompactionRow.d.ts +24 -0
- package/lib/types/client/view/rows/ContextRow.d.ts +22 -0
- package/lib/types/client/view/rows/FlowRow.d.ts +20 -0
- package/lib/types/client/view/rows/RemoteTurnRow.d.ts +33 -0
- package/lib/types/client/view/rows/RetryRow.d.ts +10 -0
- package/lib/types/client/view/rows/SystemPromptRow.d.ts +12 -0
- package/lib/types/client/view/rows/ThinkRow.d.ts +16 -0
- package/lib/types/client/view/rows/ToolCallRow.d.ts +8 -0
- package/lib/types/client/view/rows/ToolGroupRow.d.ts +11 -0
- package/lib/types/client/view/rows/TurnFoldRow.d.ts +27 -0
- package/lib/types/client/view/rows/TurnTailRow.d.ts +16 -0
- package/lib/types/client/view/rows/TurnUsageDisclosure.d.ts +9 -0
- package/lib/types/client/view/rows/UserBubble.d.ts +18 -0
- package/lib/types/client/view/rows/group-title.d.ts +32 -0
- package/lib/types/client/view/rows/produced-fit.d.ts +14 -0
- package/lib/types/host/rpc.d.ts +63 -0
- package/lib/types/host/turn-index.d.ts +40 -0
- package/lib/types/index.d.ts +3 -0
- package/lib/types/protocol.d.ts +94 -0
- package/package.json +109 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/** Pure type face of the focus flow model (React-free). */
|
|
2
|
+
import type { DiffHunk, ReadBlockLine, SearchBlockProps, WebBlockProps } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
3
|
+
import type { ContentBlock } from '@deepseek-ai/dsh-llm/types';
|
|
4
|
+
import type { AssistantBlock, ChatNodeDataMap, ContextMessageNode } from '@deepseek-ai/dsh-client-ui-chat/client';
|
|
5
|
+
import type { TurnTokenUsage } from '@deepseek-ai/dsh-client-ui-chat/src/client/contract/chat-nodes.ts';
|
|
6
|
+
/** Locale-owned label surfaces the render sites add to the shared card primitives. */
|
|
7
|
+
type DistributiveOmit<T, K extends keyof T> = T extends unknown ? Omit<T, K> : never;
|
|
8
|
+
/** Search-card data the model owns; render adds `labels`/`maxLines`/`className`. */
|
|
9
|
+
export type FocusSearchBlockProps = DistributiveOmit<SearchBlockProps, 'labels' | 'maxLines' | 'className'>;
|
|
10
|
+
/** Web-card data the model owns; render adds `labels`/`className`. */
|
|
11
|
+
export type FocusWebBlockProps = DistributiveOmit<WebBlockProps, 'labels' | 'className'>;
|
|
12
|
+
export type FocusCard = {
|
|
13
|
+
kind: 'terminal';
|
|
14
|
+
command: string;
|
|
15
|
+
cwd: string | undefined;
|
|
16
|
+
output: string | undefined;
|
|
17
|
+
exitCode: number | undefined;
|
|
18
|
+
signal: string | undefined;
|
|
19
|
+
running: boolean;
|
|
20
|
+
description: string | undefined;
|
|
21
|
+
} | {
|
|
22
|
+
kind: 'diff';
|
|
23
|
+
diffs: DiffHunk[];
|
|
24
|
+
} | {
|
|
25
|
+
kind: 'read';
|
|
26
|
+
label: string;
|
|
27
|
+
lines: ReadBlockLine[];
|
|
28
|
+
totalLines: number;
|
|
29
|
+
lang: string | undefined;
|
|
30
|
+
} | {
|
|
31
|
+
kind: 'search';
|
|
32
|
+
props: FocusSearchBlockProps;
|
|
33
|
+
recovery: string | undefined;
|
|
34
|
+
} | {
|
|
35
|
+
kind: 'web';
|
|
36
|
+
props: FocusWebBlockProps;
|
|
37
|
+
};
|
|
38
|
+
/** Tool-row state semantics; colors self-supplied by the view. */
|
|
39
|
+
export type FocusToolState = 'running' | 'ok' | 'error' | 'stopped';
|
|
40
|
+
/** Tool-call row variants selected by the generic renderer (the chat table). */
|
|
41
|
+
export type FocusToolVariant = 'search' | 'read' | 'bash' | 'write' | 'edit' | 'code' | 'question' | 'todo' | 'skill' | 'others';
|
|
42
|
+
/** One Tool call's condensed row model, derived from the frozen block. */
|
|
43
|
+
export interface FocusToolRow {
|
|
44
|
+
callId: string;
|
|
45
|
+
/** Wire Tool name ('' when the window dropped the call head). */
|
|
46
|
+
name: string;
|
|
47
|
+
/** Row variant (the chat row's classification). */
|
|
48
|
+
variant: FocusToolVariant;
|
|
49
|
+
/** Row title: the tool-owned or variant design literal (the chat row's). */
|
|
50
|
+
title: string;
|
|
51
|
+
/** Args-derived one-line summary (falls back to the call id). */
|
|
52
|
+
summary: string;
|
|
53
|
+
/** Filesystem path from args for single-file tools; undefined otherwise. */
|
|
54
|
+
filePath: string | undefined;
|
|
55
|
+
state: FocusToolState;
|
|
56
|
+
/** Flattened result text; null while running or when the result has none. */
|
|
57
|
+
output: string | null;
|
|
58
|
+
/** First result line on an error row; null otherwise. */
|
|
59
|
+
errorSummary: string | null;
|
|
60
|
+
/** Settled call's structured error code; null while running or when the
|
|
61
|
+
* result carries no error (the ask-question row's verdict codes). */
|
|
62
|
+
errorCode: string | null;
|
|
63
|
+
/** Call start wall-clock time; null once settled. The view's live-row
|
|
64
|
+
* debounce reads it (a young running call paints nothing). */
|
|
65
|
+
time: number | null;
|
|
66
|
+
/** Expanded-body input text (pretty args); null = no input section. */
|
|
67
|
+
body: string | null;
|
|
68
|
+
/** Card render material from the host-computed views; null = generic sections. */
|
|
69
|
+
card: FocusCard | null;
|
|
70
|
+
/** Recursive child rows (the sub-call tree), in dispatch order. */
|
|
71
|
+
subcalls: readonly FocusToolRow[];
|
|
72
|
+
}
|
|
73
|
+
/** One reasoning row absorbed into a tool group (the chat Think disclosure). */
|
|
74
|
+
export interface FocusGroupThink {
|
|
75
|
+
/** Complete or streaming reasoning text. */
|
|
76
|
+
text: string;
|
|
77
|
+
/** Whether the reasoning is still the streaming tail (sweep + tail preview). */
|
|
78
|
+
running: boolean;
|
|
79
|
+
}
|
|
80
|
+
/** One folded row inside a tool group: an absorbed context row, an absorbed
|
|
81
|
+
* Think row, or a call. */
|
|
82
|
+
export type FocusGroupItem = FocusContextItem | FocusGroupThink | FocusToolRow;
|
|
83
|
+
/** Step-summary metric families the group line aggregates, in display order. */
|
|
84
|
+
export type FocusMetricKey = 'commands' | 'edits' | 'searches' | 'files' | 'dirs' | 'subagents' | 'todos' | 'goals' | 'workflows' | 'skills' | 'questions' | 'plans' | 'jobs';
|
|
85
|
+
/** Tool name → metric family; unknown tools carry no metric. Writes fold
|
|
86
|
+
* into the edit family (the summary line reads one "edited" segment); the
|
|
87
|
+
* agentic families (delegation, todo, goal, workflow, skill, question,
|
|
88
|
+
* plan) replace the generic "called N tools" remainder for their own tools. */
|
|
89
|
+
export interface FocusGroupMetrics {
|
|
90
|
+
commands: number;
|
|
91
|
+
edits: number;
|
|
92
|
+
searches: number;
|
|
93
|
+
files: number;
|
|
94
|
+
dirs: number;
|
|
95
|
+
/** Delegation calls (subagent / subagent_fork): "forked N subagents". */
|
|
96
|
+
subagents: number;
|
|
97
|
+
/** Todo mutations (todo_write): "更新了待办 / updated todos". */
|
|
98
|
+
todos: number;
|
|
99
|
+
/** Goal mutations (create/update/get_goal): "更新了目标 / updated goals". */
|
|
100
|
+
goals: number;
|
|
101
|
+
/** Orchestration calls (workflow / ralph): "ran N workflows". */
|
|
102
|
+
workflows: number;
|
|
103
|
+
/** Skill loads (skill): "loaded N skills". */
|
|
104
|
+
skills: number;
|
|
105
|
+
/** User questions (ask_user_question): "asked N questions". */
|
|
106
|
+
questions: number;
|
|
107
|
+
/** Plan-mode entries (plan): "planned N times". */
|
|
108
|
+
plans: number;
|
|
109
|
+
/** Background-job activity (job_output / job_kill / job_list calls and the
|
|
110
|
+
* tool-jobs settlements a `notice` context injection carries): the summary
|
|
111
|
+
* line reads "N background jobs" — the settlement's own one-line account
|
|
112
|
+
* no longer rides the line verbatim. */
|
|
113
|
+
jobs: number;
|
|
114
|
+
/** Failed calls in the failure-aware families (error-state rows): command
|
|
115
|
+
* execution and other tools. File operations never carry a failure tally —
|
|
116
|
+
* the edit family's count is the outcome (distinct files actually edited). */
|
|
117
|
+
commandsFailed: number;
|
|
118
|
+
searchesFailed: number;
|
|
119
|
+
}
|
|
120
|
+
/** One focus-mode group: the consecutive root calls folded into a summary line. */
|
|
121
|
+
export interface FocusToolGroup {
|
|
122
|
+
/** Chat node keys of the folded roots, in flow order. */
|
|
123
|
+
nodeKeys: readonly string[];
|
|
124
|
+
/** Folded rows in flow order: the absorbed context rows, Think rows, and the calls. */
|
|
125
|
+
items: readonly FocusGroupItem[];
|
|
126
|
+
/** Whether any folded call is still running. */
|
|
127
|
+
running: boolean;
|
|
128
|
+
/** Per-family call counts, with failure tallies for the failure-aware families. */
|
|
129
|
+
metrics: FocusGroupMetrics;
|
|
130
|
+
/** Context injections directly preceding the run, absorbed into the group. */
|
|
131
|
+
contextCount: number;
|
|
132
|
+
context: readonly FocusContextItem[];
|
|
133
|
+
/**
|
|
134
|
+
* Thinking time of the runs folded into this group, summed when every run
|
|
135
|
+
* carries timing (the group merges directly-consecutive runs); null when
|
|
136
|
+
* unavailable.
|
|
137
|
+
*/
|
|
138
|
+
thoughtMs: number | null;
|
|
139
|
+
}
|
|
140
|
+
/** One context-injection message row (the chat ContextInjectionRow chrome). */
|
|
141
|
+
export type FocusContextItem = Extract<FocusFlowItem, {
|
|
142
|
+
kind: 'message';
|
|
143
|
+
}> & {
|
|
144
|
+
role: 'context';
|
|
145
|
+
};
|
|
146
|
+
/** One condensed flow row; the view dispatches on `kind`. */
|
|
147
|
+
export type FocusFlowItem = {
|
|
148
|
+
kind: 'message';
|
|
149
|
+
nodeKey: string;
|
|
150
|
+
role: 'user' | 'steering' | 'context';
|
|
151
|
+
content: readonly ContentBlock[];
|
|
152
|
+
time: number;
|
|
153
|
+
/** Context-injection chrome (the chat ContextInjectionRow); absent for user/steering. */
|
|
154
|
+
context?: {
|
|
155
|
+
source: ContextMessageNode['source'];
|
|
156
|
+
provenance: ContextMessageNode['provenance'];
|
|
157
|
+
form: ContextMessageNode['form'];
|
|
158
|
+
};
|
|
159
|
+
} | {
|
|
160
|
+
/**
|
|
161
|
+
* One running turn's context batch: consecutive context injections
|
|
162
|
+
* folded into a single line while the turn is open (a completed turn
|
|
163
|
+
* folds them individually into the turn fold instead).
|
|
164
|
+
*/
|
|
165
|
+
kind: 'context-fold';
|
|
166
|
+
nodeKey: string;
|
|
167
|
+
turn: number | null;
|
|
168
|
+
/** The merged context messages, in flow order. */
|
|
169
|
+
items: readonly FocusContextItem[];
|
|
170
|
+
} | {
|
|
171
|
+
kind: 'assistant';
|
|
172
|
+
nodeKey: string;
|
|
173
|
+
/** Remaining blocks; reasoning absorbed into a directly-following tool group is filtered out. */
|
|
174
|
+
blocks: readonly AssistantBlock[];
|
|
175
|
+
running: boolean;
|
|
176
|
+
interrupted: boolean;
|
|
177
|
+
thoughtMs: number | null;
|
|
178
|
+
/** Settled assistant seq; null while streaming. */
|
|
179
|
+
finalSeq: number | null;
|
|
180
|
+
} | {
|
|
181
|
+
kind: 'tools';
|
|
182
|
+
group: FocusToolGroup;
|
|
183
|
+
} | {
|
|
184
|
+
kind: 'system-prompt';
|
|
185
|
+
nodeKey: string;
|
|
186
|
+
/** Complete model-visible prompt text. */
|
|
187
|
+
text: string;
|
|
188
|
+
} | {
|
|
189
|
+
kind: 'turn-fold';
|
|
190
|
+
nodeKey: string;
|
|
191
|
+
turn: number;
|
|
192
|
+
/** Turn wall time (start → end); the "工作了 X 分 Y 秒" reading. */
|
|
193
|
+
durationMs: number;
|
|
194
|
+
/** The user stopped the turn: the line reads "用户 X 后停止" instead. */
|
|
195
|
+
stopped: boolean;
|
|
196
|
+
/** Turn-process counts (the official turn fold's measurement): durable
|
|
197
|
+
* messages, tool calls, and subagent delegations in the folded turn. */
|
|
198
|
+
messageCount: number;
|
|
199
|
+
toolCallCount: number;
|
|
200
|
+
subagentCount: number;
|
|
201
|
+
/** The turn's folded rows — intermediate assistant items and tool runs — in flow order. */
|
|
202
|
+
items: readonly FocusFlowItem[];
|
|
203
|
+
} | {
|
|
204
|
+
kind: 'turn-tail';
|
|
205
|
+
nodeKey: string;
|
|
206
|
+
turn: number;
|
|
207
|
+
/** Closing assistant seq — the fork anchor; null when the turn ended without one. */
|
|
208
|
+
closingSeq: number | null;
|
|
209
|
+
/** Durable identity of the closing assistant message; null when the turn
|
|
210
|
+
* ended without one (interruption-frozen partial). */
|
|
211
|
+
closingMessageId: string | null;
|
|
212
|
+
/** Closing assistant time (the actions clock). */
|
|
213
|
+
closingTime: number | null;
|
|
214
|
+
/** Text of the closing assistant (the copy source). */
|
|
215
|
+
closingText: string;
|
|
216
|
+
/** Turn wall time for the `· Ran for Ns` reading. */
|
|
217
|
+
runMs: number | null;
|
|
218
|
+
/** Turn first-step TTFT in ms, when recorded. */
|
|
219
|
+
ttftMs: number | null;
|
|
220
|
+
/** Turn decode throughput, when recorded. */
|
|
221
|
+
tokensPerSecond: number | null;
|
|
222
|
+
/** Whether fork is unavailable (engine-computed; mirrors the chat tail). */
|
|
223
|
+
branchUnavailable: boolean;
|
|
224
|
+
/** Files produced by the closing turn, in first-seen order. */
|
|
225
|
+
produced: readonly string[];
|
|
226
|
+
/** Exact provider-reported token accounting, when the turn recorded it. */
|
|
227
|
+
tokenUsage: TurnTokenUsage | undefined;
|
|
228
|
+
} | {
|
|
229
|
+
kind: 'command';
|
|
230
|
+
nodeKey: string;
|
|
231
|
+
name: string | null;
|
|
232
|
+
args: string | null;
|
|
233
|
+
outcomeText: string | null;
|
|
234
|
+
outcomeError: boolean;
|
|
235
|
+
running: boolean;
|
|
236
|
+
} | {
|
|
237
|
+
kind: 'manual-compaction';
|
|
238
|
+
nodeKey: string;
|
|
239
|
+
name: string | null;
|
|
240
|
+
outcomeText: string | null;
|
|
241
|
+
outcomeError: boolean;
|
|
242
|
+
running: boolean;
|
|
243
|
+
compaction: {
|
|
244
|
+
summary: string | null;
|
|
245
|
+
shadowedItemCount: number | null;
|
|
246
|
+
shadowedTokenCount: number | null;
|
|
247
|
+
} | null;
|
|
248
|
+
} | {
|
|
249
|
+
kind: 'compaction';
|
|
250
|
+
nodeKey: string;
|
|
251
|
+
summary: string | null;
|
|
252
|
+
shadowedItemCount: number | null;
|
|
253
|
+
shadowedTokenCount: number | null;
|
|
254
|
+
} | {
|
|
255
|
+
kind: 'retry';
|
|
256
|
+
nodeKey: string;
|
|
257
|
+
delayMs: number;
|
|
258
|
+
retry: number;
|
|
259
|
+
/** 'always' retries never exhaust; the chat row shows ∞. */
|
|
260
|
+
maxRetries: number | null;
|
|
261
|
+
mode: 'normal' | 'always';
|
|
262
|
+
retryState: 'scheduled' | 'started' | 'cancelled';
|
|
263
|
+
failure: {
|
|
264
|
+
message: string;
|
|
265
|
+
} | null;
|
|
266
|
+
} | {
|
|
267
|
+
kind: 'turn-error';
|
|
268
|
+
nodeKey: string;
|
|
269
|
+
message: string;
|
|
270
|
+
code: string | undefined;
|
|
271
|
+
} | {
|
|
272
|
+
kind: 'turn-max-tokens';
|
|
273
|
+
nodeKey: string;
|
|
274
|
+
} | {
|
|
275
|
+
kind: 'unknown';
|
|
276
|
+
nodeKey: string;
|
|
277
|
+
nodeKind: string;
|
|
278
|
+
data: unknown;
|
|
279
|
+
};
|
|
280
|
+
/** The chat node data union the focus view narrows, keyed by the merge-extensible map. */
|
|
281
|
+
export type FocusNodeData = ChatNodeDataMap[Extract<keyof ChatNodeDataMap, string>];
|
|
282
|
+
/** One produced-path fact (the ui-deliverables turn data contract). */
|
|
283
|
+
export interface FocusDeliverablesData {
|
|
284
|
+
readonly produced: readonly {
|
|
285
|
+
readonly seq: number;
|
|
286
|
+
readonly path: string;
|
|
287
|
+
}[];
|
|
288
|
+
}
|
|
289
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { FocusViewProps } from '../contract/props.ts';
|
|
2
|
+
/**
|
|
3
|
+
* The focus view slot entry: pure component over the composed props. Scroll
|
|
4
|
+
* follows the chat view's ledger: the resolved scrollport (the shared
|
|
5
|
+
* conversation column in the app, the view itself in tests) keeps reader
|
|
6
|
+
* positions saved continuously on scroll and restored on mount.
|
|
7
|
+
* @param props - conversation view standard kit and the focus locale seat.
|
|
8
|
+
*/
|
|
9
|
+
export declare function FocusView({ useSession, useChat, sessionId, useSessions, loadOlder, loadImage, openFile, forkAt, fileMentions, isLoopback, scroll, useHostHome, useFeedback, ensureFeedback, rateFeedback, toggleFeedback, clearFeedbackNote, t, }: FocusViewProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Lightbox strings the owner resolves from its own locale namespace. */
|
|
2
|
+
export interface ImageLightboxLabels {
|
|
3
|
+
/** Accessible name of the preview dialog. */
|
|
4
|
+
dialog: string;
|
|
5
|
+
/** Accessible label of the close control. */
|
|
6
|
+
close: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Document-level original-image preview opened by clicking a thumbnail.
|
|
10
|
+
* Closes on Escape, backdrop press, or the close control, and restores focus
|
|
11
|
+
* to the opener on unmount. Rendered through a body portal: an opener inside
|
|
12
|
+
* a transformed or filtered ancestor would otherwise trap the fixed backdrop
|
|
13
|
+
* in that ancestor's box instead of covering the viewport.
|
|
14
|
+
*
|
|
15
|
+
* @param props.src - the original image URL.
|
|
16
|
+
* @param props.alt - the image's alt text.
|
|
17
|
+
* @param props.labels - dialog and close-control strings.
|
|
18
|
+
* @param props.onClose - dismiss callback owned by the opener.
|
|
19
|
+
* @returns the modal preview dialog.
|
|
20
|
+
*/
|
|
21
|
+
export declare function ImageLightbox({ src, alt, labels, onClose }: {
|
|
22
|
+
src: string;
|
|
23
|
+
alt: string;
|
|
24
|
+
labels: ImageLightboxLabels;
|
|
25
|
+
onClose: () => void;
|
|
26
|
+
}): import("react").ReactPortal;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import type { FocusTranslate } from '../../contract/props.ts';
|
|
3
|
+
export declare const MessageActions: import("react").MemoExoticComponent<({ text, time, runMs, ttftMs, tokensPerSecond, clock, onBranch, branchUnavailable, extraActions, t }: {
|
|
4
|
+
/** Plain text the copy action writes. */
|
|
5
|
+
text: string;
|
|
6
|
+
/** Unix epoch ms for the clock label; null hides the clock. */
|
|
7
|
+
time: number | null;
|
|
8
|
+
/** Turn wall time, appended as `· 用时 15s`; null omits the reading. */
|
|
9
|
+
runMs: number | null;
|
|
10
|
+
/** Turn first-step TTFT in ms; null omits the reading. */
|
|
11
|
+
ttftMs: number | null;
|
|
12
|
+
/** Turn decode throughput; null omits the reading. */
|
|
13
|
+
tokensPerSecond: number | null;
|
|
14
|
+
/** Clock before the icons (user) or after (assistant tail). */
|
|
15
|
+
clock: "start" | "end";
|
|
16
|
+
/** Fork the session at this message; omission hides the branch action. */
|
|
17
|
+
onBranch?: (() => void) | undefined;
|
|
18
|
+
/** The message is not the completed turn's last row, so branch stays visible but unavailable. */
|
|
19
|
+
branchUnavailable?: boolean | undefined;
|
|
20
|
+
/** Slot-rendered actions owned by independent plugins (the chat's
|
|
21
|
+
* assistant-actions strip), placed between copy and branch. */
|
|
22
|
+
extraActions?: ReactNode | undefined;
|
|
23
|
+
t: FocusTranslate;
|
|
24
|
+
}) => import("react").JSX.Element>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-message feedback controls: a Like/Dislike pair plus an optional note.
|
|
3
|
+
* The buttons render inside the assistant message's IconActions row, so they
|
|
4
|
+
* reuse that row's chrome and sit between copy and branch. The note editor is
|
|
5
|
+
* a popover (portaled to `document.body`) anchored to the note trigger, not an
|
|
6
|
+
* inline expansion: a 260px textarea plus buttons cannot fit the row at any
|
|
7
|
+
* viewport, and an inline element pushed the branch action and clock out of the
|
|
8
|
+
* conversation column. Portaling out of the column also escapes its `overflow`
|
|
9
|
+
* clip, so the panel cannot be cropped or detached from the message it annotates.
|
|
10
|
+
* @module @deepseek-ai/dsh-client-ui-message-feedback/client/MessageFeedbackActions
|
|
11
|
+
*/
|
|
12
|
+
import type { SnapshotSelectorHook } from '@deepseek-ai/dsh-client-ui-slots';
|
|
13
|
+
import type { MessageId } from '@deepseek-ai/dsh-client-connection/client';
|
|
14
|
+
import type { MessageFeedbackRating } from '@deepseek-ai/dsh-message-feedback/types';
|
|
15
|
+
import type { MessageFeedbackActionResult, MessageFeedbackView } from '../../model/feedback-controller.ts';
|
|
16
|
+
import type { FocusTranslate } from '../../contract/props.ts';
|
|
17
|
+
/** The shared feedback verbs and view hook the focus view injects (the chat
|
|
18
|
+
* assistant-actions strip's business face, re-declared here because the view
|
|
19
|
+
* cannot take that slot seat). */
|
|
20
|
+
export interface FocusFeedbackActions {
|
|
21
|
+
/** The owning Session's feedback view, shared by every message control. */
|
|
22
|
+
useFeedback: SnapshotSelectorHook<MessageFeedbackView>;
|
|
23
|
+
/** Load the Session's feedback once, on first interaction. */
|
|
24
|
+
ensure: () => Promise<MessageFeedbackActionResult>;
|
|
25
|
+
/** Create or replace this Session's feedback for one message. */
|
|
26
|
+
rate: (messageId: MessageId, rating: MessageFeedbackRating, note?: string) => Promise<MessageFeedbackActionResult>;
|
|
27
|
+
/** Toggle or retract one message's rating. */
|
|
28
|
+
toggle: (messageId: MessageId, rating: MessageFeedbackRating) => Promise<MessageFeedbackActionResult>;
|
|
29
|
+
/** Drop the note while keeping the rating. */
|
|
30
|
+
clearNote: (messageId: MessageId) => Promise<MessageFeedbackActionResult>;
|
|
31
|
+
}
|
|
32
|
+
/** Full props of one assistant-message feedback entry. */
|
|
33
|
+
export type FocusMessageFeedbackProps = FocusFeedbackActions & {
|
|
34
|
+
/** Target assistant-message identity. */
|
|
35
|
+
messageId: MessageId;
|
|
36
|
+
/** The owning view's locale seat. */
|
|
37
|
+
t: FocusTranslate;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* One message's feedback controls.
|
|
41
|
+
* @param props - the owner's message identity, the injected verbs, and the
|
|
42
|
+
* shared feedback hook.
|
|
43
|
+
* @returns the rating buttons and the note trigger, with the note editor
|
|
44
|
+
* portal-open beneath the trigger while it is open.
|
|
45
|
+
*/
|
|
46
|
+
export declare function MessageFeedbackActions({ messageId, ensure, rate, toggle, clearNote, useFeedback, t }: FocusMessageFeedbackProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { ImageAttachmentRef } from '@deepseek-ai/dsh-attachment';
|
|
2
|
+
import { type ImageLightboxLabels } from './ImageLightbox.tsx';
|
|
3
|
+
/** Loads a session-authorized durable image URL. */
|
|
4
|
+
export type ImageLoader = (attachment: ImageAttachmentRef) => Promise<string>;
|
|
5
|
+
/** Message-image strings the owner resolves from its own locale namespace. */
|
|
6
|
+
export interface MessageImageLabels {
|
|
7
|
+
/** Fallback display name for an unnamed image. */
|
|
8
|
+
image: string;
|
|
9
|
+
/** Thumbnail tooltip inviting the original-image preview. */
|
|
10
|
+
open: string;
|
|
11
|
+
/** Accessible thumbnail label; receives the image's display name. */
|
|
12
|
+
openNamed: (label: string) => string;
|
|
13
|
+
/** Loading placeholder shown until bytes resolve. */
|
|
14
|
+
loading: string;
|
|
15
|
+
/** Retry-control label shown when the load fails. */
|
|
16
|
+
loadFailed: string;
|
|
17
|
+
/** Lightbox strings forwarded to the opened preview. */
|
|
18
|
+
lightbox: ImageLightboxLabels;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Compact history renderer with retryable loading and click-to-open original
|
|
22
|
+
* preview. A lone image renders at its `singleFit` size; an image among
|
|
23
|
+
* several renders as a fixed 64px square tile.
|
|
24
|
+
*
|
|
25
|
+
* @param props.attachment - the durable image reference to load and bound.
|
|
26
|
+
* @param props.load - session-authorized URL loader.
|
|
27
|
+
* @param props.variant - `single` for a message's lone image, `tile` otherwise.
|
|
28
|
+
* @param props.labels - resolved strings (tooltip, loading, retry, lightbox).
|
|
29
|
+
* @returns the bounded thumbnail button, or the retry control on failure.
|
|
30
|
+
*/
|
|
31
|
+
export declare function MessageImage({ attachment, load, variant, labels }: {
|
|
32
|
+
attachment: ImageAttachmentRef;
|
|
33
|
+
load: ImageLoader;
|
|
34
|
+
variant: 'single' | 'tile';
|
|
35
|
+
labels: MessageImageLabels;
|
|
36
|
+
}): import("react").JSX.Element;
|
|
37
|
+
/** Wrapping image group shared by user and assistant history: a lone image
|
|
38
|
+
* renders large, several render as 64px square tiles (DeepSeek Chat rule). */
|
|
39
|
+
export declare function ImageGallery({ images, load, align, labels }: {
|
|
40
|
+
images: readonly {
|
|
41
|
+
attachment: ImageAttachmentRef;
|
|
42
|
+
}[];
|
|
43
|
+
load: ImageLoader;
|
|
44
|
+
align: 'start' | 'end';
|
|
45
|
+
labels: MessageImageLabels;
|
|
46
|
+
}): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { FocusTranslate } from '../../contract/props.ts';
|
|
2
|
+
/** One scroll-nav entry: a user / steering message's focus anchor. */
|
|
3
|
+
export interface FocusNavEntry {
|
|
4
|
+
key: string;
|
|
5
|
+
/** First text line of the message (the rail's collapsed label). */
|
|
6
|
+
label: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The in-view scroll navigation rail (the DeepSeek chat's page nav): a
|
|
10
|
+
* right-edge strip of entry dashes, position:fixed at the scrollport's
|
|
11
|
+
* right-middle (pure CSS, no measuring), that expands on hover to list
|
|
12
|
+
* every user / steering message. Clicking an entry jumps the focus
|
|
13
|
+
* scrollport to that row; the active entry follows the reader (scroll-spy).
|
|
14
|
+
*/
|
|
15
|
+
export declare const NavRail: import("react").MemoExoticComponent<({ entries, activeKey, onSelect, t }: {
|
|
16
|
+
entries: readonly FocusNavEntry[];
|
|
17
|
+
/** The scroll-spy active entry key, or null before the first spy pass. */
|
|
18
|
+
activeKey: string | null;
|
|
19
|
+
onSelect: (key: string) => void;
|
|
20
|
+
t: FocusTranslate;
|
|
21
|
+
}) => import("react").JSX.Element | null>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** The reference-domain glyphs of the official chat (session/file/folder),
|
|
2
|
+
* reimplemented here because the npm package does not re-export them. */
|
|
3
|
+
import type { ReactNode } from 'react';
|
|
4
|
+
/** Reference domains with distinct composer and transcript glyphs. */
|
|
5
|
+
export type ReferenceIconKind = 'session' | 'file' | 'folder';
|
|
6
|
+
/** Props shared by inline reference glyphs. */
|
|
7
|
+
export interface ReferenceIconProps {
|
|
8
|
+
kind: ReferenceIconKind;
|
|
9
|
+
size?: number;
|
|
10
|
+
className?: string | undefined;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Render the icon that identifies one inline reference domain.
|
|
14
|
+
* @param props - Reference kind, optional size, and optional CSS class.
|
|
15
|
+
* @returns The corresponding current-color SVG glyph.
|
|
16
|
+
*/
|
|
17
|
+
export declare function ReferenceIcon({ kind, size, className }: ReferenceIconProps): ReactNode;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { FocusTranslate } from '../../contract/props.ts';
|
|
2
|
+
export declare function RunningStatus({ startTime, t }: {
|
|
3
|
+
/** The running turn's logged turn/start time; null falls back to mount time. */
|
|
4
|
+
startTime: number | null;
|
|
5
|
+
t: FocusTranslate;
|
|
6
|
+
}): import("react").JSX.Element;
|
|
7
|
+
/** Reader-scroll following threshold (the chat view's value). */
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { TurnNavigationItem } from '@deepseek-ai/dsh-client-ui-chat/client';
|
|
2
|
+
import type { FocusTranslate } from '../../contract/props.ts';
|
|
3
|
+
interface TurnNavigatorProps {
|
|
4
|
+
readonly items: readonly TurnNavigationItem[];
|
|
5
|
+
readonly activeTurn: number | null;
|
|
6
|
+
readonly onNavigate: (item: TurnNavigationItem) => void;
|
|
7
|
+
readonly t: FocusTranslate;
|
|
8
|
+
}
|
|
9
|
+
/** Compact rail of the loaded Turns with hover and focus previews — the
|
|
10
|
+
* official turn navigator's chrome, reimplemented for the focus view.
|
|
11
|
+
* Memoized: its props stay referentially stable across streaming commits,
|
|
12
|
+
* so a long session never rebuilds the marks per frame. */
|
|
13
|
+
export declare const TurnNavigator: import("react").MemoExoticComponent<({ items, activeTurn, onNavigate, t }: TurnNavigatorProps) => import("react").JSX.Element | null>;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { FocusTranslate } from '../../contract/props.ts';
|
|
2
|
+
export declare function firstLine(text: string): string;
|
|
3
|
+
/** The trailing `count` lines of a streaming text (the running tail preview). */
|
|
4
|
+
export declare function latestLines(text: string, count: number): string;
|
|
5
|
+
/** Zero-padded two-digit number (the chat clock's rhythm). */
|
|
6
|
+
export declare function pad2(n: number): string;
|
|
7
|
+
/** The original-image lightbox strings (the chat image-labels bridge). */
|
|
8
|
+
export declare function basename(path: string): string;
|
|
9
|
+
/** Decode-throughput figure: whole tokens from ten up, one decimal below. */
|
|
10
|
+
export declare function formatTokensPerSecond(tps: number): string;
|
|
11
|
+
/** Local calendar-day epoch (ms at local midnight) for an instant. */
|
|
12
|
+
export declare function startOfLocalDay(ms: number): number;
|
|
13
|
+
/** Delay until the next local midnight after `ms` (at least 1ms). */
|
|
14
|
+
export declare function msUntilNextLocalMidnight(ms: number): number;
|
|
15
|
+
/** The current local calendar-day epoch, re-resolved at each midnight. */
|
|
16
|
+
export declare function useCalendarDay(): number;
|
|
17
|
+
/**
|
|
18
|
+
* Compact local timestamp for message chrome (the chat clock): same local
|
|
19
|
+
* calendar day → `HH:mm`; earlier this year → the `clock.md` template;
|
|
20
|
+
* other years → `clock.ymd`.
|
|
21
|
+
* @param time - Unix epoch ms from the source session event.
|
|
22
|
+
* @param t - focus locale seat supplying the date templates.
|
|
23
|
+
* @param now - reference instant for the day/year cut.
|
|
24
|
+
* @returns the date-aware clock string.
|
|
25
|
+
*/
|
|
26
|
+
export declare function formatMessageClock(time: number, t: FocusTranslate, now?: number): string;
|
|
27
|
+
/** Concatenated text blocks of a message (the chat bubble's join). */
|
|
28
|
+
export declare function useThrottledVisualUpdate(update: () => void, intervalFrames?: number): () => void;
|
|
29
|
+
export declare function formatElapsed(ms: number, t: FocusTranslate): string;
|
|
30
|
+
/** Turn-level running signal: "Deep diving..." plus an elapsed clock past 15s. */
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Tool-family leading icons (the chat GenericToolCard table). */
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
import type { FocusToolRow } from '../../model/types.ts';
|
|
4
|
+
/** Tool-family leading icons, mirroring the chat GenericToolCard table (glyphs at 14). */
|
|
5
|
+
export declare const VARIANT_ICONS: Record<'search' | 'read' | 'bash' | 'write' | 'edit' | 'code' | 'question' | 'todo' | 'skill' | 'others', ReactNode>;
|
|
6
|
+
/** Tool name → leading-icon family (mirrors the chat row classification). */
|
|
7
|
+
export declare const TOOL_VARIANTS: Readonly<Record<string, keyof typeof VARIANT_ICONS>>;
|
|
8
|
+
/** One call's leading glyph: the family icon, or the state dot for failures. */
|
|
9
|
+
export declare function leadingFor(row: FocusToolRow): ReactNode;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Message-image label bridge and block extraction (the chat image-labels rule). */
|
|
2
|
+
import type { ImageAttachmentRef } from '@deepseek-ai/dsh-attachment';
|
|
3
|
+
import type { ContentBlock } from '@deepseek-ai/dsh-llm/types';
|
|
4
|
+
import type { FocusTranslate } from '../../contract/props.ts';
|
|
5
|
+
import type { MessageImageLabels } from '../chrome/MessageImage.tsx';
|
|
6
|
+
import type { ImageLightboxLabels } from '../chrome/ImageLightbox.tsx';
|
|
7
|
+
export declare function lightboxLabels(t: FocusTranslate): ImageLightboxLabels;
|
|
8
|
+
/** The message-image strings, including the forwarded lightbox strings. */
|
|
9
|
+
export declare function messageImageLabels(t: FocusTranslate): MessageImageLabels;
|
|
10
|
+
/** Image blocks of one user message, in order (the chat gallery's input). */
|
|
11
|
+
export declare function userImages(content: readonly ContentBlock[]): {
|
|
12
|
+
attachment: ImageAttachmentRef;
|
|
13
|
+
}[];
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** User message text projection (the chat bubble join and reference chips). */
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
export declare function messageText(content: readonly {
|
|
4
|
+
type?: string;
|
|
5
|
+
text?: string;
|
|
6
|
+
}[]): string;
|
|
7
|
+
/**
|
|
8
|
+
* Display projection of reference forms in a user bubble: `/name` / `@name`
|
|
9
|
+
* word-boundary tokens decorate as chips, everything else stays plain text
|
|
10
|
+
* (the chat bubble's projection — sent tokens were validated at compose time,
|
|
11
|
+
* so shape alone decorates).
|
|
12
|
+
*/
|
|
13
|
+
export declare function projectUserText(text: string): ReactNode;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** JsonBlock truncation footer and card-primitive label sets bound to the focus locale. */
|
|
2
|
+
import type { DiffBlockLabels, MarkdownLabels, ReadBlockLabels, SearchBlockLabels, TerminalBlockLabels, WebBlockLabels } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
3
|
+
import type { FocusTranslate } from '../../contract/props.ts';
|
|
4
|
+
export declare function jsonTruncated(t: FocusTranslate): (total: number) => string;
|
|
5
|
+
/** Card line caps the chat rows apply (design rhythm). */
|
|
6
|
+
export declare const CHAT_DIFF_MAX_LINES = 8;
|
|
7
|
+
export declare const CHAT_READ_MAX_LINES = 8;
|
|
8
|
+
export declare const CHAT_SEARCH_MAX_LINES = 8;
|
|
9
|
+
/** Markdown chrome for the primitive's document renderer (code fences + footnotes). */
|
|
10
|
+
export declare function markdownLabels(t: FocusTranslate): MarkdownLabels;
|
|
11
|
+
/** Terminal-card labels bound to the focus locale (the chat label seam). */
|
|
12
|
+
export declare function terminalLabels(t: FocusTranslate): TerminalBlockLabels;
|
|
13
|
+
/** Diff-card labels bound to the focus locale. */
|
|
14
|
+
export declare function diffLabels(t: FocusTranslate): DiffBlockLabels;
|
|
15
|
+
/** Read-card labels bound to the focus locale. */
|
|
16
|
+
export declare function readLabels(t: FocusTranslate): ReadBlockLabels;
|
|
17
|
+
/** Search-card labels bound to the focus locale. */
|
|
18
|
+
export declare function searchLabels(t: FocusTranslate): SearchBlockLabels;
|
|
19
|
+
/** Web-card labels bound to the focus locale. */
|
|
20
|
+
export declare function webLabels(t: FocusTranslate): WebBlockLabels;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { FocusTranslate } from '../../contract/props.ts';
|
|
2
|
+
import type { FocusFlowItem } from '../../model/types.ts';
|
|
3
|
+
/** One command row (the chat GenericCommandCard chrome: name · settlement, expandable multiline body). */
|
|
4
|
+
export declare const CommandRow: import("react").MemoExoticComponent<({ item, runningSummary, t }: {
|
|
5
|
+
item: Extract<FocusFlowItem, {
|
|
6
|
+
kind: "command";
|
|
7
|
+
}>;
|
|
8
|
+
/** Command-specific running copy; absent uses the generic running label. */
|
|
9
|
+
runningSummary?: string | undefined;
|
|
10
|
+
t: FocusTranslate;
|
|
11
|
+
}) => import("react").JSX.Element>;
|
|
12
|
+
/** One landed-compaction marker (the chat CompactionItem chrome). */
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { MarkdownLabels } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
2
|
+
import type { FocusTranslate } from '../../contract/props.ts';
|
|
3
|
+
import type { FocusFlowItem } from '../../model/types.ts';
|
|
4
|
+
/** One landed-compaction marker (the chat CompactionItem chrome). */
|
|
5
|
+
export declare const CompactionRow: import("react").MemoExoticComponent<({ item, title, fallbackSummary, t, mdLabels }: {
|
|
6
|
+
item: Extract<FocusFlowItem, {
|
|
7
|
+
kind: "compaction";
|
|
8
|
+
}>;
|
|
9
|
+
/** Optional command title for a manual compaction folded into this marker. */
|
|
10
|
+
title?: string | undefined;
|
|
11
|
+
/** Command settlement text used when structured compaction counts are unavailable. */
|
|
12
|
+
fallbackSummary?: string | null | undefined;
|
|
13
|
+
t: FocusTranslate;
|
|
14
|
+
mdLabels: MarkdownLabels;
|
|
15
|
+
}) => import("react").JSX.Element>;
|
|
16
|
+
/** One manual `/compact` lifecycle: the command card, or the checkpoint marker. */
|
|
17
|
+
export declare const ManualCompactionRow: import("react").MemoExoticComponent<({ item, t, mdLabels }: {
|
|
18
|
+
item: Extract<FocusFlowItem, {
|
|
19
|
+
kind: "manual-compaction";
|
|
20
|
+
}>;
|
|
21
|
+
t: FocusTranslate;
|
|
22
|
+
mdLabels: MarkdownLabels;
|
|
23
|
+
}) => import("react").JSX.Element>;
|
|
24
|
+
/** One model-retry row (the chat ModelRetryItem chrome: countdown + details). */
|