Перейти к основному содержимому
Z

dsh-conversation-retry

zhao0335/dsh-conversation-retry

Edits a message you already sent and re-runs from that point by forking the session, and retries a completed turn, in the DeepSeek Harness Web UI.

Установка

dsh plugin --profile web add github:zhao0335/dsh-conversation-retry

README

dsh-conversation-retry

Edit a message you already sent and re-run from there — plus retry a turn — in the DeepSeek Harness Web UI.

The stock Harness only lets you append another message when something goes wrong. A prompt you already sent is frozen: the bad answer stays in the history and keeps costing context. This plugin makes the conversation editable.

ActionWhereWhat it does
Editon your own messageRewrite a prompt you already sent and re-run from that point.
Retryin the assistant action stripRe-send the turn's prompt unchanged and let the model answer again.

Both actions produce a real, separate session: nothing is rewritten in place and nothing is lost. The original conversation is untouched, and the new branch appears in the sidebar like any other session.

Branching a turn is not part of this plugin — the Chat footer already ships a branch button, so there is nothing to add.

Why forks instead of in-place rewriting

A Harness session is an append-only event log — that is what makes replay, inspection, and export trustworthy. Deleting the tail of a log would break that guarantee, so "edit and re-run" is expressed as a fork of an exact event-sequence prefix: the child is a complete, self-contained session whose history ends just before the message you edited. This is the same primitive the sidebar's Fork session action uses, cut at message granularity instead of at the session's end.

That also means an edit is non-destructive: the branch you abandoned is still there if you want it back.

Install

dsh plugin --profile web add github:Zhao0335/dsh-conversation-retry

Then reload the Web UI once so the browser picks up the new client module.

To install from a local checkout instead, point the Harness at the directory:

plugin_manager install_bundle  target: <absolute path to this directory>

Requirements: a Harness build that exposes ctx.sessions.fork with an atSeq boundary, the conversation.chat.user.before chain slot, and the conversation.chat.assistant-actions slot (0.2.x and later).

Usage

Edit a message. Hover one of your own messages; a pencil button appears beside it. Click it and the message opens in a dialog, pre-filled. Change it and press Fork and send (Ctrl/Cmd+Enter). A new session opens with the edited prompt already running; everything before that message is carried over, and the old answer and everything after it are gone from the new history.

Retry a turn. The retry button sits in the assistant message's own action strip, next to copy and branch, and uses the same 28px geometry, tertiary colour, and hover treatment as the shipped buttons. It re-asks the turn's prompt on a history without that turn.

The child session inherits the title with an incremented suffix, so branches of the same conversation stay recognisable in the sidebar.

How it works

  • conversation.chat.user.before — a chain slot rendered inside the user row. Its selector elects the entry only for rows whose durable message source carries a browser prompt identity (source.rpcId), so only messages you actually typed get the pencil; synthetic context injections do not. Placement needs one subtlety: the user row stacks its children in a column (message-source seat, bubble, action row), and every slot render sits in a display: contents wrapper. The row is therefore reached through that wrapper's stable data-slot attribute, the control leaves the column flow, and the shipped action row reserves its width — which is what puts the pencil on the copy icon's line instead of on a row of its own.
  • conversation.chat.assistant-actions — the shipped action strip. The entry's component renders inside it, so the retry button inherits the row's layout and hover behaviour. It maps its messageId back to the owning turn through useChat and that turn's turn-tail data.
  • The edit affordance resolves its message through a per-session index of rpcId → sequence and text, rebuilt only when the published event-window revision moves. Scanning the log once per rendered row would make a long conversation quadratic in its own history.
  • shell.overlay — the frame-wide layer that hosts the single edit dialog. The open edit target lives in a small module-level store shared by both entries.
  • ctx.sessions.fork({ sessionId, atSeq }) — cuts an exact inclusive prefix. Edit forks at userMessage.seq - 1; retry forks at turnStart.seq - 1.
  • ctx.sessions.using(childId, …) → SessionBinding.session.prompt([…], 'queue') — sends the prompt into the child once its initial open settles.
  • ctx.uiWorkspace.openSession(childId) — retains the child as the main view (so it outlives the plugin's own reference) and navigates to it.

The Host half is an empty apply(); the whole feature is browser-side.

Limitations

  • Retry re-sends the turn's first user message. A turn opened by a synthetic context injection (goal continuation, file-change notice) will re-send that injected text rather than a human prompt.
  • Edit is offered only for messages whose source carries an rpcId — prompts submitted from this browser. Messages restored from an older log format without that identity are not editable.
  • Messages whose events have scrolled out of the loaded history are skipped; the buttons are hidden for them.
  • Attachments are not carried over — the prompt is re-sent as text.

License

MIT — see LICENSE.

Похожие плагины