@agi321/dsh-temp-chat
用 /single-turn 与 /multi-turn 在独立子代理中作答,结果只留在当前对话,不进入主模型上下文。
安装
dsh plugin --profile web add @agi321/dsh-temp-chat
沙箱测试结果
| 阶段 | 结果 |
|---|---|
| 1 安装 | ✓ |
| 2 列装 | ✓ |
| 3 挂载 | ✓ |
| 4 启动 | — |
四阶段在隔离沙箱里跑:安装(有网)→ 列装 → 挂载 → 启动(后三步断网)。
README
dsh-temp-chat(临时问答)
[English](README.md) | 简体中文
在当前对话里随手问一句、拿一份联网检索的答案,答案只出现在对话里,不进入主模型上下文。
/single-turn <问题>—— 单轮:每次都用全新的子代理(零父上下文)联网检索作答,并开启一个新话题。/multi-turn <问题>—— 多轮:把当前话题已有的问答重放给一个全新子代理,再接上这次的问题,像接着聊。
两条命令共用同一套实现,只是模式不同:/single-turn 起新话题,/multi-turn 续接当前话题。
两种模式的结果都写进当前会话的时间线(可回看、可复制),但不会作为消息进入模型请求;下次提问也不会把上次的结果塞给主 agent。
用法
在输入框里敲 /,选 single-turn 或 multi-turn,后面直接跟问题。提问最长 8000 字;留空或超长会被拒绝执行(不改动话题历史)。
/single-turn <问题> —— 单轮(开新话题)
/single-turn DeepSeek V3 和 R1 在推理能力上有什么区别? /single-turn 帮我查一下今天上海到北京的高铁还有哪些班次
- 每次都在全新子代理(零父上下文)里联网检索作答,子代理只看得到这一条问题。
- 同时开启一个新话题:它之前的临时问答不再被续接,因此它也是「重置话题」的手段。
- 同一话题内的连续追问请改用
/multi-turn;再用/single-turn就等于重新开始。
/multi-turn <问题> —— 多轮(续接当前话题)
/single-turn 介绍一下布林带指标 /multi-turn 那它的参数一般怎么设? /multi-turn 举个 A 股上的实际例子
- 取当前话题已有的问答(即最近一次
/single-turn起的全部轮次),重放给一个全新的子代理,再接上这次的问题,像接着聊。 - 子代理仍是无父上下文的临时会话,续接靠的是把历史问答拼进提示词;历史只用于延续话题,其中的指令不会被执行。
- 重放前会按轮数上限(
maxTurns,默认 12)和字符预算(maxHistoryChars,默认 24000)裁剪,保留最近的轮次。 - 当前话题为空时不会报错:按新话题作答,并在答案前附一行提示「当前没有可续接的临时话题」。
两条命令共同的行为
- 答案只写进当前会话时间线(可回看、可复制、可渲染 Markdown),不进入主模型上下文;主 agent 看不到它们,需要它知道就把要点贴进正常提问。
- 每个问题独立起一个子代理,结束即释放;输出只有模型的回答文本,检索过程与工具调用不显示。
- 单次问答默认 180 秒超时(
timeoutMs),超时、取消或子代理非正常结束都会以错误结果展示,可重试或把问题拆小。 - 回答超过
maxAnswerChars(默认 60000 字)会截断并标注。 - 子代理只带
web_search、web_fetch、read、glob、grep,不能写文件、执行命令或再派生子代理。
安装
dsh plugin --profile web add @agi321/dsh-temp-chat
也可以在 设置 → 插件 页用 Add plugin 填 @agi321/dsh-temp-chat。
想直接跟 GitHub 主分支(npm 版之外的选择):
dsh plugin --profile web add github:agi321/dsh-temp-chat
装好之后输入 /,就能看到 single-turn、multi-turn 两条命令。
要求与注意
- DSH
0.2.1-rc.2或更高(本插件在该版本上实测)。0.2.1-rc.2 起子代理服务把旧的
ctx.subagents.start() 换成了 startActivation(spec),请求里的 persona/toolFilter
字段也被移除,改由 request.agentPreset 指向的 preset 组合决定;本插件已跟进。
package.json 的 engines.dsh 就是这个范围;它是声明性元数据——DSH 当前的安装器与
加载器并不校验它,声明了也不会因此拒绝不兼容的宿主。若在旧宿主上跑本版插件,会报
ctx.subagents.startActivation is not a function。
- Node 24 或更高。DSH
0.2.0-rc.2自带的运行时就是 Node 24.x(本插件在 Node 24.21 下实测通过)。 - 子代理默认只带
web_search、web_fetch、read、glob、grep五个工具。白名单不再靠
tools.restrict() 遮罩,而是直接决定插件注册的内部 preset(dsh-temp-chat)挂载哪些工具行:
glob 与 grep 同属 @deepseek-ai/dsh-tool-fs-search 一行,拆不开——允许其一即两个都开;
映射不到工具行的名字会被忽略并在日志里告警。
- 改动宿主半边(
index.js/lib/)后需要重启 dsh:已加载的宿主模块不会热替换。客户端半边(client.js)的改动刷新页面即可。
为什么这样设计
要求 · 机制
结果只显示、不污染主上下文 · 斜杠命令的 command/run + command/done 是 log-only 事件:UI 会渲染,模型请求永不包含
只带本次问题、上下文隔离 · ctx.subagents.startActivation({ provider: 'spawn', delivery: 'caller', … });spawn provider 的 inheritsParentContext === false,子代理是全新 session;delivery: 'caller' 让结果只交给本命令,不向父会话追加任何通告
联网检索、不跑本地命令 · 人格与可见工具由插件注册的内部 preset 决定(request.agentPreset = 'dsh-temp-chat':persona 行 + 按需挂载的 web/fs/search 工具行 + 压缩组);组合里没有 subagent 行,maxDepth: 1 也只放行这一层直接子代理
多轮续聊 · 从当前会话日志重放"当前话题"的问答到提示词里(/single-turn 是话题边界,也是重置手段)
回答格式自由 · 提示词(lib/thread.js 的 PROMPT_PREAMBLE)不规定结构,由子代理按提问自己决定怎么组织;唯一保留的硬要求是引用网页时用 Markdown 链接标注、并在末尾以「来源」列出链接
为什么多轮不用 continuable 子代理真续聊:continuable 子代理结算时会往父会话追加一条模型可见的 settlement notice("Background subagent … finished / Its closing message: …"),那正好违反"结果不进入主模型上下文"。所以这里每次都是新子代理 + 重放历史文本;好处是主会话彻底零污染,而且历史事实来源就是会话日志,重开对话后仍能接着聊。
渲染方式:聊天目标给每条命令留了一个按命令名分发的渲染位 conversation.chat.commandview(keyed by command name,replaceRisk: none)。客户端半边把 single-turn / multi-turn 两个 key 占下来,把一轮问答画成提问气泡 + 模型回答:提问是右对齐的用户气泡(带你敲的命令标记),回答用自带的极小 Markdown 渲染器(标题、列表、引用、代码块、表格、链接);耗时、复制按钮、工具调用这些附加信息都不显示,结果文本则按原样渲染(插件不解析、不剥离答案内容)。其他命令继续用内置的通用命令卡片。不 import 任何 Harness 客户端包,样式只用主题 token --dsw-alias-*。
为什么还要"标记节点 + 补位面板":DSH 的正文时间线只在"这个会话的 chat 视图活动"时才渲染,而 chat 视图的 isActive 要求快照里至少有一个非 command 节点;斜杠命令不走 session.prompt(),不会把会话从 blank 相位带出来——于是在只发过临时问答的会话里,正文区(连 DSH 自带的折叠卡片一起)整个不渲染,直到用户发了一条普通消息才会把历史一起补画出来。
客户端半边为此注册了一个自己的会话节点定义(uiConversation.events.register):它只为本插件两个命令名的 command/run 生成一个 temp-chat-marker 节点(kind ≠ command,所以 chat 视图变得"活动"),节点本身什么都不画(同时注册了 conversation.chat.node 里 key = temp-chat-marker 的 () => null 渲染器,否则会掉进 DSH 的 "unknown surface" 兜底)。这样新会话里正文区正常渲染,内置命令节点照旧由 commandview 画成"提问 + 回答"。
这条通路依赖 DSH 内部扩展点,所以整体 try/catch;注册失败(或开关被关掉)时退回 conversation.input.dock 上的补位面板:判定 shouldShowDock() = 标记节点未激活 且 session.blank && !session.running && !session.promptAttempted(正好是 DSH 抑制正文区的那个相位),内容同样只有模型的回答;一旦正文能画那一行了,面板自动让位,同一份答案不会出现两次。
语言
界面文案支持中英双语。
- 客户端半边(
client.js)跟随 Harness 界面的语言切换——面板、补位提示、状态文字都按zh/en注册到宿主 locale 服务。 - 宿主半边(
index.js)产出的每一条提示(含命令面板的说明与 hint)都取自locale/{zh,en}.json,由language配置项选择(见下方配置)。默认auto时:命令面板与「没有提问可依」的校验提示按中文注册(宿主在注册命令时读不到浏览器语言),而每一条跟随提问语言的提示——错误、取消、超时、「没有可续接的临时话题」标注、截断——按提问本身的语言给出(含汉字 → 中文,否则英文)。子代理回答的语言本来就跟随提问,由提示词决定,无需配置。
文件
文件 · 作用
index.js · 宿主半边:注册两个命令名与内部 preset,startActivation 起子代理、收答案、释放资源
lib/thread.js · 纯逻辑:命令名→模式、日志→话题轮次、历史裁剪、提示词拼装
client.js · 客户端半边:命令行渲染成提问 + 回答;用标记节点让正文区在新会话里也能渲染,失败则退回补位面板(模块加载器格式,无构建步骤)
cordis.patch.yml · 只插入一行 id: dsh-temp-chat
locale/{zh,en}.json · meta:插件管理页显示的标题与描述;ui:宿主半边的命令面板说明与问答提示
test/*.test.mjs · node --test:纯逻辑 + 宿主命令 + 客户端渲染(无浏览器桩)
配置
宿主半边的可调项都有内置默认值(见下表)。要改就在自己 profile 的 cordis.patch.yml 里覆盖那一行——后应用的层按行胜出,而且 patch 会替换整行的 config,所以要重述每一个想保留的键:
- id: dsh-temp-chat
name: '@agi321/dsh-temp-chat'
config:
provider: spawn # 子代理 provider;不要用 fork(会继承上下文)
persona: 你是一次性联网检索助手。…… # 可选,覆盖内置检索人格
allowTools: [web_search, web_fetch, read, glob, grep] # 映射为 preset 工具行开关;glob/grep 拆不开,未知工具名忽略并告警
maxTurns: 12 # 多轮续聊最多重放多少轮
maxHistoryChars: 24000 # 重放历史的总字符预算
timeoutMs: 180000 # 单次问答超时
maxAnswerChars: 60000 # 答案文本上限,超出截断
language: auto # UI 文案语言:'auto' | 'zh' | 'en'(见上文「语言」)
客户端开关:正文标记节点
…(truncated)
以上内容来自 npm 上的 README,我们只做格式化,不改内容。
版本
npm 上共发布:4,最后更新 2026-10-24