DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

liufeicc /

liufeicc/dsh-btw-command

Verified

/btw slash command for DSH: ask a side question or inject information into a running agent session

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@d51da78f

/btw —— 运行中插一句话

主 agent 正在跑的时候,问一句、或者补一条信息,都不打断它。

/btw 为什么这一步这么慢
/btw 记住 MEMORY.md 已经改过,别再改

两种行为,由旁注助手自己判(不需要 ? 前缀)

用户说的话 判定 实际发生什么
提问题(进度 / 原因 / 某个数值) question 起一次独立的模型请求,回答作为命令结果返回
补充事实 / 决定 / 约束 / 偏好 info 整理成一条记忆条目,agent.inject() 投到 next-step

提问为什么是"独立请求"而不是 steer

steer 的消息是用户指令,模型会把它当成新的主任务:常见后果是丢掉手上的活,或者把已完成的一步重做。旁注要的恰恰是"只回答、不改变"。

所以提问走这条路:

  1. session.deriveMessages() 拿到当前会话真正送给模型的那份历史(压缩、裁剪、投影都算好了);
  2. 原 system prompt 保留(旁注要知道这个会话在干什么),末尾追加一段"你现在是旁注助手,只回答、不动手";
  3. ctx.llm.stream() 发一次请求,模型路由取 session.requestHeader().config —— 和主线同一个模型;
  4. 回答作为命令结果返回。command/run / command/done 是 log-only 事件,不进模型上下文,所以主 agent 的上下文一个字都没多。

补充信息为什么走 inject

agent.inject() 的语义正好对上:

Queue model-facing context for the next pre-step without waking the driver. A running driver claims it at the nearest later step boundary.

也就是:进下一步的 pre-step 收件箱、不唤醒正在跑的 driver、下一个模型请求里就能读到。注入的消息带 [补充信息 · 用户插话] 前缀和"不要把它当成新任务"的说明——它是 user 角色,不加这句模型很可能当成新指令。

判错了会怎样

  • 解析不出 JSON ⇒ 一律退化成"回答原文"(当提问),绝不会把没解析出来的内容注入记忆。
  • info 但 memory 为空 ⇒ 同样退化。
  • 往记忆里塞脏数据比分错类危险得多,所以这里刻意不对称。

配置

行里的 config 全部可省略:

键 默认 说明
enabled true 总开关
historyMessages 40 喂给旁注助手的历史条数上限
maxHistoryChars 120000 历史字符上限(大会话兜底)
maxAnswerChars 4000 回答最大字符数
timeoutMs 120000 单次旁注请求超时

界面:两个入口,同一份数据

入口 行为
输入框工具行的气泡按钮(+ 号右侧) 浮层里提问,回车发送
输入框直接敲 /btw … 同一个命令节点 ⇒ 浮层自动弹出并显示答案

两条路都产生 command/run + command/done,浮层渲染的永远是最新一条 btw 命令节点 (useChat 读 snapshot.nodes.values(),该 API 明确包含被折叠隐藏的节点)。所以 Agent 正在跑、对话流把行折进「运行过程」时,浮层照样能显示——这是它存在的理由。

对话流里另有一张同源卡片(conversation.chat.commandview 的 btw 键):空闲时按 时间线显示,位置更自然;运行中会被折叠,需要时点开「运行过程」也能看到。

浮层怎么跟随窗格

浮层不再按整个视口写死 left:24; bottom:132。打开时按触发按钮、composer 和 所在窗格的实时矩形计算:

  • 底边贴在 composer 上方 8px,不压住输入框;
  • 宽度不超过当前窗格,平铺成窄格时不会横跨到隔壁;
  • 高度限制在 composer 上方的可用空间,放不下时浮层内部滚动;
  • 通过 portal 挂到 document.body,避免被 composer 的层叠上下文或 overflow 裁掉;resize / scroll / ResizeObserver 会跟着窗格尺寸变化重新定位。

输入框为什么能立刻清空

composer 是在 commands.execute 结算之后才清空输入框的。所以命令被拆成两段:

  1. btw handler 立刻返回占位文本 → 命令结算 → 输入框清空、节点出现;
  2. 后台跑完模型调用,用同一条 commandId 再追加一条 command/done。客户端按 commandId 折叠生命周期,后到的 done 覆盖前一个的 outcome(dsh-client-ui-chat 的 commandFromDone(match, previous) 就是这么写的),于是同一张卡片/浮层原地刷新 成答案,不新增行、不新增事件类型。

已知边界

  • 旁注助手看的是模型可见历史。主 agent 正在等一个 20 分钟的构建时,"还在跑"这件事不在历史里,旁注只能从工具调用和结果推断。要更准得让它读会话日志尾部或 job 表(P2)。
  • 历史从最近一条 user 消息切开:OpenAI 兼容协议要求 tool 结果对得上前面的调用,从中间切会被网关拒。
  • 回答是一次性返回的,不是流式(P2)。

测试

node --test test/*.test.mjs

25 条用例,重点覆盖三个不变量:提问不注入、补充信息才注入、解析失败绝不注入; 另有 5 条浮层几何用例(主对话、窄窗格、极窄窗格、按钮未测量、无 composer 兜底)。

—/ 5

No ratings yet

Verified DSH bundle

Commit d51da78fa817

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout