Passer au contenu principal
L

dsh-btw-command

liufeicc/dsh-btw-command

Adds a /btw slash command that asks a side question or injects information into a running session without interrupting the main agent.

Installer

dsh plugin --profile web add github:liufeicc/dsh-btw-command

README

/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 全部可省略:

键默认说明
enabledtrue总开关
historyMessages40喂给旁注助手的历史条数上限
maxHistoryChars120000历史字符上限(大会话兜底)
maxAnswerChars4000回答最大字符数
timeoutMs120000单次旁注请求超时

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

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

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

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

输入框为什么能立刻清空

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/btw.test.mjs

17 条用例,重点覆盖三个不变量:提问不注入、补充信息才注入、解析失败绝不注入。

Plugins associés