Skip to content

Releases: DDDMUC/dsh-rerun-turn

v0.2.5 - fix: 选项两个字、说明一句话、下拉跟内容

Choose a tag to compare

@DDDMUC DDDMUC released this 25 Oct 13:02

0.2.5 —— 设置卡导出给组合包;两个补法只留两个字,说明收成一句,下拉不再撑满一行。

  • 选项就是词:「顺补」「自补」这两个词本身已经说清了是二选一,标签里却还跟着一整句解释。现在选项只有两个字,解释放在它正下方那行提示里。
  • 提示一句话:原来的提示是一百多字的整段,带三对【】和一对();现在各一句 —— 顺补是「重跑它下面第一个有 O 的可见轮;下面没有,就重发最新那条缺 O 的」,自补是「重跑这一可见轮自己的 O,后面的轮次不动」。
  • 下拉跟内容走:控件原来有 190px 的最小宽度,两个字的选项被撑成一条横贯卡片的框;现在宽度跟着内容。
  • 设置卡导出:exports.ConfigCard 对外导出,聚合包 dsh-as-aistudio 在自己页面上渲染的是这一张卡,不是另画一份;单独装本插件时那张卡仍在本插件自己的行上。

v0.2.4 - feat: 缺失 O 的可见轮可点重跑(顺补 / 自补)

Choose a tag to compare

@DDDMUC DDDMUC released this 24 Oct 06:28

0.2.4 —— 缺失 O 的可见轮也能点重跑:顺补 / 自补两种补法可选。

  • 约定简写(本节与后续记录都用它):Q = 用户输入;O = 模型输出的所有内容块(O = C + A + T),其中 C = 思维链,A = 正文,T = 工具调用。一轮 = Q O,所以 QOQOQO 是三轮各有一问一答。注意 tool/result(工具的结果)不是模型输出,不算 O —— 它是工具/宿主产生的,只是恰好和 T 挨着。实测一份两万条的日志:assistant 消息 2931 条、内容块只有 tool-call ×2855 / reasoning ×2205 / text ×195,没有第四类。
  • 两种轮:日志轮 = 日志里记录的轮次(日志不可删,所以它是全集);可见轮 = 对话视窗里、经插件操作之后应该看到的那些轮次(被删掉 / 被隐藏 / 早先重跑退役掉的那部分不在其中,所以可见轮 ⊆ 日志轮)。下面两条规则都按可见轮算。
  • 没回答的轮次也有按钮了:以前是「这一轮没有回复 → 撤掉按钮」,于是「刚发出去还没回答」「被停止」「失败」「回答被删掉」这几种情况下按钮根本不在,用户看到的就是一片空。现在每一条没有回复的用户消息都带按钮。
  • 新增设置「缺失 O 的可见轮」(插件页配置卡片里,和「重跑时询问」同一张卡):两种补法各有两字名字 —— 顺补(顺着往下补:去重跑下面第一个有 O 的可见轮)与 自补(补它自己那一轮):
    • 顺补(默认):点哪个缺失 O 的可见轮,都去重跑【从这个轮往下、第一个有 O 的可见轮】的回答。它下面一个可见的 O 都没有时(它就在最末),改成重发最新那条缺失 O 的可见轮。
    • 自补:点哪个缺失 O 的可见轮,就重新生成【这个轮自己】的回答 —— 这是唯一能把上下文里的洞真正补上的做法。
  • 代价说清楚(两条路一样的地方):真正会再调一次模型的只有被作用的那一轮本身。它后面的轮次是被重放,不是重新生成 —— 把日志里已经记下的 C/T/A 原样抄回上下文(buildReplayWrites 逐条 appendWrite,全程没有模型调用;只有思维链的签名会去掉,因为签名签的是旧文本)。副作用是日志追加一份尾巴、被抄的轮次拿到新 seq(界面上看起来一样)。只有被作用的那一轮本来就是最末一轮时,才是「一次请求、后面一概不动」。
  • 宿主没改:planRerun 本来就接受「提示词目标」,只对「自己没有任何可重跑回复的那一轮」放行(停止 / 失败 / 刚发出还没回答都算),并拒绝把「有 A 的轮次的 Q」当目标 —— 所以「点这个 Q 去重跑下面那一轮」这种映射由客户端决定发哪个 seq,宿主不接受这种地址。被隐藏的 A 不算可见:默认模式会跳过它继续往下找,找不到就退回重发最新那条没回答的提示词。
  • 测试:npm test 86/86(宿主侧提示词目标只 shadow 提示词自己、回放窗口为空,且只广播「带 O」的回答 —— 空内容 / 零宽文本不算 O,纯工具调用算 O;客户端侧两种模式各自的作用对象与按钮文案、隐藏的 A 被跳过、回答被删的轮次仍带按钮且不落到别人的 A 上、卡片里能切模式并落盘)。

v0.2.3 - 中断提示能关了 + 命名会话不再被拒

Choose a tag to compare

@DDDMUC DDDMUC released this 23 Oct 14:48

0.2.3 —— 修掉「重跑已中断」提示关不掉;命名会话不再被拒。

  • 根因(宿主):setProgress() 把每次阶段更新合并进上一条记录,从不清理旧字段。一次 interrupted 写下的 error 会跟着 replaying、done 一路活下来,/state 于是一直报告"已中断",前端也就一直画那条提示。
  • 修法(宿主):新增纯函数 progressAfter(current, patch);阶段变化 = 新记录,不再继承上一阶段的 error / promptError;同一阶段内的增量 patch 仍然合并。setProgress() 改走它。
  • 修法(客户端):提示只认 phase === 'interrupted' | 'failed' 的 error(旧宿主合并出来的 done + error 不再显示);提示条右侧加关闭按钮,点整条也能关;关闭状态按「阶段 + rerunId + 文案」记忆,新错误仍会重新出现。
  • 命名会话不再被拒(本版一并带上):会话 id 校验原来只认 UUID,而 bili-whale 这类命名会话(~/.dsh/storages/<profile>/sessions/bili-whale.json)是完全合法的会话 —— 于是对它的每个请求都被 400 拒掉,面板上就是「状态加载失败,稍后重试。」。现在按 DSH 自己的语法(宿主侧 schema 就是 z.string().min(1))放宽为 /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/,仍然挡住 /、\、..、空白与控制字符。
  • 查不到会话按空状态处理:没有日志的会话(刚建的命名会话)返回空状态而不是 404 —— 面板正常加载、显示"没有可操作的内容",日志一出现下一次刷新就接上。
  • 测试:npm test 81/81(新增 3 条 progressAfter 用例、5 条 DOM 用例:stale error 不显示、关闭按钮、点整条关闭、dismissed key、promptError 仍显示;以及命名会话 / 空状态的契约用例)。

v0.2.2 - 设置页「重跑时询问」+ 确认框对齐 delete

Choose a tag to compare

@DDDMUC DDDMUC released this 22 Oct 16:14

变更

  • 设置页新增「重跑时询问」:插件管理页里 dsh-rerun-turn 这一行的配置入口(plugins.row.config,key 为 <bundle>#<row id>)新增一个勾选,默认关。勾上后每次点重跑先弹确认框,说明这一轮会怎么重放;取消勾选则点一下直接重跑。选择存在浏览器本地(dsh-rerun-turn:prefs),没有存过时跟随 profile 里的 confirm。
  • 确认框与 dsh-delete-turn 完全对齐:使用官方 Modal + Button,位置/宽度(380)/圆角(28)/背景/阴影/按钮行与删除确认一致;正文 14/22,第二段说明 13/20。
  • 重跑一开始就退掉旧回答(0.2.1):in-flight rerun 一旦确认,目标回答行立即隐藏,新的流式行占用它原来的位置;代价是最多一帧空位。
  • 静默载体按会话判适配器:按会话日志的 model/selection 取 provider,再查该适配器是否原生丢弃空 user/assistant 消息,是就写空载体,判不出来仍旧用零宽兜底。

验收

  • npm test 72/72、npm run verify:contract 29 项、npm run verify:client 7 项。
  • 真页面复验:勾选后提示切换为「每次重跑前都会先弹出确认…」,存储写入 {"ask":true};确认框实测宽 380 / 圆角 28px / 居中,与 delete 的删除确认同款。

Changes

  • Added "Ask before rerun" to the settings page: The configuration entry for the dsh-rerun-turn row on the plugin management page (plugins.row.config, key <bundle>#<row id>) now has a new checkbox, off by default. When checked, clicking rerun opens a confirmation dialog first, explaining how this turn will be replayed; when unchecked, a single click reruns directly. The choice is stored locally in the browser (dsh-rerun-turn:prefs); if it has never been stored, it follows confirm in the profile.
  • The confirmation dialog is fully aligned with dsh-delete-turn: It uses the official Modal + Button; position/width (380)/border radius (28)/background/shadow/button row are consistent with the delete confirmation; body text 14/22, second explanatory paragraph 13/20.
  • Retire the old answer as soon as rerun starts (0.2.1): Once an in-flight rerun is confirmed, the target answer row is hidden immediately, and the new streaming row takes its original position; the cost is at most one frame of empty space.
  • Silent carrier determines adapter per session: The provider is taken from model/selection in the session log, and then the adapter is checked to see whether it natively drops empty user/assistant messages. If so, an empty carrier is written; if it cannot be determined, the zero-width fallback is still used.

Acceptance

  • npm test 72/72, npm run verify:contract 29 items, npm run verify:client 7 items.
  • Real-page re-verification: after checking, the hint switches to "A confirmation will pop up before each rerun…", and storage writes {"ask":true}; the confirmation dialog measured width 380 / border radius 28px / centered, the same style as delete's deletion confirmation.

dsh-rerun-turn v0.2.0

Choose a tag to compare

@DDDMUC DDDMUC released this 21 Oct 16:19

dsh-rerun-turn 0.2.0

  • 多目标补丁兼容:dsh-edit-turn 0.5 的「全部」保存会把整轮多个块写成一条 plugin:dsh-edit-turn/patch 记录(targets 可跨多条消息)。重放新增测试覆盖:被保留的后续轮里,每条消息按自己的 target 取到新文本,原记录不改写。
  • 按钮尺寸修正:.dsrr-action 补 box-sizing:border-box(此前 28px + padding 6 实际渲染 40×40),hover 去掉 inset 描边;与官方 action 图标一致:28×28、15px SVG、stroke 1.2、#81858c。

测试:npm test 64/64、contract 29、client 7。

dsh-rerun-turn 0.1.28

Choose a tag to compare

@DDDMUC DDDMUC released this 20 Oct 10:25

Added

  • Replay now carries dsh-edit-turn reply patches: editing a later answer and then rerunning an earlier turn preserves that edit in the replayed copies.
  • Text and reasoning patches are applied to the copy; reasoning drops its stale signature. Malformed, future-version and retired-target records are skipped.
  • Same-turn rerun still wins: the rerun target is regenerated, not copied.

Verification: npm test 63/63, contract 29, client static 7.

v0.1.27 - the carrier's shape follows the installed adapter

Choose a tag to compare

@DDDMUC DDDMUC released this 09 Oct 14:11

The silent carrier's content shape now follows the adapter that is actually installed.

0.1.26 made the shadow carrier an empty user/message (content: []), on the assumption that both
official adapters drop empty user messages before they are sent. That is true only for a pi-ai build
carrying the local patch dsh-delete-turn:skip-empty-user. The DSH desktop runtime has no such line,
so content: [] was turned into { role: 'user', content: '' }, the provider rejected the whole
request with HTTP 400 user message must have content, and an entire turn was aborted on a real
session (2026-10-07).

The shape is now decided at load time: an empty array only when the installed adapter is proven to
drop empty user content, otherwise a single zero-width space - which the provider accepts. The proof
is a read of the adapter source for the patch marker; anything else counts as "no proof" and falls
back to the zero-width space, so the failure direction is always the safe one.

isSilentPluginCarrier was widened from "empty" to "no readable text", so a zero-width carrier
standing where the prompt used to be is still refused as a re-sendable prompt.

Nothing else moved: the shadow is still exactly one turn-less event, the ledger and replay still skip
it, and old logs fold byte-for-byte the same.

60 unit / 29 contract / 7 client checks green. The other branch is green as well (the probe forced to
false). Verified negatively: restoring the previous carrier behaviour turns exactly the two new cases
red.

v0.1.26 - the carrier no longer buys a turn

Choose a tag to compare

@DDDMUC DDDMUC released this 06 Oct 06:03

Rerunning used to leave an empty turn behind. The carrier had to be a system/message, and that is a step event - it can only travel inside a turn of its own.

v0.1.25 - a turn with no finalized reply is rerunnable through its prompt

Choose a tag to compare

@DDDMUC DDDMUC released this 03 Oct 18:59

A turn that produced no finalized reply used to offer no rerun button at all - on the
answer strip, on its prompt row, and in the dsh-edit-turn editor, which reads the same
/state and answered with 「已保存,但这一轮没有可重跑的作答。」

Reproduced from a real session. At the moment the prompt was sent and its reply had not
landed yet:

seq 47  02:47:55  turn/start
seq 49  02:47:55  step/start
seq 50  02:47:55  user/message  "回复1"      <- the row, no button
seq 51  02:47:57  assistant/message "..."     <- two seconds later

Against that truncated log, rerunnableReplies returned nothing for turn 5, so the prompt
row found no entry and injected nothing. Not because the session was busy - being busy
never hides a button - but because the turn had no entry to find.

What changed (host half only)

  • resolveTarget accepts a user/message target, where it only accepted a reply before;
  • planRerun accepts a prompt target only for a turn with no rerunnable reply of its own,
    and only when that prompt IS the live prompt of that turn. The predicate is the new
    rerunnableReplyOf - the same one the advertisement uses, so the two cannot drift;
  • rerunnableReplies appends { seq: , turn, messageId: null } for a turn that has
    no advertised reply but does have a live user prompt.

No new replay semantics: planRerun already used the target seq only to identify the turn,
and the window has always opened at the prompt, so a prompt-addressed plan is
field-for-field what a reply-addressed one produces. A null messageId keeps the answer
strip from claiming it. The client half is unchanged.

The old rule does not widen: a prompt is still not an address when its turn does have a
rerunnable reply.

Verification

  • 53 unit / 22 contract / 7 client checks green;
  • negative check: reverting the two changes turns exactly the two positive new tests red;
  • check-rerun-plans.mjs on the live session: 95 advertised, 0 unplannable;
  • on real data, session-2dffdf89 turns 48 and 50 (stopped, prompt still live) went from no
    entry at all to an entry that plans.

Not covered, on purpose: a turn whose prompt was deleted still offers nothing, because
re-sending it would undo that deletion.