dsh-history-edit
Conversation history edits for DeepSeek Harness (DSH): change what you said, go back to an earlier point, or fix an AI reply, without losing anything.
Maintenance: best-effort. Issues may go unanswered; forks are welcome.
What it adds to the chat
- Recall (under each of your messages). Goes back to just before that message and puts its text back in the message box, to resend as is, changed, or with files. Nothing is deleted: when you send the next message, the recalled message and everything after it are set aside.
- Edit again (on a message that was edited through the
rewritemethod of the channel below). Opens an edit window; the edited message replaces the old one and the AI answers again. If later messages of yours exist, a copy of the conversation is created instead, so nothing is lost, and the page opens it. - Go back here (under an AI reply that has later turns). The next message you send restarts from that reply and the later turns are set aside. A banner says so and has a Cancel button.
- Edit reply (under an AI reply). Creates a copy of the conversation up to that turn with the reply text changed; the original stays as it was, and the page opens the copy.
"Set aside" means hidden from the AI and from the chat page. The events stay in the session log.
The interface is in English, and in French when the page language is French. To add a language,
add a table to STRINGS at the top of client.js (missing keys fall back to English).
Install
dsh plugin --profile web add github:MathieuPortmann/dsh-history-edit
Restart the profile afterwards. Requires Node ^22.19.0 || >=24 and DSH >=0.2.0-rc.2 <0.3.0
(see Compatibility). Once the package is on npm, dsh plugin --profile web add dsh-history-edit works too.
The plugin has no configuration.
How it works
- The DSH session log is append-only. A message can carry
surfaceOp: replace {startSeq, endSeq}: it takes the place of that range of events in what the model sees (the "surface"). Editing and going back both write one such message; nothing is ever removed from the log. lib/history.jsholds the reasoning over the log as pure functions (which turn a message is in, which range an edit or a go-back replaces, whether a reply can be edited, how an edited reply event looks). It has no dependency and is covered bytests/.index.js(host side) reads the session through DSH, callslib/history.js, and writes the result. It serves a small JSON channel at/dsh-history/<method>(list,rewrite,rewind,cancelRewind,editReply,canEdit), protected by DSH's own connection check (Host/Origin fence and browser token).client.js(page side) draws the buttons, the edit window and the banner, and hides the turns that were set aside. It finds the chat rows through thedata-chat-flow-kind,data-chat-anchor-keyanddata-chat-turnattributes of DSH's chat page.
Compatibility
| Component | Supported |
|---|---|
| Node.js | ^22.19.0 || >=24.0.0 (engines.node) |
| DSH | >=0.2.0-rc.2 <0.3.0; declared as optional peerDependencies on @deepseek-ai/dsh-llm and @deepseek-ai/schemastery, the only DSH packages the host side imports |
| Platform | Linux (tested); pure JavaScript, no native addon |
| Page | the chat page of DSH's web UI; the buttons depend on its row attributes and may need an update when the page changes |
Tested with DSH 0.2.0-rc.2 on Node 22.23 (see Verification).
Permissions and external services
Everything the plugin can touch, and what happens when it fails:
| Capability | Where | Used for | If it fails |
|---|---|---|---|
| Files | index.js (realpathSync) |
resolves the path of the running dsh binary, to find DSH's own packages; the plugin reads and writes no other file itself |
the plugin fails to load |
| Session log | index.js (through ctx.agents, ctx.sessionController) |
reads the events of a conversation; appends the edited message, and creates a copy of the conversation (new session) for an edit in a copy or an edited reply. This is the plugin's purpose | the operation returns an error code and the page shows a message; the original conversation is not touched |
| Network | none | nothing leaves the computer | n/a |
| Commands | none | no child process, no shell | n/a |
| HTTP route | index.js (ctx.webServer.register) |
POST /dsh-history/<method> for the page, behind ctx.connection.admit() (DSH's Host/Origin fence and token); bodies are limited to 1 MiB and must be JSON |
non-admitted requests get 401/403; other errors are returned as JSON |
| Dynamic module loading | index.js (importFromDsh) |
loads @deepseek-ai/dsh-llm (to build a user message) and @deepseek-ai/schemastery (the empty config schema) from the DSH installation that runs the plugin (a synchronous require of an ES module fails on Node 22). Nothing is downloaded and no code is evaluated from text (eval / new Function are not used) |
the plugin fails to load |
| Hook on the agent loop | index.js (agent/pre-step) |
when you confirm an edit or a go-back, the next user message is written as a replacement. For that, the plugin wraps session.append of that one conversation until the message is written, then removes the wrapper (also on abort or if the session is closed) |
the edit is not applied and the error is reported; a go-back that cannot be computed is dropped and the message is sent normally |
The plugin adds no tool for the model and no setting.
Verification
Checked on a disposable profile (DSH_HOME pointing at a temporary folder, profile cloned with
dsh <name> --from-default-profile web, so the real profile is never touched):
npm pack
dsh plugin --profile t add file:$PWD/dsh-history-edit-0.1.0.tgz # install
dsh --profile t --no-open --port 3095 # start: plugin loads, no error
dsh plugin --profile t remove dsh-history-edit # uninstall
npm test runs 24 standalone tests of lib/history.js (turn outline, edit plans, go-back ranges,
reply cuts, edited replies, contiguity errors) with no DSH installation needed. The module is a
JavaScript port of the logic that first ran in a native addon; the port was compared with that
addon on about 2.2 million generated and real-log cases with identical results.
Develop
npm test
License
MIT
No comments yet. Be the first to write one.