zeranhub/dsh-context-shaping ↗★ 0
dsh-context-shaping
就地改写或删除会话历史中的回复文本与思考链 适合需要通过人工干预和微调来引导AI后续行为的用户。
安裝
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:zeranhub/dsh-context-shaping說明文件
閱讀完整 README ↗Usage
Per-message buttons (web GUI)
The plugin registers into the conversation.chat.assistant-actions slot (order: 20), so each assistant message gets an action row:
| Button | Action |
|---|---|
| ✏️ | Rewrite this reply. Opens an inline text box prefilled with the current reply text; Save → "Reply rewritten ✓". The reasoning chain and tool calls are kept. |
| 💡 | Rewrite this reasoning chain. Shown only when the message actually has a reasoning block; saving an empty text removes it. |
| ↩️ | Restore the content this rewrite shadowed. Shown only on rewrite nodes. |
| 🗑️ | Delete this message. Asks for confirmation first; the message disappears from the model's view. |
| badge | rewritten marks a node that is itself a rewrite; its original text is still in the event log. |
Button labels and tooltips follow the browser language (zh* → Chinese, otherwise English).
The host composes the row as [clock] copy · extraActions · branch, and our slot's entry is that extraActions — so these buttons sit immediately to the right of the copy icon.
Edit your own message (web GUI)
The AI's buttons are per-message; your own messages have no action row a plugin can extend in this DSH build (see Notes). Instead the plugin adds a small ✏️ Edit mine control in the composer's tool row (conversation.input.left), which opens a full-width editor above the card (conversation.input.dock):
- click Edit mine — it loads your most recent own message (injected
user/messagecontext is skipped); - change the text and press Save;
- the message is rewritten in the model-visible history — nothing is sent, no new turn starts, and the next model request reads the edited text.
/shape command
/shape on its own (or /shape list) prints the current model-visible nodes — the last 10, as [seq] AI|TOOL|YOU , with rewritten nodes marked — followed by the usage list.
| Command | Effect |
|---|---|
/shape, /shape list, ls, ? | List the current model-visible nodes (last 10) with seq, role badge and a 120-character preview. |
/shape show | Print one node's full reply and reasoning chain (and whether it carries tool blocks). |
/shape edit | Rewrite the reply text only; reasoning chain and tool calls are kept. |
/shape think | Rewrite the reasoning chain only; the reply text is kept. |
/shape clear-think | Remove the reasoning chain. |
/shape rewrite | Rewrite the whole node as plain text (part=all). This is the only command that may change a node's role. |
/shape delete | Remove the node from the model's view. |
/shape replace | Replace the contiguous range start..end (inclusive, current surface order) with one message. |
/shape history [n] (alias log) | Rewrite audit trail, newest first (default 10, clamped to 1–50). |
/shape undo [n] (alias restore) | Restore the n-th most recent rewrite (default 1). |
`` is taken verbatim from the command line, spaces included; seq arguments must be integers. Failures are reported as 操作失败: and unknown subcommands as 未知子命令: — command output, error strings and audit lines are in Chinese in 0.2.0.
Model tools
| Tool | Parameters | Notes |
|---|---|---|
shape_list | limit? | List surface nodes in order (or the last N) with seq, role, text. Read-only. |
shape_edit | seq, text, part? (reply/thinking/all), role? | part defaults to reply; role is only honored with part=all. |
shape_delete | seq | Shadow one node with an empty assistant message. |
shape_replace | start, end, role, text | Both endpoints inclusive and must be current surface nodes. |
shape_history | limit? | Read the rewrite audit trail. Read-only. |
shape_restore | seq or index | Undo the rewrite at seq, or the index-th most recent rewrite (1 = most recent). |
All six are refused when exposeTools: false; the four mutating tools require a running top-level session. Failures come back as { "ok": false, "error": "…" }, successes as { "ok": true, "replacementSeq": …, "shadowedSeq": … } and similar fields.
HTTP API
Routes are registered under /api/dsh-context-shaping (prefix registration). GET routes are read-only, POST routes rewrite history.
| Method | Path | Parameters |
|---|---|---|
| GET | /list (or /) | ?sessionId=&limit= — limit = last N rows; omitted or 0 = all. |
| GET | /last-user | ?sessionId= — the most recent message you sent, for the composer's Edit mine control: { ok, found, seq?, messageId?, text?, isRewritten?, sourceKind? }. Skips injected user/message context. Reading only; no top-level check needed. |
| GET | /message | ?sessionId=&messageId= — one node split into reply / reasoning. |
| GET | /history | ?sessionId= — audit trail: in-process journal plus records recovered from the log. |
| POST | /edit | { sessionId, seq | messageId, part?, role?, text } |
| POST | /delete | { sessionId, seq | messageId } |
| POST | /replace | { sessionId, start, end, role, text } |
| POST | /restore | { sessionId, seq | messageId } |
// GET /api/dsh-context-shaping/list?sessionId=abc&limit=2
{ "ok": true, "sessionId": "abc", "total": 12, "rows": [
{ "seq": 10, "type": "user/message", "role": "user", "text": "…", "isRewritten": false },
{ "seq": 11, "type": "assistant/message", "role": "assistant", "text": "…", "messageId": "msg_…", "isRewritten": true }
] }
// POST /api/dsh-context-shaping/edit
// { "sessionId": "abc", "seq": 11, "part": "thinking", "text": "…" }
{ "ok": true, "replacementSeq": 15, "shadowedSeq": 11, "role": "assistant", "part": "thinking", "text": "…" }
| Status | Condition |
|---|---|
| 403 | Request is not from loopback (context-shaping API is loopback-only). |
| 403 | Host header is not a loopback hostname on the current port (invalid host header) — DNS-rebinding defence, applied to GET and POST alike. |
| 403 | POST from a cross-origin page (cross-origin request rejected). |
| 403 | httpEnabled: false, or POST while httpWrite: false. |
| 415 | POST without Content-Type: application/json. |
| 400 | Body is not valid JSON (a body over 256 KiB is rejected the same way). |
| 404 | Session not running (会话 不在运行中), messageId not on the surface, or unknown route. |
200 + ok: false | Operation-level failure: shadowed seq, tool/result node, thinking on a user message, a subagent, and so on. |
| 500 | Internal error. |
Configuration
Set these in the DSH settings page (the plugin registers a settings section, namespace context-shaping) or in the profile config layer. Everything has a default, so the plugin works unconfigured; a missing settings service is harmless (defaults stay in effect).
| Key | Default | Effect |
|---|---|---|
exposeTools | true | Register the shape_* tools for the model. When false, model calls are refused. |
allowToolNodes | false | Allow whole-message rewrite, delete and range replace on messages carrying tool calls (this hides tool records from the model). |
allowRoleChange | true | Allow the command and the GUI to change a message's role (requires part=all). |
allowModelRoleChange | false | Allow the model to change a message's role (off by default, to prevent forged user turns). |
httpEnabled | true | Serve the /api/dsh-context-shaping routes. |
httpWrite | true | Allow HTTP rewrite / delete / restore; false makes the API read-only. |
auditSize | 200 | Rewrite records kept per session. |
maxTextLength | 200000 | Character limit for a single rewrite's text. |