dsh-message-handoff
其他 活跃维护

dsh-message-handoff

antonkoatl/dsh-message-handoff

轻量级会话处理扩展,支持对单条消息实现独立的会话状态交接,不干扰整体会话链路运行,开箱即用无需额外配置,可直接嵌入现有消息处理流程,适配多数主流AI会话框架。

1
Stars 标星
0
Forks 分支
1
Watchers 关注
0
Open Issues
JavaScript
主要语言
MIT
开源协议
19 KB
仓库大小
1 个月前
最后推送
一键安装扩展 / 插件指令
dsh plugin --profile web add github:antonkoatl/dsh-message-handoff
git clone https://github.com/antonkoatl/dsh-message-handoff.git
git clone git@github.com:antonkoatl/dsh-message-handoff.git
README.md main

dsh-message-handoff

Per-message session handoff for DeepSeek Harness.
Inspired by dsh-session-handoff. The trigger is a
handoff icon next to each message's fork button (no slash command): forking back to an earlier
point while staying informed about later progress — the child carries the copied history up to the
selected message, and an LLM summary of everything that happened after it is injected on top.

Each finalized assistant message's icon row renders copy · ✋ handoff · fork. Clicking handoff:

  1. copies the verbatim history up to that message into a fresh session (its whole completed
    turn — the same pipeline the web UI's own fork button uses);
  2. summarizes only what happened in the source session after that point with one auxiliary LLM
    call (byte-capped input, oldest entries dropped first); clicking the latest message skips the
    call entirely;
  3. appends the structured handoff document (task goal / progress / decisions / files / next steps /
    open questions) covering that post-fork activity on top of the copied history;
  4. attaches the child to the source's workspace, pins a handoff: <title>, and auto-opens it.

The origin session stays untouched. Any summary failure (no route yet, stream error, timeout,
empty output) leaves zero side effects — no session is created.

⚠️ Privacy: the conversation text AFTER the selected message is sent to the configured model
to produce the summary.

Install

# no build step needed — lib/client.js is prebuilt
dsh plugin --profile web add /path/to/dsh-message-handoff
dsh web
dsh --profile web --dump-config | grep message-handoff

dsh plugin add forwards to pnpm add inside the profile directory, so any install spec works: a directory checkout like above, a git URL once pushed, or the bare package name after publishing. Updating later means editing and re-running the same command.

Zero runtime dependencies: the host half is plain ESM over public services, and the client half is
the official prebuilt browser module (lib/client.js). npm test runs the pure-function unit
suite with node --test.

lib/client.js is intentionally committed: dsh plugin installs run no registry-side build, so
the checked-in module IS the shipped artifact and directory installs work with no toolchain. It
is hand-maintained source (not generated output) — edit it directly; there is no separate build
step to drift from.

Configuration

Optional config: on the cordis.yml row:

- id: message-handoff
  name: dsh-message-handoff
  config:
    maxInputBytes: 24000   # UTF-8 byte cap for the summary input (oldest dropped first)
    maxTokens: 10000       # summary output budget (reasoning-heavy routes need headroom)
    timeoutMs: 120000      # summary call timeout

The summary model route is the source session's latest logged request route (the model that
actually produced the history), falling back to the deployment's default model selection.

How it works

  • Host half (index.mjs): registers /message-handoff <assistant-message-id> in the public
    command registry — resolves the fork cut for the addressed message (first completed turn/end
    at or after it, extended through trailing out-of-band appends, exactly like the api-proxy fork
    handler), summarizes via ctx.llm.stream, creates the child via
    ctx.agents.create({ seed, seedLength, meta, setup }) with agentPresets.resolve → mount,
    then best-effort workspaceRegistry attach and sessionTitle.rename, and appends the handoff
    document with surfaceOp: 'append'. The success text names the child id in backticks.
  • Client half (lib/client.js): registers one additive entry in the
    conversation.chat.assistant-actions slot (rendered between the built-in copy and fork
    controls), dispatches /message-handoff through Remote commands.execute, extracts the child
    id from the result, polls sessions.binding until it is addressable, and opens it. A failed
    handoff turns the icon red with the error in its tooltip; clicking retries.

Model Experience

Summary request (auxiliary model call)

What the model sees

One auxiliary llm.stream request per handoff click with post-fork activity: this package's system prompt below plus a single user message whose text is a JSON array of the conversation turns AFTER the fork cut [{"role":"user"|"assistant","text":"..."}], oldest entries dropped first until it fits maxInputBytes. Clicking the latest message runs no request.

Verbatim summary system prompt
You are producing a handoff summary that gives a forked agent session the context it is missing.
The transcript up to the chosen fork point was copied into the fresh session verbatim; your summary covers ONLY what happened in the source session AFTER that point, so the forked agent knows the later progress without carrying that later transcript.
The user input is a JSON array of the post-fork conversation turns: {"role":"user"|"assistant","text":"..."}.
Produce a concise structured handoff in Markdown with these sections:
## Task goal
## Current progress (what is done and what is not, concrete)
## Key decisions (and their reasons)
## Files involved (paths only)
## Next steps (numbered)
## Open questions / risks
Write in the language of the conversation. Be concrete and factual; do not invent facts that are not in the conversation.
Return only the handoff document, no preamble, no code fences.

Token effect

Conditional and capped: zero tokens until a handoff runs. The one-shot request is bounded by the maxInputBytes input framing and the maxTokens output budget; reasoning effort follows the route default unless the route's adapter lists off, which the summary then pins.

KV Cache effect

Independent behavior: the summary is a separate one-shot call outside any session loop, so it neither reuses nor invalidates provider caches for the source or child conversations.

Handoff document injection

What the model sees

In the forked child session, one appended user/message headed "📋 Session handoff": the source session id, an orientation line stating that the summary covers only post-fork activity, the generated summary, and a continuation note. The copied seed history precedes it unchanged.

Token effect

Append-only growth of the child's context: the copied prefix carries the same tokens as the source history up to the fork cut, plus the document, which scales with the post-fork conversation length under the same maxInputBytes cap.

KV Cache effect

Append-only: the seed replays identically from persistence, so the copied prefix stays prefix-stable across the child's later turns; the injected document sits after that prefix and never rewrites earlier request tokens.

Known Limitations and Deferred Work

  • Assistant-turn-only trigger — the icon renders where the shipped fork control lives, on finalized assistant turns; user messages expose no per-message action strip to sit beside.
  • Preset read from the creation header — a session that switched agent presets mid-flight forks its child under the original composition instead of re-deriving the switch from the log.
  • No durable artifact — the handoff document lives only in the child session log; writing HANDOFF.md remains deferred work.
  • Text-only summarization — tool calls and attachments are excluded from the summary input; only user/message + assistant/message text blocks are extracted.

License

MIT