# dsh-smooth-stream

> 为 DeepSeek Harness Web 界面接管助手回复与工具结果的自适应流式渲染与平滑跟随滚动，并接入"丝滑流式"用户设置卡。

## Metadata

- Author: [@Laplace-bit](https://github.com/Laplace-bit)
- Repo: <https://github.com/Laplace-bit/dsh-smooth-stream.git>
- GitHub: [Laplace-bit/dsh-smooth-stream](https://github.com/Laplace-bit/dsh-smooth-stream)
- Stars: 43
- Language: JavaScript
- License: [MIT](https://spdx.org/licenses/MIT.html)
- Homepage: <https://laplace-bit.github.io/dsh-smooth-stream/>
- Topics: `ai-chat`, `chat-ui`, `cordis`, `deepseek`, `deepseek-harness`, `developer-tools`, `dsh`, `dsh-plugin`, `fluid-streaming`, `llm`, `markdown`, `plugin`, `react`, `smooth-scrolling`, `smooth-streaming`, `streaming`, `streaming-markdown`, `typescript`, `web-ui`
- Forks: 4
- Open Issues: 1
- Last push: 2026-08-20T08:44:50.000Z
- Added: 2026-08-20T00:00:00.000Z

## Install

```bash
dsh plugin --profile web add github:Laplace-bit/dsh-smooth-stream
```

## Wiki

## 一句话定位
dsh-smooth-stream 是 DeepSeek Harness（`dsh`）Web 界面的第三方插件，用"打字机"式的自适应揭示接管助手回复、Markdown、代码块、表格和工具结果的渲染，并在内容增长时让页面平滑跟随滚动，避免长回复一次性铺满或频繁跳行。

## 核心能力
- 把助手回复（文本块、Markdown、代码块、表格）按打字机节奏逐字揭示，标题/列表等结构在流式过程中持续可用
- 用同一套 follow 边界包裹 Agent 拥有的聊天行（Tool、Context、Command、重试等），让多行场景保持一条连续滚动轨迹
- 实时观察模型到达速率（EMA）来调整揭示速度：慢输出从容展示，快输出及时跟上，闲置期以限定速度收尾排空
- 在 Web 界面"设置 → 插件 → 插件配置"提供"丝滑流式"卡片，开关插件接管、切换"自动展开思考"两项偏好即时生效
- 内置 FPS 守护（30 fps 阈值）与 `prefers-reduced-motion` 适配，屏外低帧或开启减少动画时直接显示完整文本，不与可见帧抢资源
- 支持 Host 的 npm 安装包固定更新流程：检测到 profile 用 npm 注册表安装时，UI 卡片显示"更新"按钮，调用同一 `pnpm update`

## 技术实现
- **语言**: TypeScript（ESM，`type: module`，构建工具 `tsdown`）
- **关键依赖**: `@deepseek-ai/cordis`（Host 插件运行时）、`@deepseek-ai/schemastery`（配置 Schema）、`@deepseek-ai/dsh-settings`（用户级设置注册）、`react` ^18.2.0（浏览器渲染层）
- **架构模式**: 双端 Cordis 插件。`src/plugin.ts` 是 Host 端：`apply(ctx, config)` 打印 `[dsh-smooth-stream] plugin loaded!` 横幅、调用 `webServer.tapIndex` 把 Schema 校验后的配置作为 `window.__DSH_SMOOTH_STREAM_CONFIG__` 内联脚本注入到 `index.html`，再注册 `smooth-stream` 命名空间的用户设置和仅 loopback RPC（读/写/触发 npm 更新）。`src/client/index.ts` 是浏览器端：从内联配置读取后，通过 `slots` 影子化 `assistant-step` 并就地包裹其它 Agent 行；用户级偏好通过插件自己的 loopback RPC 同步，绕开第三方 namespace 默认 allowlist。
- **入口文件**: `src/index.ts`（Host 端导出 `apply/name/Config`），`src/client/index.ts`（客户端 `apply`，`exports` 通过 `./client` 子路径暴露）

## 适用场景
喜欢长篇 Markdown、代码块、表格或工具调用结果逐步出现在 DSH 上的用户，例如想看着思考过程一边落字一边展开的代码审查场景；或者希望阅读节奏不被一次性刷屏打断的方案对比 / 长文写作 / 报告生成。普通短回复也能直接受益——它把 Harness 内置的"块状铺设"换成单一连续揭示曲线。

## 前置依赖与兼容性
| 依赖 | 最低版本 | 说明 |
|---|---|---|
| DeepSeek Harness（cordis、settings、connection、conversation、UI 套件等） | 0.1.0-rc.6+ | 来自 `peerDependencies` 和 `devDependencies` 锁定值，cordis ^4.0.1 |
| Node.js | ^22.19.0 或 >=24.0.0 | 来自 `engines.node` |
| React | ^18.2.0 | 来自 `peerDependencies`，用于浏览器端渲染 |
| 宿主 profile | Web profile（`dsh.client.platform: web`） | 本插件只为 Web 宿主面注册到 `cordis.patch.yml`，CLI/Desktop 不会被注入 |
| 平台 | macOS / Windows / Linux（任意带现代浏览器的桌面 OS） | `engines` 无 `os` 限制；客户端是浏览器，无原生模块依赖 |
| 原生模块 | 无 | 纯前端渲染 + Cordis RPC，无 `node-pty` / `node:sqlite` 等 |

## 安装方式
```bash
dsh plugin --profile web add github:Laplace-bit/dsh-smooth-stream
```

## 配置项
本插件包含两类配置：**profile 级组合配置**（写在 `cordis.patch.yml` 里、改完需重启 Harness）和**用户级偏好**（在 Web 设置卡里改、即时生效）。

Profile 级组合配置（字段由 Host 端 Schema 校验）：
| 配置 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| `mode` | `typewriter` / `teleprompter` | 兼容性字段，两种 mode 当前都走同一套自适应揭示引擎 | `typewriter` |
| `preset` | `realtime` / `balanced` / `silky` | 揭示节奏预设：`realtime` 更贴模型到达；`balanced` 默认；`silky` 缓冲最大、跟进最慢 | `balanced` |
| `revealCharsPerSec` | 5–200 的数字 | 旧版字段，仍被加载但运行时不再使用，自适应引擎只跟到达速率 | 80 |
| `scrollSpeedPxPerSec` | 1–200 的数字 | 旧版字段，仍被加载但运行时不再使用，跟随走 smooth-damp 而非巡航速度 | 48 |
| `maxScrollSpeedPxPerSec` | 1–2000 的数字 | 旧版字段，仍被加载但运行时不再使用 | 1000 |

用户级偏好（写入 dsh 用户设置文档，通过插件自己的 loopback RPC 编辑，无需重启）：
| 偏好 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| `enabled` | 布尔 | 总开关：开启时由本插件接管回复和工具行的渲染与跟随；关闭后会撤销接管、完整回退到 Harness 内置渲染 | `true` |
| `thinkAutoExpand` | 布尔 | 思考（Think）块是否在流式期间自动展开，思考结束后再收起；关闭后保持折叠但仍可手动展开。`enabled = false` 时本项不再生效 | `true` |

## 常见问题

**Q: 这个插件是做什么的？**

A: 它在 DSH 的 Web 界面把助手回复按打字机节奏逐字揭示，Markdown 结构在流式时也保持可用；同时接管跟随滚动，让多行 / 多工具场景也走同一条视觉曲线，不让页面反复跳。

**Q: 这是官方插件吗？**

A: 不是。代码仓库和 README 都明确：本项目是独立维护的 MIT 授权插件，与 DeepSeek 公司没有官方从属关系。

**Q: 支持 `prefers-reduced-motion` 和低帧率吗？**

A: 支持。系统开启减少动态效果时（`window.matchMedia('(prefers-reduced-motion: reduce)')`）直接展示完整文本、不接管跟随；流式时若帧率持续低于 30 fps 且回复位于屏外，揭示会被 FPS 守护暂停，等恢复后再补上。

**Q: 如何切换流式节奏？**

A: 在安装 profile 的 `cordis.patch.yml` 里把 `config.preset` 改为 `realtime`（贴近模型到达）、`balanced`（默认）或 `silky`（缓冲最大、跟进最柔），保存后重启 Harness 即可看到差异。

**Q: 安装后还需要额外做什么吗？**

A: 通常不需要。npm 包随包带预构建的 `lib/`，所以不用 pnpm ≥10 的构建脚本授权；安装命令完成后 `dsh web` 启动，Host 日志出现 `[dsh-smooth-stream] plugin loaded! ...` 表示加载成功。

**Q: 如何卸载？**

A: 在 dsh 源码目录运行 `dsh plugin --profile web remove dsh-smooth-stream` 即可，UI 会回到 Harness 内置渲染，组合包配置也会被一并撤掉。

**Q: 可以从 npm 安装吗？**

A: 可以。`dsh plugin --profile web add dsh-smooth-stream` 安装的就是 `Laplace-bit/dsh-smooth-stream@0.3.4` 这个 npm 包的预构建产物。

**Q: 怎么更新到这个插件的新版本？**

A: 如果安装时走的是 npm 包（不是 `link:` / `file:` 本地开发），网页"丝滑流式"卡片会显示"更新"按钮，点一下它会在当前 profile 目录下跑一次固定的 `pnpm update dsh-smooth-stream`，完成后会提示重启 Harness；也可以从命令行跑 `dsh plugin --profile web update dsh-smooth-stream`。

**Q: 这个插件只能装在 Web profile 吗？**

A: 是。`package.json` 的 `dsh.client.platform` 声明为 `web`，Hook 面板里只注册了 `@deepseek-ai/dsh-client-runtime`、`@deepseek-ai/dsh-client-ui-conversation`、`@deepseek-ai/dsh-client-locale`、`@deepseek-ai/dsh-client-connection`、`@deepseek-ai/dsh-client-ui-settings`、`@deepseek-ai/dsh-client-ui-settings-plugins` 这一组 Web 相关的客户端包，因此不会自动注入 CLI / Desktop 等其它宿主面。

**Q: 报错或没看到效果怎么办？**

A: 优先检查 Host 日志是否出现 `[dsh-smooth-stream] plugin loaded!` 字样；如果没出现，多半是 profile 没勾上插件或浏览器已被改造。如果是 boot 配置不合法（错误码见 `dsh-smooth-stream: malformed __DSH_SMOOTH_STREAM_CONFIG__`），可以把 `cordis.patch.yml` 的 `config` 段清空让它重新走默认。

## 上手难度
入门 —— 安装即用，默认配置即可工作；只有想切换节奏或停用插件时才需要改 `cordis.patch.yml` 或设置卡，不需要修改 React / 源码。

## 已知问题与限制
- `revealCharsPerSec`、`scrollSpeedPxPerSec`、`maxScrollSpeedPxPerSec` 三个 legacy 数字字段仍能被 Schema 接受，但运行时已不再使用，自适应引擎只看 `preset`（见 `src/config.ts:20-30`）；用户改这些字段不会改变手感，只有 `preset` 才有效果
- 思考块处于流式尾部时，root 节点刻意不开启 pre-paint 的横向位移，避免在快节奏推理下把空白 runway 露在固定 turn-status 上方；如果你依赖"提前打位置"的体验，需要关掉流式或停用插件（`src/client/TypewriterAssistantNodeView.tsx:513-522`）
- 一次点击"更新"按钮只能在 profile 用 `npm:` / 通用注册表范围声明时生效；`link:` / `file:` 本地开发安装和 `catalog:` / `patch:` / `portal:` / `workspace:` 等非注册表说明符会被识别为不可更新，更新按钮保持禁用以保护源码目录（见 `src/profile-installation.ts:56-77`、`:100-102`）
- 这个插件只为 Web profile 设计，不为 CLI / 其他宿主面注册；试图装到非 web profile 不会生效但也不会报错，需要自己把 profile 改回 web（`package.json:65-78`）

---

This document is auto-generated by [deepseek-plugin.org](https://deepseek-plugin.org). HTML page: [dsh-smooth-stream](https://deepseek-plugin.org/plugins/Laplace-bit/dsh-smooth-stream)
Wiki generated by AI (model: `MiniMax-M3`)
