DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

YubaiLoving /

YubaiLoving/dsh-context-annotations

Verified

Select text anywhere in a DSH conversation, attach a note to it, and send the whole annotation batch together with the next message.

★ 1 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@b2a07e81

dsh-context-annotations

DSH Plugin DSH License: MIT

English · 中文

A DSH (DeepSeek Harness) Web GUI plugin: select any text in the conversation, write a note about it, and let the whole batch ride along with your next message — for that one round only.

This repository carries the dsh-plugin topic, which the DeepSeek Harness documentation requires of plugin repositories so they can be discovered; the link above is the inline, clickable form of that requirement.

What it does

  1. Select → annotate. Select text anywhere in the conversation (a reply, a tool card, your own message), and a floating 注释 button appears beside the selection. Click it, type the note, press Enter. Shift+Enter breaks the line, Escape cancels.
  2. Collect several. Every saved note becomes a numbered marker at the left edge of the passage it is about — hovering a marker shows that note — and a N 条注释 strip appears above the composer. Click the strip to open the pending batch, where each annotation shows its quoted passage and note with edit and delete actions. Clicking a marker opens that note's editor, with a delete button.
  3. Send together. Your message gains one short “💬 N 条注释” bubble; the annotation text never appears in the conversation. Hover that bubble to see exactly which passages the batch quoted and what each note says. The list reaches the model as a system-prompt section, so the request still carries every quoted passage and note. The batch is consumed once and its markers stay in the transcript, dimmed.
  4. Send alone. With an empty composer, the strip's send button starts a round from the annotations alone — no typed text required. That round carries the same 💬 N 条注释 pill as its own message, so the transcript looks no different from a batch that rode a typed message.

How it works

The browser half owns the editing UI; the Host half owns delivery.

  • The browser posts the complete batch to /api/dsh-context-annotations (a route registered through ctx.connection.fetch, behind the carrier's trust fence). It never writes into the draft.
  • The Host keeps that batch per Session and listens on the agent/pre-step waterfall. pre-step hands over exactly the messages the step claimed — never replayed history — so a batch can only ride one round. When the step carries a source.kind === "user" message, the Host appends one extra message that holds only the marker (💬 N 条注释) and leaves the human message byte-for-byte unchanged.
  • The annotation text does not travel in a message: ctx.systemPrompt.section() contributes it to the prompt, and the rendered prompt is logged as a hidden system/message node. The conversation therefore shows one short bubble while the request carries the full list; both are reconstructable from the log, and no plugin event type is invented.
  • The marker message is written before the step records its messages, so it is part of an ordinary user/message record, and the prompt is likewise reconstructable from the log. By design, fork, resume and replay should reproduce the conversation the model saw; no plugin event type is invented.
  • A round needs a message body, and the shipped submit path ignores an empty draft. With nothing typed (and no attachment), the strip therefore writes the batch pill into the composer and submits once that write is visible — the same path a typed message takes. The Host recognises the pill-shaped body as “this round is the batch”, consumes it and appends no second pill. A pill the round did not take (a refused submit, or a write that only reached the composer after the strip stopped waiting) is cleared again after a short grace period, so the plugin does not leave text behind that the user never typed. The strip stays armed until the batch's consumption is observed, so a second click in that window cannot start a duplicate round.
  • The batch outlives only the turn it rode: pre-step marks it consumed (the browser then clears the strip) and that turn's turn/end retires it from the prompt, so a later round never inherits it. A batch that no round consumed is left pending instead — a note written while the model is still answering waits for your next message rather than vanishing with that turn.
  • After a send the browser reconciles with one cheap request: the Host states consumed explicitly, which marks the local annotations sent (the strip collapses and the markers stay, dimmed). The same request adopts a still-pending batch after a page reload.

What the conversation shows vs what the model receives

The conversation gains exactly one short message:

💬 2 条注释

The model receives the list as a system-prompt section:

1. 所选文本:
<the selected passage>
注释:<your note>

2. 所选文本:
<the selected passage>
注释:<your note>

Files

Path Role
lib/index.js Host half: batch store, /api/dsh-context-annotations, agent/pre-step fold
lib/client.js Browser half: selection button, note editor, numbered markers, composer strip and panel
cordis.patch.yml Insert the plugin row into the profile
locale/{zh,en}.json Plugin Manager title and description
test/smoke.mjs Dependency-free test of the fold semantics and the browser bundle's registration
test/client.mjs Regression test for the browser store and the annotation-only send: per-Session push, explicit consumption, editor identity, composer exclusion, pill write/submit/cleanup on a fake clock

Configuration

The bundle currently reads no configuration. The folded list carries no marker line, so it reads as the user's own numbered notes rather than a plugin block.

Install

Installed from this repository:

plugin_manager install_bundle  target="github:YubaiLoving/dsh-context-annotations"

Or from a local checkout of this directory:

plugin_manager install_bundle  (target: this directory)

Limits

  • Markers key on character offsets into the flattened conversation text and are validated against the recorded passage; when that offset no longer matches (the content above the passage changed), a whitespace-insensitive passage search takes over, disambiguated by the passage's occurrence ordinal. There is no DOM path fallback. A passage that is re-rendered with different wording loses its marker; the note itself stays in the strip and is still sent. Markers that would land on the same box are nudged upwards so they do not stack.
  • Annotations live in Host memory per Session. A Host restart drops a pending batch (the browser adopts only what the Host still holds).
  • The float, strip, and panel read documented data-* markers of the shipped conversation shell ([data-conversation-content], [data-composer-seat], [data-composer-card]) and the browser's own selection. No other plugin's DOM is modified.
  • An annotation-only round writes its pill into the composer, so in rare cases a pill can outlive the attempt: the composer refused the write, or a failed send restored its draft after the cleanup window. Delete it by hand; the N 条注释 strip still offers the batch for another attempt. If you had already started typing, the leftover pill sits in front of your text — remove the prefix.
  • A message the user types themselves as 💬 N 条注释 is read as that round's marker: the pending batch is consumed and no second pill is appended. The notes still reach the model through the prompt section, so nothing is lost.
  • The pill spelling is fixed Chinese text (💬 N 条注释) in both halves, independent of the UI locale, because it is also the transcript record.

License

MIT

—/ 5

No ratings yet

Verified DSH bundle

Commit b2a07e813968

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout