← 返回列表
未验证
自研 dsh 插件合集 · dsh-btw: 划选引用 / btw 临时会话 / 新上下文 / Provider…
尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/9/14 · 已提供中文文档
自研 dsh 插件合集 · dsh-btw: 划选引用 / btw 临时会话 / 新上下文 / Provider 高级配置
综合分
28.9
GitHub 分
28.9
用户评分
—
★ Stars
0
周下载量
—
兼容 / 相关生态插件(非 dsh 原生,请按其对应运行时安装)
git clone https://github.com/jasonjiang9527/dsh-plugins.git信任档位:已验证本站已于 0 天前真实安装成功
- 是什么
- 生态应用(桌面端 / Web 外壳,不以 dsh plugin add 安装)
- 装得上吗
- 本站已真实安装成功(非静态推断)
- 安全吗
- 本站尚未对该插件做风险分级(暂未覆盖,不等同于无风险)
- 还在维护吗
- 活跃:最近一次提交在 11 天前
档位由下列信号合成:本站实装验证(真实安装,当前最高到 L4)· 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。下方各区块是它的证据明细。 验证判据与等级说明 →
🟢实装验证通过· 2026/9/25
由本站实装验证器在真实 dsh 环境安装成功,非静态推断。
数据截至 2026/9/24(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动
README
由 DeepSeek 最新模型翻译生成dsh-btw 💬
顺便说一句:将任意选中的聊天文本引用到输入框,或从选中的消息启动一个一次性临时会话——离开时自动归档,让主对话保持整洁。
license platform dsh
dsh 临时会话插件:在会话历史里划选任意内容时浮现操作条——引用到当前输入框,或开一个一次性的 btw 临时会话(离开即自动归档)。顺手一问,问完即走,不污染当前会话,不弄乱侧边栏。另有新上下文:就地切分本会话的模型上下文,历史保留但不再发送。
命名取自 Claude Code 的 /btw 习惯:by the way,顺便一问,不进主线。
功能
| 动作 | 行为 |
|------|------|
| 引用提问 | 选区以「引用块 + 来源头」(含源会话标题与时间)预填进当前会话输入框草稿(不发送),继续编辑后发送 |
| btw | 从选中消息所在节点 fork 出一个一次性临时会话并自动切换;会话改名「🔍 btw · 」,输入框预填 btw 引用块 |
| 自动归档 | 离开 btw 会话时自动从侧边栏归档隐藏(running 时顺延到空闲,可在设置关闭) |
| 新上下文 | 输入框工具行的「⧉ 新上下文」按钮(或斜杠命令 /newcontext):就地切分上下文,此前的历史不再发送给模型,但会话记录完整保留 |
| Provider 高级配置 | Models 设置页每个 provider 卡片下新增「高级配置」折叠面板,把 settings.yaml 里的隐藏字段全部可视化;含模型级配置项——按模型 id 覆盖 name / 容量 / 输入类型 input / reasoningEfforts / compat(见下节) |
细节:
- 浮层只在会话消息区的选区上出现(输入区、设置面板等不触发);Esc / 滚动 / 点关闭按钮收起;
- 引用块多行逐行加 > 前缀;超过截断长度(默认 2000 字符)加省略号;
- 既有草稿会保留在引用块之后;
- 中英双语文案,随 dsh 界面语言切换;文案缺失时降级中文。
安装
要求:dsh 0.1.5-rc.2(web 端)。此前的 0.1.1-rc.2 适配已失效,改动清单见 CHANGELOG.md 的 0.1.1 条目。
仓库 jasonjiang9527/dsh-plugins 是自研 dsh 插件的合集;
dsh-btw 目前就放在仓库根目录(等有了第二个插件再改成 dsh-btw/ 子目录 + #path:/dsh-btw 的装法)。
从本地路径安装(web profile)
dsh plugin --profile web add
或从 GitHub 安装
dsh plugin --profile web add git+https://github.com/jasonjiang9527/dsh-plugins.git
确认组合树里出现 dsh-btw
dsh --profile web --dump-config
重启 dsh web 并刷新页面,客户端 bundle 才会生效
卸载 / 回滚:
dsh plugin --profile web remove dsh-btw
注意:boot graph 在服务启动时构建。安装后或修改插件源码后都需要重启 dsh web(若以 link: 方式安装,源码改动即时生效,但仍需重启让 bundle 重新入图)。
新上下文(New context)
同一个会话内的逻辑切分:像 Cherry Studio 的「新建话题」,但历史不删、不分叉、不换会话。
- 点输入框工具行的 ⧉ 新上下文,或直接输入 /newcontext;
- 此后发给模型的请求只剩「系统提示 + 一条 notice + 此后新增的消息」——之前的历史全部不再发送;
- 会话记录照旧完整显示(历史仍在日志里,只是退出模型上下文),可以回看、可以复制;
- 累积:可以反复切分,每次都从当前状态重切,等效于"只保留最新一段";
- 分割点是一条写进会话日志的事件,所以重启 dsh、恢复会话、fork 子会话后依然成立。
原理:客户端插件碰不到发给模型的 messages(那由 dsh-agent-loop 从会话日志的
可见面 surface 派生并冻结后交给适配器),所以这个功能由宿主半边(lib/index.js)
实现 —— 它把 surface 上除系统提示外的全部节点,用一条 replace 操作替换成一条
plugin: dsh-btw / form: notice 的 user 消息。这与 /compact 是同一套原生机制,
区别只是不生成摘要。按钮只是触发器,内部走 ISession.command("/newcontext"),
和你手打斜杠命令同一条路。
使用
1. 在会话历史里划选一段内容 → 选区旁浮出操作条;
2. 引用提问:输入框出现引用块(保留原草稿),编辑补充你的问题后发送;
3. btw:切到一次性临时会话「🔍 btw · 」——历史完整、上下文锚定在选中消息处,输入框已预填 btw 引用块,直接提问;
4. 离开 btw 会话时 → toast「已归档」,侧边栏无残留。
5. 新上下文:在输入框工具行点「⧉ 新上下文」(或打 /newcontext)→ toast 确认,
此后该会话不再把之前的历史发给模型;继续正常提问即可。
flowchart TD
A[划选消息区文本] --> B[mouseup 取样]
B -->|命中| C[浮层:引用提问 / btw]
C -->|引用提问| D[setDraft 预填引用块]
C -->|btw| E["sessions.fork(atSeq = 节点 anchorSeq)"]
E --> F[临时会话改名 🔍 btw · …]
F --> G[自动切换 + 预填 btw 引用块]
G --> H[离开且非 running → archiveSession]
设置(localStorage)
| 键 | 默认 | 说明 |
|----|------|------|
| dsh-btw:autoArchive | "1" | 离开 btw 会话时自动归档;"0" 关闭 |
| dsh-btw:truncateChars | "2000" | 引用文本截断长度(≥100 生效) |
| dsh-btw:activeBtws | [] | 活跃 btw 会话表(内部持久化,勿手改) |
Provider 高级配置面板
设置 → Models 页,每个 provider 卡片下方有「高级配置(dsh-btw)」折叠面板。dsh 官方 Models 页只暴露 API key / 显示名 / Base URL / 模型列表等基础字段,其余高级参数只能手改 settings.yaml——本面板把它们全部可视化,读写走官方 RPC(settings.describe / settings.mutate 乐观锁),保存时服务端 schema + serviceable 校验兜底。
可视化字段(llm-pi-ai 命名空间,providers. 下):
| 分组 | 字段 | 说明 |
|------|------|------|
| 端点与协议 | displayName / baseURL / api | api ∈ openai-completions \| openai-responses \| anthropic-messages |
| 超时 | timeoutMs / streamIdleTimeoutMs / websocketConnectTimeoutMs | 毫秒 |
| 传输与缓存 | transport / cacheRetention / reasoning | transport ∈ auto\|sse\|websocket\|websocket-cached;cacheRetention ∈ none\|short\|long;reasoning ∈ off…max |
| thinkingBudgets | minimal / low / medium / high | 推理 provider 的 token 预算 |
| 容量与模态兜底 | defaultContextWindow / defaultMaxTokens / defaultInput | 未声明模型的兜底值(默认 262144 / 32768 / ["text"]);defaultInput 是模型自己没声明 input 时的兜底输入类型 |
| headers | 自定义请求头 | 每行 Name: Value;凭据请走 apiKeyEnv,勿写入此处 |
| 模型配置 | modelOverrides. 全字段 | 见下节:name / contextWindow / maxTokens / input(支持的输入类型) / reasoningEfforts / compat |
| retryPolicy | mode / maxRetries / retryableCodes / backoff. | normal(可配重试次数与错误码)或 always |
模型配置项(modelOverrides.)
「模型配置」分组按模型 id 逐行覆盖目录里的模型,一行一个模型的全部模型级字段
(= dsh-llm-pi-ai schema 的 modelFields 全集):
| 字段 | 控件 | 说明 |
|------|------|------|
| name | 文本框 | 显示名 |
| contextWindow | 数字框 | 该模型的上下文窗口 |
| maxTokens | 数字框 | 该模型的最大输出 |
| input | 多选:text / image | 该模型支持的输入类型(请求模态)。都不勾 = 不声明 = 继承目录;声明 image 是让自建视觉模型可用的关键,只声明 text 可修正网关并不提供图片的目录模型 |
| reasoningEfforts | 三态选择 | 继承目录 / false(声明非推理模型,用于剥掉网关服务不了的推理)/ 自定义:文本框每行 等级: wire 拼写(等级 ∈ off/minimal/low/medium/high/xhigh/max,wire 留空 = null) |
| compat | 勾选组 | supportsTemperature / forceAdaptiveThinking / allowEmptySignature / supportsStrictTools / requiresThinkingAsText / supportsCacheControlOnTools |
input 是对端点的声明而非探测:pi-ai 不会去问网关接受什么,声明了图但端点拒绝,会在回合中途由 provider 报错。
行为细节:
- 字段留空 = 继承目录/协议默认(保存时 unset,不写死值);
- 只对改过的字段生成写入(打开面板时快照做 diff,不把 base 层值钉进 user 层);
- modelOverrides 是整字段重写,但面板读写的正是 modelFields 全集,因此不会丢掉手写在
settings.yaml 里的其它模型级配置(回归用例见 scripts/check-form.mjs 的 round-trip 断言);
- route 上若已声明 models 列表,modelOverrides 与之互斥(服务端拒绝),面板会就地提示;
- 配置冲突(别处同时改动)会明确提示,收起重新展开即可;
- 凭据仍走官方 API key 表单(credentials seam),本面板不碰密钥。
工作原理
纯客户端插件,只走 dsh 公开扩展面,零核心改动:
- 浮层:注册到 shell.overlay 座位(root 作用域),document 级 mouseup + rAF 取样,用 ui-conversation 自身的 data-conversation-scroll / data-chat-anchor-key DOM 锚点判定选区位置;
- 会话桥:注册到 conversation.session.header.utilities 座位(session 作用域,零渲染高度),借 standard kit 拿到 inputActions.setDraft、输入草稿快照与 useChat 的聊天节点面,提升给 root 作用域的浮层使用;
- fork 锚点:useChat((s) => s.nodes) 拿到的 ChatNodeStore.get(选中行 data-chat-anchor-key).anchorSeq 定位选中节点(dsh 0.1.5 起 SessionSnapshot 已无 chat,节点面只能从 session 作用域的 kit 取);fork 后 child.rename() 钉住临时会话标题(不被 LLM 自动再生);
- 归档 watcher:root 级订阅 sessions.list,当前选择离开“活跃 btw 会话”且该会话不在 running 时调用 workspaces.archiveSession;
- 配置面板:注册到官方预留的 settings.models.provider-card 座位(ui-settings-models 声明;0.1.5 起为 keyed 座位,注册键 = key: "llm-pi-ai"),读 settings.describe()、写 settings.mutate(ns, ops, revision)(乐观锁 revision),diff 后最小化写入;模型级字段落在 modelOverrides. 的 modelFields 全集上(input 即输入类型多选);
- 新上下文:宿主半边注册 /newcontext 命令(ctx.commands.register),把会话 surface 上除系统提示外的全部节点 replace 成一条 notice;客户端按钮注册到 conversation.input.left,点击走 ISession.command;
- 宿主半边:lib/index.js 是真正的 cordis 插件(inject: ["commands","sessions"]),零运行时依赖(notice 消息手工构造,不 import @deepseek-ai/,因为 link 安装的目录解析不到它们);
- hooks 纪律:任何 hook 都不条件调用(useInput / useChat 各由内层子组件无条件调用,组件本身按宿主能力条件渲染)。
兼容性(dsh 升级时的核对清单)
本插件只走公开扩展面,但公开面本身会随版本漂移。实测基线:dsh 0.1.5-rc.2。升级后请依次核对:
| 依赖面 | 位置 | 0.1.5 现状 |
|--------|------|------------|
| Cordis inject 服务 key | lib/client.js 尾部 | slots / sessions / workspaces / locale / remote / remote.settings(必须是服务名,不是包名) |
| shell.overlay 座位 | 浮层 | list 座位,注册 { id } |
| conversation.session.header.utilities 座位 + standard kit | 会话桥 | useInput / inputActions.setDraft / useChat 均在 |
| settings.models.provider-card 座位 | 配置面板 | keyed 座位,注册 { key: "llm-pi-ai" } |
| settings.describe() / settings.mutate(ns, ops, rev) | 配置面板 | describe 无参、writable 在信封顶层;mutate 结果含 revision;冲突码 settings/conflict |
| sessions.list / .binding / .fork({sessionId, atSeq}) / .open | fork 与归档 | 均在 |
| workspaces.archiveSession | 自动归档 | 在(单向,无 unarchive) |
| commands.register + sessions.get | 宿主半 /newcontext | 在;命令定义全局可见 |
| surface replace 契约(session.surface.nodes / append(..., { surfaceOp })) | 宿主半切分 | 与 /compact 同一机制,规则由 scripts/check-newcontext.mjs 对着真实 dsh-session 验证 |
| DOM 锚点 | 选区判定 | data-conversation-scroll / data-chat-anchor-key / data-composer-seat 均在;data-input-mirror 已移除 |
自检会覆盖其中可静态断言的部分:
npm run check # 语法 + 结构 + i18n key 覆盖 + formToOps diff 语义单测
node scripts/check-newcontext.mjs # 用部署里真实的 dsh-session 验证切分契约
check-newcontext.mjs 需要机器上装过 dsh:它按 $DSH_SESSION_PKG →
node 可执行文件旁的全局安装 → %APPDATA%\npm → $DSH_HOME/profiles/ 的顺序找
@deepseek-ai/dsh-session,找不到就明确报错(其余两个脚本无外部依赖)。
已知限制
- 归档是单向操作(当前 dsh 版本没有 unarchive API):归档后仅从侧边栏隐藏,会话日志仍在磁盘 ~/.dsh/sessions/ 下,数据不会丢;
- 正在运行的回合(streaming 尾部)不能作为 fork 锚点,此时 btw 按钮会给出提示;
- 依赖 ui-conversation 的 data- DOM 锚点:dsh 升级若改变这些属性,需同步本插件的选择器常量;
- 宿主若不再提供 useChat(聊天节点面缺席),btw 仍可 fork,但锚点退回 fork 的缺省边界——即从已完成回合的末尾切,而不是从选中消息处切。
常见问题
Q: 为什么叫 btw?
A: 沿用 Claude Code 的 /btw——by the way,顺手一问。btw 会话是一次性的:问完离开即自动归档,主线与侧边栏都保持干净。
Q: 我的原始会话标题看起来被加了后缀?
A: 不是本插件。dsh 会自动用 LLM 根据你的第一句话生成会话标题,措辞纯属巧合。本插件只给 btw 临时会话改名(🔍 btw · …),从不修改源会话。
Q: 归档的 btw 会话去哪了?
A: 只是从侧边栏隐藏,日志仍在 ~/.dsh/sessions// 下,可以随时去磁盘查看。
Q: 划选后浮层没出现?
A: 浮层只在会话消息区生效;输入框、本浮层自身等区域被排除,少于 2 个字符的选区也会被忽略。
开发
dsh-btw/
├── lib/
│ ├── client.js # 浏览器半边:手写 CJS factory(ModuleLoader),交互功能所在
│ └── index.js # 服务端半边:/newcontext 命令 —— 把一段历史移出模型上下文
├── cordis.patch.yml # 组合树 patch(insert 插件节点)
├── scripts/check.mjs # 静态自检(语法 + 结构 + i18n key 覆盖)
├── scripts/check-form.mjs # formToOps diff 语义单测(从 client.js 抽纯函数跑)
├── scripts/check-newcontext.mjs # 切分契约测试(对付真实 dsh-session 的 foldSurface)
└── package.json # dsh.client.platform = "web"、exports["./client"]
自检:
npm run check # = check.mjs + check-form.mjs
npm run check:newcontext # 需要机器上装过 dsh
无需构建器:lib/client.js 是手写的 CommonJS factory(window.__ModuleLoader__.load({ id, factory })),运行时依赖由 dsh 注入(react 为 shell 预置种子模块)。修改源码后重启 dsh web 即可看到效果。
License
MIT