dsh-streamfold 0.7.0 → 0.7.2
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/CHANGELOG.md +17 -0
- package/README.en.md +8 -7
- package/README.md +8 -7
- package/lib/client.js +38 -12
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
本项目按 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/) 的组织方式记录用户可感知的变化;版本号遵循语义化版本。
|
|
4
4
|
|
|
5
|
+
## [0.7.2] — 2026-10-05
|
|
6
|
+
|
|
7
|
+
- 调整:开启「提问不入折叠」时,「跑完回到提问处」落到本轮最后一张 LLM 提问卡(而不是你那句话),并在就位前把这张卡展开。
|
|
8
|
+
- 调整:提问卡自动展开沿用「扫描只登记、合成点击在下一帧」的队列;React 重挂载后又折着的卡会再展开一次。
|
|
9
|
+
- 调整:用户手动折过的提问卡不被抢开;「提问不入折叠」关闭或本轮没有提问卡时,落点仍是你那句话。
|
|
10
|
+
|
|
11
|
+
## [0.7.1] — 2026-10-04
|
|
12
|
+
|
|
13
|
+
**纯文档修正(无代码变更)**:0.7.0 的 npm 包内 README 仍是发布前的安装段——写着「0.7.0 尚未发布到 npm」,与仓库首页的最终版不一致(发布 commit `029df7e` 之后 50 秒才提交 README 终稿 `9f3206a`)。本版重新发布,让包内 README 与实际发布状态一致。
|
|
14
|
+
|
|
15
|
+
### 文档
|
|
16
|
+
|
|
17
|
+
- 包内 `README.md` / `README.en.md` 安装段为最终版:**DSH 插件面板为首选方式**(npm `latest` 即本版,含 provenance),命令行三种写法并列;移除已过期的「尚未发布到 npm」警告。
|
|
18
|
+
- 版本号引用不再硬编码具体版本,避免下次发布再次滞后。
|
|
19
|
+
- `lib/` 无任何改动(`lib/client.js` 仍为 `9404096f`)。
|
|
20
|
+
|
|
5
21
|
## [0.7.0] — 2026-10-04
|
|
6
22
|
|
|
7
23
|
0.6 → 0.7 的架构重建之后的**首个对外版本**(npm 上此前最新为 0.5.7,0.6 / 0.7 均未发布;本文描述的全部内容都是首次对外)。除架构重建外,本版还并入 2026-10-04 的审计修复批次:输入/卸载语义(P0)、折叠与导航(P1)、性能去重、诊断口径,以及用户点名的「瞬时判据改场景 + 展开也错峰」。
|
|
@@ -59,4 +75,5 @@
|
|
|
59
75
|
- **自动展开移出扫描帧**:提问卡/思考/工具只登记,合成点击在下一帧 rAF 执行。
|
|
60
76
|
- **折叠内容用 `hidden="until-found"`**,兼顾长会话性能与 Ctrl+F 可搜。
|
|
61
77
|
|
|
78
|
+
[0.7.1]: https://github.com/rezon-aki/dsh-streamfold/releases/tag/v0.7.1
|
|
62
79
|
[0.7.0]: https://github.com/rezon-aki/dsh-streamfold/releases/tag/v0.7.0
|
package/README.en.md
CHANGED
|
@@ -18,7 +18,7 @@ In a long conversation, tool calls and reasoning drown out the prose. The offici
|
|
|
18
18
|
|
|
19
19
|
- **You can watch it think.** The newest thinking window of the running turn opens automatically (height configurable); older ones fold back into a one-line summary after a grace period. Superseded windows and past turns no longer fight for the scroll position.
|
|
20
20
|
- **Folding keeps a rhythm and does not flash.** Collapsing runs bottom-up, 3 rows per group with a 70 ms stagger; expanding runs top-down, 3 rows per group. Cross-turn batches (page load, session switch) complete instantly; even a very long single turn advances group by group (only a single turn over 84 rows takes the instant guard rail).
|
|
21
|
-
- **Settle on the prompt.** When a turn finishes, the view glides back to **the message that started it** (
|
|
21
|
+
- **Settle on the prompt.** When a turn finishes, the view glides back to **the message that started it** — or, when "Keep LLM questions unfolded" is on and the turn contains an `ask_user_question` card, to the turn's **last question card**, auto-expanded (that is what needs your answer). Skipped if you scrolled away yourself. For 2 seconds after arrival it also corrects late layout shifts from images or code blocks.
|
|
22
22
|
- **Pin the prompt.** The prompt of the turn you are reading stays pinned to the top of the conversation, one line with an ellipsis; it steps aside while the real row is on screen, and clicking it glides back to that message.
|
|
23
23
|
- **Steady follow.** The bottom follow advances per frame; scrolling up stops it, and a "back to bottom" button appears once you are away. Scrolling inside a thinking window or a tool body no longer stops the follow by mistake.
|
|
24
24
|
- **Search is handled too.** Folded content is still findable with Ctrl+F; while searching the plugin releases the scroll and does not pin to the bottom, and returning to the window tail or pressing back-to-bottom resumes the follow.
|
|
@@ -36,18 +36,19 @@ In a long conversation, tool calls and reasoning drown out the prose. The offici
|
|
|
36
36
|
dsh-streamfold
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
>
|
|
39
|
+
> The panel installs this version (npm `latest` is this release, with provenance). Option 2 is for tracking the repository's latest code.
|
|
40
40
|
|
|
41
|
-
**Option 2: the command line** (
|
|
41
|
+
**Option 2: the command line** (three forms):
|
|
42
42
|
|
|
43
43
|
```bash
|
|
44
|
-
dsh plugin --profile web add
|
|
44
|
+
dsh plugin --profile web add dsh-streamfold # npm package (recommended)
|
|
45
|
+
dsh plugin --profile web add github:rezon-aki/dsh-streamfold # track the repository
|
|
45
46
|
dsh plugin --profile web add https://github.com/rezon-aki/dsh-streamfold
|
|
46
47
|
```
|
|
47
48
|
|
|
48
49
|
Restart the profile, then **refresh the browser page** (client code is injected at page load).
|
|
49
50
|
|
|
50
|
-
Requires DSH **>= 0.2.0-rc.2** (the official transcript view is owned by the `configForms` service; on the 0.1.7 series use 0.5.0, and on 0.1.5 and earlier use 0.4.x).
|
|
51
|
+
Requires DSH **>= 0.2.0-rc.2** (the official transcript view is owned by the `configForms` service; on the 0.1.7 series use 0.5.0, and on 0.1.5 and earlier use 0.4.x).
|
|
51
52
|
|
|
52
53
|
Uninstall: remove it in the plugin panel, or
|
|
53
54
|
|
|
@@ -86,7 +87,7 @@ While running, only the newest thinking window opens automatically; **windows yo
|
|
|
86
87
|
| Work details | `mode` | Fold | Fold / official four modes | Choosing Fold parks the official mode on Verbose, avoiding double folding |
|
|
87
88
|
| Fold history turns | `foldHistory` | on | toggle | Off: do not fold past turns on page load (only while a turn runs) |
|
|
88
89
|
| Keep interleaved prose | `keepInterleavedText` | on | toggle | Keep prose rows while folding and separate them from the final answer with a rule (no capped window) |
|
|
89
|
-
| Keep LLM questions unfolded | `keepUserQuestions` | on | toggle | The `ask_user_question` card and its reply node never fold; off folds them with everything else |
|
|
90
|
+
| Keep LLM questions unfolded | `keepUserQuestions` | on | toggle | The `ask_user_question` card and its reply node never fold, and "Settle on the prompt" lands on the last question card instead; off folds them with everything else |
|
|
90
91
|
| Follow speed cap | `followMaxSpeed` | 240 | 60–2000 px/s | Cap on our own catch-up speed; lower is softer and lags more on fast output. Content growth is not capped |
|
|
91
92
|
| Follow acceleration cap | `followMaxAccel` | 10000 | 2000–120000 px/s² | Cap on speed change; lower is softer at start/stop, higher is more responsive |
|
|
92
93
|
| Window height | `windowHeight` | 360 | 80–1200 px | Max height of a thinking / interleaved-prose window |
|
|
@@ -96,7 +97,7 @@ While running, only the newest thinking window opens automatically; **windows yo
|
|
|
96
97
|
| Return to tail on new message | `returnToTail` | on | toggle | While stopped mid-transcript, sending a new message glides back to the bottom; off keeps the view where it is until you scroll to the bottom or press back-to-bottom |
|
|
97
98
|
| Smoothing factor | `smoothGrow` | 0.15 | 0.05–0.9 | Share of the remaining gap consumed per frame |
|
|
98
99
|
| Show "back to bottom" | `showJumpButton` | on | toggle | Shown when away from the bottom (hidden for follow lag, to avoid flicker) |
|
|
99
|
-
| Settle on the prompt | `settleToPrompt` | on | toggle | When a turn finishes, glide back to your message that started it; if you scrolled away yourself, nothing moves |
|
|
100
|
+
| Settle on the prompt | `settleToPrompt` | on | toggle | When a turn finishes, glide back to your message that started it; with unfolded questions on and a question card in the turn, glide to that last card (and expand it) instead; if you scrolled away yourself, nothing moves |
|
|
100
101
|
| Pin the prompt | `pinPrompt` | on | toggle | Keep the prompt of the turn you are reading pinned to the top: one line with ellipsis, steps aside while the real row is in view, click to glide back |
|
|
101
102
|
| Animated transitions | `animations` | on | toggle | Off makes folding / expanding / jumping instant |
|
|
102
103
|
| Window sparks | `sparks` | on | toggle | Sparks along the bottom edge of the running thinking window (off = no canvas, no frames) |
|
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
- **运行中看得到思考。** 自动展开本轮最新的思考窗(限高可调),旧的按宽限折回一行摘要;被取代的、上一轮的窗不再抢滚动。
|
|
20
20
|
- **折叠有节奏,不闪。** 收起从下往上、一组 3 行、组间 70ms;展开从最上面往下、同样一组 3 行。加载页面、切会话这类**跨轮批量**场景直接瞬时完成;单轮再长也逐组推进(只有单轮超过 84 行才走瞬时护栏)。
|
|
21
|
-
- **跑完回到提问处。**
|
|
21
|
+
- **跑完回到提问处。** 一轮结束,视图平滑滑回**你这轮那句话**的位置;开启「提问不入折叠」且这一轮里 LLM 问过你(`ask_user_question`)时,落点改在**这一轮最后那张提问卡**上并自动把它展开(要你答的是它)。你自己上滚过就不动你。到位后 2 秒内还会纠正图片/代码块迟到落版造成的偏移。
|
|
22
22
|
- **置顶显示提问。** 读到哪一轮,那一轮的提问就钉在会话顶端(一行,超出省略);它自己在屏幕上时自动让位,点它滑回那句发言。
|
|
23
23
|
- **跟随够稳。** 底部跟随按帧推进;上滚即停跟,离底出现「回到底部」;在思考小窗或工具正文里滚动不会误触发「停止跟随」。
|
|
24
24
|
- **搜索也照顾。** 折叠的内容仍可被 Ctrl+F 搜到;搜索期间不抢滚动,滚回窗尾或点回底恢复。
|
|
@@ -36,18 +36,19 @@
|
|
|
36
36
|
dsh-streamfold
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
>
|
|
39
|
+
> 面板装的就是本版(npm 上 `latest` 即本版,含 provenance)。方式二适合想跟仓库最新代码的人。
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
**方式二:命令行**(三种写法):
|
|
42
42
|
|
|
43
43
|
```bash
|
|
44
|
-
dsh plugin --profile web add
|
|
44
|
+
dsh plugin --profile web add dsh-streamfold # npm 包(推荐)
|
|
45
|
+
dsh plugin --profile web add github:rezon-aki/dsh-streamfold # 跟仓库最新
|
|
45
46
|
dsh plugin --profile web add https://github.com/rezon-aki/dsh-streamfold
|
|
46
47
|
```
|
|
47
48
|
|
|
48
49
|
装完**重启 profile**,然后**刷新浏览器页面**(客户端代码在页面加载时注入)。
|
|
49
50
|
|
|
50
|
-
要求 DSH **>= 0.2.0-rc.2**(官方「对话显示」档位由 `configForms` 服务托管;0.1.7 系列请用 0.5.0,0.1.5 及更早请用 0.4.x)。
|
|
51
|
+
要求 DSH **>= 0.2.0-rc.2**(官方「对话显示」档位由 `configForms` 服务托管;0.1.7 系列请用 0.5.0,0.1.5 及更早请用 0.4.x)。
|
|
51
52
|
|
|
52
53
|
卸载:在插件面板里移除,或
|
|
53
54
|
|
|
@@ -86,7 +87,7 @@ dsh plugin --profile web remove dsh-streamfold
|
|
|
86
87
|
| 工作步骤展示 | `mode` | 折叠 | 折叠 / 官方四档 | 选「折叠」时官方档自动停到「完全展开」,避免两层折叠 |
|
|
87
88
|
| 折叠历史轮次 | `foldHistory` | 开 | 开关 | 关掉后:加载页面不再自动折叠历史轮次(只在跑动时折前面的) |
|
|
88
89
|
| 保留穿插正文 | `keepInterleavedText` | 开 | 开关 | 折叠时保留带正文的行,用一条横线与正式回答分开(正文不套限高小窗) |
|
|
89
|
-
| 提问不入折叠 | `keepUserQuestions` | 开 | 开关 | LLM 的提问工具(`ask_user_question
|
|
90
|
+
| 提问不入折叠 | `keepUserQuestions` | 开 | 开关 | LLM 的提问工具(`ask_user_question`)与其回复节点始终保留、不折进摘要,且「跑完回到提问处」改落到最后那张提问卡上;关掉则随其余内容一起折 |
|
|
90
91
|
| 跟随速度上限 | `followMaxSpeed` | 240 | 60~2000 px/s | 主动追赶时的速度上限;越小越柔、高速输出时落后越多。内容自身增长的速度不受它限制 |
|
|
91
92
|
| 跟随加速度上限 | `followMaxAccel` | 10000 | 2000~120000 px/s² | 速度变化的上限;调小起步/刹车更柔,调大更跟手 |
|
|
92
93
|
| 窗口高度 | `windowHeight` | 360 | 80~1200 px | 单个思考/穿插正文小窗的最大高度 |
|
|
@@ -96,7 +97,7 @@ dsh plugin --profile web remove dsh-streamfold
|
|
|
96
97
|
| 发消息回到尾部 | `returnToTail` | 开 | 开关 | 你停在中途(看过置顶、跳转过轮次)时,自己再发一条消息 ⇒ 视图滑回尾部;关掉后一律停在原地,只有滚到底或点「回到底部」才恢复跟随 |
|
|
97
98
|
| 平滑系数 | `smoothGrow` | 0.15 | 0.05~0.9 | 跟随时每帧吃掉多少差距,越小越柔 |
|
|
98
99
|
| 离底显示「回到底部」 | `showJumpButton` | 开 | 开关 | 离开底部时出现回底按钮(跟随中的轻微落后不显示,避免闪烁) |
|
|
99
|
-
| 跑完回到提问处 | `settleToPrompt` | 开 | 开关 |
|
|
100
|
+
| 跑完回到提问处 | `settleToPrompt` | 开 | 开关 | 一轮结束后平滑移到本轮你那句话的位置;开启「提问不入折叠」且本轮有 LLM 提问卡时改落到这一轮最后那张卡(并展开它);你已经自己上滚过就不动你(动效关掉时直接到位) |
|
|
100
101
|
| 置顶显示提问 | `pinPrompt` | 开 | 开关 | 把「你正在看的那一轮」的提问钉在会话顶端:往上滚会跟着换成那一轮,超过一行只显示一行;它自己在视口里时自动让位,点它滑回那句话 |
|
|
101
102
|
| 动效过渡 | `animations` | 开 | 开关 | 关掉则折叠/展开/回底全部瞬时 |
|
|
102
103
|
| 小窗火花 | `sparks` | 开 | 开关 | 运行中思考小窗底部的火星(关掉后不建画布、不排帧) |
|
package/lib/client.js
CHANGED
|
@@ -1740,7 +1740,7 @@ function mainFollowTick(dt) {
|
|
|
1740
1740
|
let want = null; // 每帧重算:tail 跟着 floor 长
|
|
1741
1741
|
if (goalKind === "element") {
|
|
1742
1742
|
if (goalEl === null || !goalEl.isConnected) { // task-32:目标丢了 ⇒ 协调作废(立刻折)
|
|
1743
|
-
const retry = settleTurn !== null ?
|
|
1743
|
+
const retry = settleTurn !== null ? settleTargetRow() : null; // S1-2:本轮提问行被重挂载 ⇒ 不放弃导航,按同一目标选择重试一次
|
|
1744
1744
|
goalEl = null; goalKind = "none"; navActive = false;
|
|
1745
1745
|
if (settleTurn !== null) clearSettle("lost");
|
|
1746
1746
|
if (retry !== null && retry.isConnected) navigate({ kind: "element", el: retry });
|
|
@@ -1940,6 +1940,19 @@ function lastUserRow() {
|
|
|
1940
1940
|
const rows = userRows();
|
|
1941
1941
|
return rows.length === 0 ? null : rows[rows.length - 1];
|
|
1942
1942
|
}
|
|
1943
|
+
/** 「回到提问处」的目标行:「提问不入折叠」开启、且**最后一条用户发言之后**还有 LLM 提问工具卡
|
|
1944
|
+
* ⇒ 落在卡所在的那一行(要你看/要你答的是它;你对它的回答是 question-reply 行、不是 user 行)。
|
|
1945
|
+
* 没有更靠后的提问卡、或开关关掉 ⇒ 与旧行为逐字相同(= 你那句话)。 */
|
|
1946
|
+
function settleTargetRow() {
|
|
1947
|
+
const user = lastUserRow();
|
|
1948
|
+
if (state.keepUserQuestions !== true) return user;
|
|
1949
|
+
const rows = chatRows();
|
|
1950
|
+
for (let i = rows.length - 1; i >= 0; i -= 1) {
|
|
1951
|
+
if (rows[i] === user) break;
|
|
1952
|
+
if (isQuestionCard(rows[i])) return rows[i];
|
|
1953
|
+
}
|
|
1954
|
+
return user;
|
|
1955
|
+
}
|
|
1943
1956
|
/** 结束「先滑后折」协调(一次性):清掉标记后立刻排一次扫描,让该轮按正常规则折叠(不留历史闩锁)。 */
|
|
1944
1957
|
/** 记录"用户当场操作过的轮次"(manualState 的**唯一**写入口):值真的变了就立刻取消 settle 协调。
|
|
1945
1958
|
* task-23:滑行途中用户手动折叠/展开该轮 ⇒ 当场按用户操作折,不再等滑行到位。 */
|
|
@@ -1962,8 +1975,9 @@ function settleToPrompt(flow) {
|
|
|
1962
1975
|
if (state.settleToPrompt === false) return false;
|
|
1963
1976
|
if (state.mode !== "fold") return false; // 官方档位:完全不接管
|
|
1964
1977
|
if (writer !== WRITER_US || goalKind !== "tail" || navActive) return false; // 只在"视图钉在末端"时起效
|
|
1965
|
-
const row =
|
|
1978
|
+
const row = settleTargetRow();
|
|
1966
1979
|
if (row === null) return false;
|
|
1980
|
+
queueSettleQCard(row); // 落点是提问卡 ⇒ 先把卡展开(合成点击仍挪到下一帧)
|
|
1967
1981
|
navigate({ kind: "element", el: row });
|
|
1968
1982
|
return true;
|
|
1969
1983
|
}
|
|
@@ -1991,12 +2005,29 @@ function markQCard(card) {
|
|
|
1991
2005
|
if (turn === null) qCardEls.add(card); else qCardTurns.add(turn);
|
|
1992
2006
|
try { card.dataset.dshsfKeepOpen = "1"; } catch { /* ignore */ }
|
|
1993
2007
|
}
|
|
2008
|
+
/** 登记一张待自动展开的提问卡(扫描只登记,点击在下一帧 rAF —— 合成点击会触发 React 同步提交)。
|
|
2009
|
+
* force:已按轮次记过也再排一次 —— 「回到提问处」要把落点那张卡当场展开(React 重挂载会把旧元素连同标记一起换掉)。 */
|
|
2010
|
+
function queueQCard(card, force) {
|
|
2011
|
+
const forced = force === true;
|
|
2012
|
+
if (card.dataset.dshsfKeepClosed === "1") return; // 用户手动折过:不抢开
|
|
2013
|
+
if (!forced && (qCardHandled(card) || card.dataset.dshsfKeepOpen === "1" || qCardQueued.has(card))) return;
|
|
2014
|
+
qCardQueued.add(card);
|
|
2015
|
+
qCardQueue.push({ card, force: forced });
|
|
2016
|
+
if (qCardRaf === 0 && typeof requestAnimationFrame === "function") qCardRaf = requestAnimationFrame(runQCardQueue);
|
|
2017
|
+
}
|
|
2018
|
+
/** 「回到提问处」落点是提问卡 ⇒ 先把卡展开;行里没有卡(或用户手动折过)⇒ 只滑不动。 */
|
|
2019
|
+
function queueSettleQCard(row) {
|
|
2020
|
+
const card = row.matches(Q_TOOL_SEL) ? row : row.querySelector(Q_TOOL_SEL);
|
|
2021
|
+
if (card !== null) queueQCard(card, true);
|
|
2022
|
+
}
|
|
1994
2023
|
/** 下一帧再点:扫描帧里不再背 React 提交的成本。 */
|
|
1995
2024
|
function runQCardQueue() {
|
|
1996
2025
|
qCardRaf = 0;
|
|
1997
2026
|
const batch = qCardQueue; qCardQueue = [];
|
|
1998
|
-
for (const
|
|
1999
|
-
|
|
2027
|
+
for (const item of batch) {
|
|
2028
|
+
const card = item.card;
|
|
2029
|
+
if (!card.isConnected) continue;
|
|
2030
|
+
if (!item.force && qCardHandled(card)) continue;
|
|
2000
2031
|
const target = disclosureTarget(card);
|
|
2001
2032
|
if (!target || target.getAttribute("aria-expanded") === "true") { markQCard(card); continue; }
|
|
2002
2033
|
if (clickOnce(target)) markQCard(card);
|
|
@@ -2382,12 +2413,7 @@ function syncWindows(flow, running, collected, bodies, heights) {
|
|
|
2382
2413
|
// 成本契约:合成点击会触发 React 同步提交(真机实测一次扫描 +30.4ms)⇒ **扫描只登记,点击挪到下一帧**;
|
|
2383
2414
|
// 去重按「轮次」而不是卡片元素(React 重建卡片时元素变了,按元素记会重复点)。
|
|
2384
2415
|
try {
|
|
2385
|
-
for (const card of flow.querySelectorAll(
|
|
2386
|
-
if (qCardHandled(card) || card.dataset.dshsfKeepOpen === "1" || qCardQueued.has(card)) continue;
|
|
2387
|
-
qCardQueued.add(card);
|
|
2388
|
-
qCardQueue.push(card);
|
|
2389
|
-
}
|
|
2390
|
-
if (qCardQueue.length > 0 && qCardRaf === 0 && typeof requestAnimationFrame === "function") qCardRaf = requestAnimationFrame(runQCardQueue);
|
|
2416
|
+
for (const card of flow.querySelectorAll(Q_TOOL_SEL)) queueQCard(card);
|
|
2391
2417
|
} catch (err) { scanErrors += 1; lastScanError = String((err && err.message) || err).slice(0, 120); } // F4:异常计数进诊断(不空吞)
|
|
2392
2418
|
const wiredTools = new Set();
|
|
2393
2419
|
const windowQueue = []; // 先只读、后集中写:量一个写一个会让下一次量强制重排(布局抖动)
|
|
@@ -3652,7 +3678,7 @@ function SettingsPage() {
|
|
|
3652
3678
|
h(Toggle, { value: s.foldHistory !== false, onChange: (v) => setSettings({ foldHistory: v }) })),
|
|
3653
3679
|
h(Row, { title: "保留穿插正文", desc: "折叠时保留带正文的行,用横线与正式回答分开(正文不再套限高小窗)" },
|
|
3654
3680
|
h(Toggle, { value: s.keepInterleavedText !== false, onChange: (v) => setSettings({ keepInterleavedText: v }) })),
|
|
3655
|
-
h(Row, { title: "提问不入折叠", desc: "LLM 的提问工具与其回复(ask_user_question / question-reply):开启则两者都始终保留、不折进「已折叠 N
|
|
3681
|
+
h(Row, { title: "提问不入折叠", desc: "LLM 的提问工具与其回复(ask_user_question / question-reply):开启则两者都始终保留、不折进「已折叠 N 行」,且「跑完回到提问处」改落到最后那张提问卡上;关闭则随其余内容一起折叠" },
|
|
3656
3682
|
h(Toggle, { value: s.keepUserQuestions === true, onChange: (v) => setSettings({ keepUserQuestions: v }) }))),
|
|
3657
3683
|
h("div", { className: "dshsf-group" },
|
|
3658
3684
|
h(Row, { title: "跟随速度上限(px/s)", desc: "我们主动追赶时的速度上限(px/s,默认 " + DEFAULTS.followMaxSpeed + " = 旧 8px/帧@60Hz 的手感)。越小越柔、高速输出时落后越多;前馈(内容自己的增长速度)不受它限制" },
|
|
@@ -3673,7 +3699,7 @@ function SettingsPage() {
|
|
|
3673
3699
|
h(Row, { title: "平滑系数", desc: "跟随底部时每帧吃掉多少差距,越小越柔(默认 0.15)" },
|
|
3674
3700
|
h(NumberInput, { value: s.smoothGrow, min: 0.05, max: 0.9, step: 0.05, onChange: (v) => setSettings({ smoothGrow: v }) })),
|
|
3675
3701
|
h(Row, { title: "离底显示「回到底部」" }, h(Toggle, { value: s.showJumpButton !== false, onChange: (v) => setSettings({ showJumpButton: v }) })),
|
|
3676
|
-
h(Row, { title: "跑完回到提问处", desc: "
|
|
3702
|
+
h(Row, { title: "跑完回到提问处", desc: "一轮结束后平滑移到本轮你那句话的位置;开启「提问不入折叠」且本轮有 LLM 提问卡时,改落到最后那张卡并自动展开(要你答的是它);你已经自己上滚过就不动你。动效过渡关掉时直接到位" },
|
|
3677
3703
|
h(Toggle, { value: s.settleToPrompt !== false, onChange: (v) => setSettings({ settleToPrompt: v }) })),
|
|
3678
3704
|
h(Row, { title: "置顶显示提问", desc: "把「你正在看的那一轮」的提问钉在会话顶端,往上滚动会跟着换成那一轮(超过一行只显示一行);它自己在视口里时自动让位,点它滑回那句话" },
|
|
3679
3705
|
h(Toggle, { value: s.pinPrompt !== false, onChange: (v) => setSettings({ pinPrompt: v }) })),
|