Skip to content
dsh.fish
Bundle

dsh-thinking-summary

Readable thinking display for DeepSeek Harness: live per-paragraph summaries of the reasoning stream, rendered in the chat history where the 'Think' row is, with a user-chosen summary model (thinking disabled on summary requests).

Source
lyuwen
stars
1 stars
License
MIT
Updated
Updated 5 days ago

Readme

# dsh-thinking-summary

Readable thinking display for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness):
while the model thinks, the reasoning stream is captured and summarized paragraph by
paragraph, and the summary is shown **inside the chat history** where the built-in
"Think" row used to be. The summary model is chosen in **Settings → General** and is
called with thinking disabled.

## Install

The repo is a Harness **bundle**: a package whose `dsh.bundle.patch` adds one
dual-face row (a Host `ThinkingSummaryService` plus the browser half). Install it
into a profile with `dsh plugin`:

```sh
# from a checkout of this repository
dsh plugin --profile web add .

# directly from GitHub
dsh plugin --profile web add git+https://github.com/lyuwen/dsh-thinking-summary.git
# or shorthand: dsh plugin --profile web add github:lyuwen/dsh-thinking-summary
```

Then restart `dsh web`. The `lib/` artifacts are committed, so no build step runs
on install (the repo has no `prepare` script; `pnpm build` is only for
maintainers rebuilding from source).

Remove with `dsh plugin --profile web remove dsh-thinking-summary` (then restart).

## Requirements

- Harness `web` profile (the browser surface); the Host half needs the `llm`
  service (e.g. `llm-deepseek`) and optionally `agent-default-model`.
- Works against the published `@deepseek-ai/*` packages (`0.1.1-rc.1+`).

## What it does

The built-in "Think" row shows a single streaming line, or a large bulk of raw
text when expanded. This plugin replaces the `assistant-step` renderer so each
reasoning block becomes a disclosure with three stages, live in the message:

| Stage | Shows |
| --- | --- |
| 0 — collapsed | One line: the summary of the last completed paragraph (live "Thinking…" while the first paragraph is still in progress) |
| 1 — first expanded | The thinking flow: each paragraph's summary chained on a vertical rail, plus a "Show raw thinking" link |
| 2 — fully expanded | The raw thinking text |

Clicking the row title only opens/closes stage 1; the fully expanded raw view is
reached from the "Show raw thinking" link inside stage 1, and "Show summaries"
returns from stage 2.

### Paragraph grouping

Summaries are computed per blank-line-separated paragraph, but **sub-threshold
fragments merge forward**: completed fragments keep accumulating into one unit
until it reaches ~160 characters, so a model that breaks its reasoning into
frequent tiny paragraphs does not produce one summary per fragment. The
remainder below the threshold folds into the streaming tail and is summarized
only when the tail completes; a settled message always emits its final
remainder as a unit.

### Old vs new thinking

Only reasoning the plugin observed while streaming is summarized. Historical
reasoning that was already settled when its row mounted is **not** re-summarized:
it keeps the plain raw-thinking disclosure (collapsed = first line, expand = full
text) — unless the Host already has cached summaries for its paragraphs, in which
case those are reused via the `lookup` Remote.

## Architecture

- **Host** (`src/index.ts`) — `ThinkingSummaryService`, a `TypertRemoteService`
  served by the API gateway at `/api/thinkingSummary/*` (source-mode discovery;
  no generated descriptors). Methods:
  - `listModels` → provider/model catalog + current selection.
  - `setModel` → remembers the user's summary model for the plugin's lifetime.
  - `lookup` → cached summaries for settled paragraphs.
  - `summarize` → `llm.stream()` with the selected model,
    `reasoningEffort: 'off'` (thinking disabled on the wire), low temperature,
    and a terse one-sentence system prompt; a model with no reasoning surface
    rejects `'off'` and the call is retried without it. Results are cleaned and
    LRU-cached by text hash.
- **Browser** (`src/client/`) — registers `settings.general.item`
  ("Thinking summary model") and the `conversation.chat.node` key
  `assistant-step`. It watches the live reasoning text from the node's own
  `data.blocks`, splits it into blank-line-separated paragraphs, and summarizes
  completed paragraphs one at a time through the Host Remotes. Text blocks are
  rendered by a lightweight GFM-ish markdown renderer; images go through the
  product's `conversation.message.images` slot; tool-call rows stay on ui-tool.
  The client bundle is self-contained (no product component imports), so it
  builds against the published packages alone.

## Development

```sh
pnpm install
pnpm build        # tsdown → lib/index.js (host) + lib/client.js (browser)
```

## Known limitations

- The answer text is rendered by a lightweight markdown subset (no math,
  footnotes, or file-mention chips); code, tables, lists, and links are
  supported.
- Summaries are computed per completed paragraph; the in-progress tail paragraph
  shows "Thinking…" until it completes.
- The summary-model choice lives in host memory for the plugin's lifetime; a
  restart resets it to the default (DeepSeek-V4-Flash, or the deployment's
  default model).
- Historical reasoning is not summarized (see above); the summary cache lives in
  host memory.

Install

dsh plugin --profile web add github:lyuwen/dsh-thinking-summary

Profile: web

  • This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.
  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source