DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

Session Retry — DSH Plugin for DeepSeek Harness
DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in
← Plugins
S

@local/dsh-session-retry

Session Retry

Session retry — A button labeled “Answer again” in the assistant message action bar: removes the previous answer for the current turn from the model context, then resubmits the user’s question for that turn to the same conversation.

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add github:linanbuan/dsh-session-retry#d7f4c29fd781aba395db56b7754b029840eef05f
READMECompatibilityVersions

Description

A DSH plugin that adds an “Answer again” action to every assistant turn’s action bar, removing the previous answer from the model context first.

Compatibility and provenance

Session Retry is published as @local/dsh-session-retry and currently resolves to version 1.0.0. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
web
Release source
github
Registry updated
10/11/2026

Versions

1.0.0stable
10/11/2026

Related plugins

Loading related plugins…

Latest
1.0.0
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
Unavailable
Files
Unavailable
Surface
web
License
MIT
Source
github
GitHub
★ 0
Weekly downloads
0
Last push
10/11/2026
View source ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue

Related plugins

More verified plugins in memory-context.

Hindsight Coding Agents@vectorize-io/hindsight-coding-agentsReflect-only Hindsight long-term memory for coding agents (harness-pluggable: opencode, …), with automatic background ingestion (no setup CLI).Ab Memorydsh-ab-memory--- description: "The dsh-ab-memory package: a cross-session, file-backed agent memory with five tools (remember / recall / forget / load_skill / distill) and an always-on light injection." kind: "package-reference" ---Contextdsh-contextA DeepSeek Harness plugin for context insight and management, with context dashboard and context command, for understanding how the context is made of, and how it evolves.Memsearch Dsh@zilliz/memsearch-dshMemSearch plugin for DeepSeek Harness: shared markdown memory across agents, with capture, pre-step context injection, memory-recall skill, and a skill-candidate review panel.

README

重新回答 · dsh-session-retry

中文 | English

在助手消息的动作条上加一个 重新回答 按钮:把该轮回答对应的用户提问重新提交给 同一个会话,并先让这一轮的旧回答退出模型上下文 —— 重答时模型看不到自己上一次 在这一轮里答了什么(日志与界面上的历史消息不动)。

按钮落在复制与分支之间(conversation.chat.assistant-actions,order: 20),样子与原生动作条按钮一致:方形图标按钮、悬停出深色提示气泡、与那条动作条一起悬停/聚焦显隐(data-clock=end 那一轮尺寸跟着原生图标走)。图标与提示气泡都是插件自带的:插件实践要求第三方插件的浏览器半边不 require Harness 客户端包,所以这里只 require('react')。

  • 行 id:session-retry
  • 位置:助手消息动作条(conversation.chat.assistant-actions)
  • 依赖:无(宿主半边注入 connection 与 agents,浏览器半边只依赖 react)

它做什么

  • 宿主半边(index.js)在共享的 /api 通道上注册两条路由:

    POST /api/session-retry/context      { sessionId }                 (只读)
      → { ok, sessionId, latestTurn, cached, anchors: [
            { messageId, turn, text, promptCount, omittedParts, promptSeq, anchorSeq } ] }
    
    POST /api/session-retry/regenerate   { sessionId, messageId }      (登记改写)
      → { ok, turn, promptSeq, runs, shadowed, kept, eventSeqs, deferred: true }
    

    前者一遍扫过整条会话日志,把「动作条挂在哪条助手消息上」与「该轮的用户提问」配对,结果按会话缓存 1.5 秒。后者只认活会话:从 sessions.get(id) 拿会话、用 snapshotEvents() 现场重算锚点(与 /context 同一套 retryTargets 规则),再把该轮的可见面节点替换成空节点 —— 但不在点按钮的当场写,而是登记一份影子计划,等下一次请求真的打开一个步骤时补写(原因见下一节)。

  • 浏览器半边(client.js)按会话注册一个动作条条目:取一次上面的表,每条动作条拿自己的 messageId 查表 —— 命中就可点,没命中就置灰并说明原因。点击后先 POST /regenerate,成功才用 session.prompt([{ type: 'text', text }], 'queue') 提交提问(与 ui-conversation 的 conversation.send 走同一条路径)—— 两步都成了才提示「已重新回答(旧回答已退出上下文…)」;改写没成就只转述原因、不提交,否则等于在旧回答还在上下文时把提问问第二遍。

旧回答是怎么消失的

改写的是可见面(surface),不是日志:会话记录、界面上的历史消息、标题与统计都原样保留,只有送给模型的消息列表少掉这一段 —— 模型能看到什么由 dsh-session 的 surface 折叠与 deriveMessages() 决定。

用法是 surface 自己的替换通道:追加一条 system/message 事件,带 surfaceOp: { op: 'replace', startSeq, endSeq } 与 sourceEventSeqs(被遮蔽节点必须列全,应用会严格校验)。载体必须是空 system 节点:应用自己的规则是「空 system/developer 节点保留可见面位置但不产生线缆消息」(dsh-session 的 deriveEventMessage),而空 user/message 会作为一条空 user 消息真的发出去。

写这条事件的时机有硬约束:system/message 属于 V4 的「步骤事件」,校验要求它的 turn/step 必须等于当前打开的那一对(dsh-session-format-v3-to-v4 的 STEP_EVENT_TYPES + requireStep)。点按钮时会话是空闲的 —— 上一轮已经 turn/end、下一轮还没 turn/start,没有任何打开的步骤 —— 此刻带着上一轮的 turn/step 写进去,日志当场就坏:

SessionFormatError: system/message does not match an open turn and step
→ stored log is corrupt ...

所以 /regenerate 只登记影子计划(deferred: true,可见面当场不动),等客户端提交的提问真的打开一个步骤时,在 agent/request 钩子里用当时打开的 turn/step 补写。这个位置既合法(步骤确实开着),又足够早 —— dsh-agent-loop 的 step() 先 step/start,然后 prepareRequest→agent/request(hook),最后才 buildRequest→deriveMessages(),所以用户这一次请求就已经看不见旧回答了。会话在补写前被关掉也没事:计划带 TTL,过期即弃,日志里什么都没写过。

影子范围怎么算:每个可见面节点取一个「内容区间终点」—— 追加型节点是自己本身就是新内容,终点是它自己的 seq;替换型节点继承被替换段的位置(压缩摘要就是这样占住早期位置的),终点是被替换段的末端。终点早于本轮提问的节点属于「提问之前的记忆」(例如提问前产生的压缩摘要),保留;终点不早于提问的节点都是这一轮的产物,影掉。要影的节点在可见面里未必连续,所以按可见面下标切成连续段,一段一次 append(每段留一个空节点占位)。这段判定是纯函数 shadowPlan(),真实日志与合成事件都能直接喂进去测。

判定规则(与界面严格对齐)

动作条由 ui-chat 的轮次尾部渲染:每轮一条,挂在该轮最后一个产出文本的步骤里最后一条 assistant/message 上(closing = finalized.findLast(hasText))。本插件的锚点就是这条消息,所以:

  • 该轮没有产出文本的步骤(例如中途被打断)→ 界面本来就不渲染动作条,自然也没有按钮;
  • 该轮的提问 = turn/start 之后、锚点之前的人工消息(source.kind === 'user')。注入的上下文(time-context、skill-catalog、插件通知)与压缩检查点都不是提问;替换操作(surfaceOp 为对象,压缩复写旧消息)也不是追加,不参与判定。

一轮里不止一句提问:用户在模型回答途中发话(steering / 排队)时,那句话会被接进同一个轮次。此时按顺序把该轮全部提问合并成一段重发 —— 只挑其中一句会丢掉另一句,合并则既不丢内容也只提交一次。提示语会如实写明「合并 N 条提问」。

刻意做出的取舍

  • 影掉而不是删除:宿主没有截断历史或回滚轮次的公开接口,已经写进日志的事件也删不掉,所以这是「让模型看不见」。想要真正另起一段历史,用动作条上的分支按钮(另开会话)。
  • 重答更早的轮次 = 回退到那一轮重来:影子范围从该轮提问起一直覆盖到可见面末尾,所以那一轮之后的轮次也会退出上下文(否则模型会带着「后面已经发生的事」去答前面那轮)。
  • 只服务活会话:/regenerate 要拿到内存里的会话对象才能改写;会话不在应用里打开时返回 NOT_LIVE。会话正在回答时返回 RUNNING —— 边答边改可见面属于压缩那种受控场景,这里不做(提示语会直接说「先停止再重新回答」)。
  • 非文字内容不重发:只重发文字块;原消息里的图片、附件只计数,并在提示语里说明「N 个非文字内容没有重发」。
  • 一次请求答完整条会话:动作条是每轮一条,一场长会话有几十条同时挂在页面上;逐条询问就是几十趟日志回放。所以客户端按会话取一次表,同一提交里挂载的动作条共用一趟请求(后挂载的动作条会补一趟,保证看到的是它挂载之后的判定)。

工程约束

  • 浏览器半边只依赖 react:dsh.client.inject 只声明 @deepseek-ai/dsh-client-ui-chat(插槽的属主),immediately: true 让前端在启动时就预取这个包。图标(RefreshIcon,几何照抄原生刷新图标)与提示气泡(纯 CSS 显隐,不 portal、不写 document.body)都在 client.js 里自带。
  • 宿主半边注入 connection 与 agents:agents 是 agent/request 钩子(补写那一步)必需的;sessionQuery 与 sessions 都不注入,缺失时按不可用降级回答 —— 没挂 sessionQuery 的组合里 /context 答 UNAVAILABLE,没挂 sessions 的组合里 /regenerate 也答 UNAVAILABLE,都不会把插件拖垮。
  • 空节点写在打开的步骤里:补写只发生在 agent/request(步骤已打开、消息还没装配),所以空节点的 turn/step 一定等于当时打开的那一对,日志不会被写坏;没有打开的步骤时(例如钩子被别的组合提前调用)就什么也不写,计划留到下一步。

安装

本插件是一个标准 DSH bundle:package.json 里声明了 dsh.bundle.patch 与 dsh.client,装进任何 profile 都走同一条路。先装好 DSH 桌面端(deepseek.com/download),然后下面任选一种。

方式一 · 在 DSH 桌面端里装(推荐)

  1. 侧栏点 插件 → 添加插件(Add plugin);
  2. 在输入框里填下面任意一种 spec:
    • 本仓库地址:https://github.com/linanbuan/dsh-session-retry
    • 本仓库的压缩包链接(GitHub 页面的 Source code (zip))
    • 已经克隆到本机的目录绝对路径
    • 包名(若将来发布到 npm)
  3. 点 安装:Harness 先读出这个 spec 指向什么(包名、简介、版本),确认后开始装;
  4. 装完点 立即启用。

整个安装由 Harness 自己的插件管理器完成:把这个包写进当前 profile 的 dsh.profile.bundles,并挂上宿主半边。桌面端装插件不需要命令行,也不需要手改 profile 文件。

方式二 · 让 Agent 自己装

把仓库地址或本机目录直接交给任意会话里的 Agent,它会调用 plugin_manager 工具(action: install_bundle)走同一条路。这是官方给第三方插件推荐的安装方式。

方式三 · 命令行

装了 dsh CLI 的机器上:

dsh plugin --profile <profile 名> add <spec>

<spec> 与方式一相同(包名、Git 地址、压缩包链接或本地路径);参数以 dsh plugin --help 的实际输出为准。

方式四 · 手工装进某个 profile(排障用,不推荐)

profile 目录默认在 ~/.dsh/profiles/<profile 名>。把包放进去,并在 profile 自己的 package.json 里登记两处:

"dependencies": { "@local/dsh-session-retry": "link:<本目录绝对路径>" },
"dsh": { "profile": { "bundles": [ "…", "@local/dsh-session-retry" ] } }

手改 profile 文件要过权限审批,写坏会让 Harness 起不来,所以正常安装请走前面三种。

一个坑:在 WSL 里 ln -s 出来的链接是 Linux 符号链接,Windows 侧跑的 Electron 解析不了它,插件页会报 dsh: cannot resolve profile bundle "@local/dsh-session-retry"。要真链接就让 Windows 侧的 pnpm 去建(方式一/二),否则就用目录副本。

装上之后

激活与改完代码之后怎么让它生效是两件事:

  1. 侧栏 插件 → 找到 @local/dsh-session-retry;
  2. 点那一行的开关 停用再启用(一次热挂载);
  3. 组件状态从「已关闭」变「运行中」=宿主半边挂在启动图里了;
  4. 浏览器半边会跟着 /plugins/events 的 graph 帧重新拉取 client.js,不用刷新页面。

但宿主半边改了代码必须重启应用。 cordis 的插件加载器用裸 import() 加载宿主模块,Node 的 ESM 缓存按文件 URL 命中,停用再启用只会重跑缓存里那份旧模块的 apply() —— 新注册的路由不会出现。表现是:按钮是新版本,点下去却提示「宿主那半还是旧版本(404),重启应用后再试」(客户端把这条 404 专门翻译成能照着做的一句话)。所以:

  • 只改 client.js:热挂载即可,页面不用刷新;
  • 改了 index.js 或 package.json:重启应用。

停用 / 卸载

- id: session-retry
  disabled: true

或者直接点插件页那一行的开关;彻底移除用插件页 → 这个包 → 卸载。

注意事项

  1. 本插件不是官方插件:与 DeepSeek AI 无任何关联,不提供服务承诺。它依赖 DSH 内部的 surface 折叠与步骤事件契约,这些不是稳定 API:Harness 升级后按钮可能置灰或改写失败,此时插件只转述原因、不提交任何东西,不会破坏会话日志。
  2. 它会改写当前会话的可见面:这是插件的全部目的,但它确实往会话里追加了事件(system/message + surfaceOp)。原始日志与界面历史不动,可随时用「分支」另开会话保留原样。请勿在需要严格留证的一次性会话里使用。
  3. 0.3.0 之前写过坏日志:早期版本在会话空闲时当场追写步骤事件,会被 V4 校验器拒绝(system/message does not match an open turn and step),受影响的会话日志需要单独修复;1.0.0 起改为「登记影子计划 + 在打开的步骤里补写」,不再有这个问题。若你手上是旧版本,请升级。
  4. 运行中的会话不能重答:返回 RUNNING,提示语会说「先停止再重新回答」。
  5. 非文字内容不重发:图片与附件只计数、不重新提交,提示语会写明数量。
  6. 安装后不会自动更新:官方插件管理器目前不支持自动更新,升级=先卸载再装新版;替换已安装的包之后宿主半边要重启应用。
  7. 兼容性:在 DSH 0.1.7-rc.2(Windows 桌面端)上开发与验证。宿主半边注入 connection 与 agents(后者供 agent/request 钩子用),sessionQuery / sessions 缺失时降级为 UNAVAILABLE 而不是崩溃。
  8. 隐私:插件不联网、无遥测。它在宿主侧读会话日志与内存中的会话对象,浏览器半边只拿到这一轮要用的锚点表(消息 id、轮次、提问文本)。
  9. 权限:插件自身不申请任何额外权限;安装时由 Harness 的插件管理器走它自己的审批流程。
  10. 本仓库的隐私:仓库内不含任何密钥、凭据、账号标识、会话日志或本机路径(文档里的路径一律是 ~/.dsh/... 形式或 <占位符>)。

测试

node test/retry-targets.mjs      # 判定与影子范围的单元测试(合成事件,零依赖)
node test/client-contract.mjs    # 浏览器半边在替身环境里的契约测试(零依赖)

retry-targets 覆盖锚点判定与影子范围:一轮一会话、多轮取最大轮次、一轮多句提问合并计数、提问只有非文字内容时不给锚点、该轮没有产出文本的步骤时不给锚点、注入上下文与插件通知不算提问、锚点之后的提问不算本轮、空日志/畸形事件/缺 turn/end 安全降级、影子范围的边界与不连续切段。

client-contract 按宿主客户端的加载契约搭一个最小替身(window.__ModuleLoader__ + react + slots/locale/sessions 服务),驱动真模块走完「注册 → 挂载 → 取上下文 → 点击提交 → 提示语」的全过程。替身故意不提供任何 Harness 客户端包 —— 一旦 client.js 又去 require 一个,就在那里当场失败。它验证的是模块自己的逻辑与注册形状;「按钮在真实界面里的位置与样式」不在它能证明的范围内。

真机实证(用应用自己的 Session 实现与真实会话日志跑端到端,含「补写出来的日志能被 V4 校验器读回来」这条)不在本仓库内,属于本机验证材料。

结构

package.json              bundle 清单(dsh.bundle.patch + dsh.client)
cordis.patch.yml          一行 insert:装载宿主半边
index.js                  宿主半边:两条路由 + retryTargets/shadowPlan
client.js                 浏览器半边:动作条按钮(手写 lazy CJS,只用 react)
test/retry-targets.mjs    判定与影子范围单元测试
test/client-contract.mjs  浏览器半边契约测试
icon.svg                  插件图标

致谢与第三方许可

  • 提示气泡与刷新图标照抄 DSH 官方 @deepseek-ai/dsh-client-ui-primitives 的外观(13px 文字、深色底、圆角、下方 6px 的摆放,以及 IconRefreshOutlineRegular 的几何),只取外观与几何,不加载该包、不复制其代码:官方包的许可为 MIT,本条按 MIT 的要求标注来源。
  • 与界面判定对齐的规则(动作条挂在「该轮最后一个产出文本步骤的最后一条助手消息」上)来自 DSH 官方 ui-chat 的实现口径,属于接口兼容性的对齐,不含官方代码副本。
  • surface 替换通道(surfaceOp 的 replace 语义、空 system 节点不产生线缆消息)是 DSH 官方 dsh-session 自带契约,本插件只按契约写入,不包含其代码。
  • 本仓库没有引用或改编任何第三方插件的代码。

License

MIT © 2026 linanbuan