Files
deepseek-harness/packages/compaction/compaction-tool-result-pruner
Turtle 38c7a9fbf4 feat(release): publish package source, declaration maps, and documentation (#5884)
* feat(release): publish package source, declaration maps, and documentation

Every release member publishes its TypeScript source and the declaration
maps that resolve into it, and @deepseek-ai/dsh publishes the repository
Markdown documentation staged from docs/ at prepack time.

The ./src/* export most members already declared now resolves for an
installed consumer, and a consumer editor follows a declaration to the
implementation. Bundled JavaScript maps stay unpublished; the vendored
family and the Desktop runtime file policy are unchanged.

Rationale: .agents/notes/implemented/process/2026-10-08-published-source-and-docs.md

* feat(release): publish JavaScript maps and compress bundles

Every emitted JavaScript map ships beside the bundle it describes, and the
workspace build and the client preset compress bundles without mangling
identifiers.

The documentation payload now mirrors the website publication manifest and
is removed again by `postpack`; Desktop and the Python executable exclude
the published source, documentation, and maps; `clean` removes a staged
copy. Typert's publication contract gains the Remote declaration map.

* fix(release): keep node bundles readable for the worker image

The browser worker image lowers `yield*` only as a whole statement and
rewrites `for await` loops by their source layout, so compressed node-side
entries either fail that lowering or lower to unparseable code. Only the
browser bundles keep compression, which removes about a third of their text.

The bundle-purity assertion now matches the module-loader call regardless of
the quote style compression picks, and the release-pack fixture exercises
the installed package's new documentation requirement.

* feat(release): publish the whole documentation tree

`@deepseek-ai/dsh` copies `docs/` in full instead of the website's page
set: the maintainer documents, the generated migration records, the
translation guidelines, and the `*.i18n.yaml` consistency records ship
with the installed package, so the documentation's own links resolve
without a checkout.

* feat(release): publish the upgrade guides with the documentation

The staged documentation keeps the website's page set and adds every
`docs/upgrade-guide/` document, which is what an installed reader consults
when a released change breaks something. The rest of the maintainer tree
stays out.

* test(release): expect source and maps in master's new payload cases

* feat(release): keep installed docs and source readable in Desktop

Desktop keeps the published src/ and docs/ trees inside app.asar, and
every model shell call receives DSH_INSTALL_DIR and DSH_NODE_EXECUTABLE
so an agent can read them through Electron's Node mode. Staging also
generates docs/upgrade-guide/README.md, an index of the upgrade guides
grouped by the release they upgrade from.

Minified client bundles print string literals with backticks: the
worker image packer now recognizes those chunk requests, client license
banners are prepended after minification so their text survives, and
the affected artifact tests accept either quote.

* test(desktop): read archived docs through the Windows PowerShell form

Regenerate the config catalog for the shifted shell-env source line.

* test(desktop): wait for the GUI-subsystem Electron process from PowerShell

* build(release): publish source and maps from the message-quotes package

* build(release): publish source and maps from packages new on master

* build(release): publish source and maps from the tool-office package
2026-11-05 00:22:36 +08:00
..

description, kind
description kind
Tool-output trimming for deployments composing compaction: choosing size limits or debugging why oversized tool results get shortened. package-reference

@deepseek-ai/dsh-compaction-tool-result-pruner

English | 中文

Summary

dsh-compaction-tool-result-pruner keeps oversized tool output from filling the context window. Once a compaction trigger qualifies, it replaces over-budget text with a bounded head, a short "middle pruned" marker, and a bounded tail; below-pressure conversations remain unchanged. The complete original result remains in the session log for exact replay and inspection. Trimming makes no model call and may relieve enough token pressure to skip summarization. Character budgets only approximate token use; the token meter determines whether pressure was relieved.

Table of Contents


Use this package

Mount this package next to dsh-compaction-basic when tool output regularly dominates the conversation window. Trimming changes what the model sees — shorter results — and gives compaction less history to condense.

Smallest working composition

Mount token measurement, this package, and the backend in this order:

- name: '@deepseek-ai/dsh-token-meter'
- name: '@deepseek-ai/dsh-compaction-tool-result-pruner'
- name: '@deepseek-ai/dsh-compaction-basic'

With these rows, oversized tool results are trimmed automatically as part of condensation. You can verify success by checking that future requests show the trimmed results; the full originals remain in the session log.

What gets trimmed

Every tool result whose text exceeds the threshold is replaced by a trimmed version: the configured head, a short "middle pruned" marker, and the configured tail. Rich content such as images and structured blocks keeps its order and all logged image-offload selections. The replacement keeps the tool call, step, errors, and metadata — only the text content changes. If a replacement cannot be recorded, the run fails and the trims already applied stay in place.

Setting the size limits

All settings are optional; the defaults trim any result with more than 8,192 text characters to its first 4,096 plus its last 1,024, joined by the marker. The generated configuration catalog is the exhaustive source.

Field Default Meaning
thresholdChars 8192 Trim when combined text exceeds this many Unicode code points.
headChars 4096 Leading Unicode code points retained.
tailChars 1024 Trailing Unicode code points retained.

Character counts are Unicode code points, so slicing never splits an emoji pair, though a multi-character grapheme can still be cut. The head plus the marker plus the tail must fit within the threshold, so a valid configuration trims every over-budget result without growth or repeated rewriting. An unknown setting rejects the plugin at construction.

When trimming runs

Trimming only runs when a compaction trigger qualifies: dsh-compaction-basic invokes it after pressure or overflow is confirmed, before it selects what to condense. Below pressure nothing is trimmed, and trimming itself makes no model call.


Understand the implementation

Implementation internals — click to expand

This section explains the design decisions behind the pruner; the observable behavior is fully covered in Use this package.

Design philosophy

The pruner is built on three commitments:

  • Deterministic one-pass convergence. Slicing is by Unicode code point with fixed budgets, so every emitted result has exactly the configured head, marker, and tail in text code points, is no larger than thresholdChars, and is strictly smaller than the triggering input.
  • Replay-safe replacement. The original event remains in the append-only log; the replacement cites it through sourceEventSeqs, so replay recovers the exact input that produced the pruned result.
  • The shadow-price protocol. compaction/prune immediately precedes its replacement, pricing the exact replaced range through the injected token meter so pure consumers subtract it without per-node state — the shared protocol documented on the compaction/prune event.

Pruning mechanics

Pruning measures text blocks by Unicode code point (non-text blocks cost zero), produces a bounded replacement — or none when content is already within budget — and swaps each over-budget tool result for one newly appended tool/result that replaces the original event and cites it through sourceEventSeqs, immediately preceded by a compaction/prune shadow-price event. A session that rejects a replacement fails the run synchronously; replacements committed earlier in the pass stay durable. Non-text blocks keep their original relative positions, and slicing never splits a UTF-16 surrogate pair. Exact signatures are in src/index.ts.

Source map

File Role
src/index.ts Plugin entry: ToolResultPruner service, pruneSession / pruneContent / measureContent
src/config.ts PRUNE_MARKER, defaults, code-point counting, budget validation
src/types.ts ToolResultPruneConfig, ResolvedConfig, PrunedEntry, PruneResult

Further Exploration

Read these pages when the package-level contract is not enough; they move from the consuming backend to the shared seam and the pricing service.


Model Experience

Pruned tool result

What the model sees

Once a compaction trigger qualifies, future requests see the retained head, \n\n[... tool result middle pruned ...]\n\n, and retained tail in place of the removed text. Rich blocks keep their order. The model does not see a second copy of the original.

Token effect

Each rewritten tool result has at most thresholdChars text code points. Pruning itself makes no model call; compaction-basic skips summarization when the remeasured request falls below pressure, otherwise the summarizer reads the pruned surface.

KV Cache effect

Replacing an earlier result invalidates reuse from the first changed token. The pruned prefix is eligible for reuse while its route, envelope, and preceding history remain identical.

Known Limitations and Deferred Work

These limits define when trimming is a poor fit or needs special care; they are the current package constraints.

  • Character budgets are not token budgets — provider token density varies, so ctx.tokenMeter remains the authority for deciding whether trimming relieved request pressure.
  • Pruning is syntactic — it retains the beginning and end without interpreting which middle lines are semantically important.
  • Grapheme clusters can split — code-point slicing protects surrogate pairs but does not perform locale-aware grapheme segmentation.

Dev Note

Working context for maintainers — click to expand

This Dev Note is working context for maintainers and is explicitly non-authoritative; shipped behavior lives in the sections above, the package code, and the linked Agent Notes.

  • Semantic middle selection, undecided — pruning keeps the head and tail blindly; interpreting which middle lines matter would need a model or structured heuristics, neither of which ships.
  • Token-based budgets, deferred — budgets are Unicode code points; switching to token-based budgets would require an estimator contract the token meter does not expose.