@falling-ts/dsh-force-compact

sessiontested: passnpmMIT

Forces context compression when running low-context llama.cpp models such as Qwen3.8-27B, improving model efficiency and usage smoothness, together with well-refined compaction prompts.

下载量 / Downloads
2,482
依赖体积 / node_modules
1.38 MB
测试时间 / Tested
2026-11-06
DSH 版本 / Version
0.2.2-rc.1

Install

dsh plugin --profile web add @falling-ts/dsh-force-compact

Sandbox test results

StageResult
1 install✓
2 list✓
3 mount✓
4 boot—

Four stages run in an isolated sandbox: install (network on) → list → mount → boot (last three with no network).

README

dsh-force-compact

Aggressive, local-first context compaction for DeepSeek Harness agents.

A DSH Cordis function plugin that keeps the agent's working context lean by design: serve

Qwen3.8‑27B on a self-hosted llama.cpp with a modest context, and the plugin shrinks the

conversation itself — a large-window feel with no API cost and no data egress.

[中文](README.cn.md)


Why

  • Self-hosted inference — the agent talks to a local OpenAI-compatible llama.cpp server

through the standard DeepSeek adapter; no separate adapter needed.

  • Low context, high signal — instead of fighting a small cap, the plugin shrinks the

conversation, so the agent reasons over a tight prompt while keeping deep memory in the

compressed head.

  • Think off for compactions, passthrough everywhere else — disableThinking: true

(default) turns thinking off on this plugin's own compaction summarization call only;

every other model request rides the machine's configuration unchanged.

  • Private & free — no per-token billing, no egress.

What it does

Two compaction engines coexist behind one facade (resolveCompaction), transparent to callers:

Engine · Used when · Notes

Official · the compaction service resolves in the agent realm · Preferred; delegates to compaction/basic.

Builtin · automatic fallback (typical standard preset isolates the service) · Self-contained persistent transaction on ctx.sessions / ctx.llm.stream / ctx.tokenMeter; reuses the official compaction/* event vocabulary, so it replays safely across builds.

No toggling — official wins when reachable, builtin takes over otherwise.

Trigger points

  • Per-request guard (agent/pre-step) — reads the session's projected context tokens

(the exact number the harness renders bottom-right). At autoThresholdTokens it rejects the

outgoing request and compacts the head instead, retaining the latest retainLatestTokens

verbatim. Below the threshold the request proceeds.

  • Turn end / idle (agent/status → idle) — when the agent quiesces, optionally

compacts via compactNow (gate: turnEndForceCompactionEnabled).

  • Manual /force-compact — immediate compactNow when idle; when busy it queues a

process-local flag consumed at the next model step. Loaded lazily — see "Command

availability" under Install. In the / picker the row carries the same face as the

first-party commands: an icon, a localized name and a localized description (the official

presentation table only covers first-party commands, so the client half attaches the face

itself — see AGENTS.md, "指令行的官方外观").

  • session/flush — the awaited durability checkpoint.

Every path funnels into the single "compaction result landed in the session" boundary — the

same point where the LiveUI signal fires.

Decision key is projectedTokens (provider-anchored, same figure as the UI corner), so the

plugin never drifts from what you see; the threshold-aware shrink gate skips summarizer calls

that provably cannot pull the session below the threshold (kills the low-threshold dead loop).

The builtin transaction bills shadowedTokenCount from the same tokenMeter.measure

per-node prices the official engine uses, so the meter's collapse protocol settles the drop

correctly — the bottom-right counter goes down after compaction.

Thinking control: scoped to compactions

Since the 2026-08 semantics revision, disableThinking controls one thing: whether this

plugin's own summarization call (engine/builtin.js → engine/summarizer.js →

ctx.llm.stream) carries reasoningEffort:'off'. Everything else is untouched:

Call site · With disableThinking: true

Builtin-engine summarization call · Carries reasoningEffort:'off'

Every other model request (business, sub-agents, tools, other plugins) · Machine's LlmCallConfig unchanged

Official compaction service calls · Not routed through any plugin seam — unaffected

A route that cannot express off degrades instead of failing. Not every catalog model

declares an off level — pi-ai's thinkingLevelMap may map it to null, as

opencode-go/deepseek-v4.1-flash does (it accepts only low / high / max, while

deepseek/deepseek-flash accepts off too). The summarizer probes the route's capability

before the call (llm.resolveCallConfig, a detached lookup with no provider I/O) and, when

off is unavailable, uses the cheapest level the route does accept; a model with no

reasoning support at all gets no effort field. Because a thinking route bills its reasoning

trace against the same maxTokens cap, a fixed reasoning allowance is added on top of

maxSummaryTokens (documented as the cap on the summary text) so the summary still fits.

Both are logged once per route:

summarization route opencode-go/deepseek-v4.1-flash does not support reasoning effort 'off'
  — using the cheapest supported level 'low' instead; compaction continues

Before this guard, such a route failed every compaction outright (the harness rejects

the unsupported effort before any provider I/O).

When the target is a llama.cpp / OpenAI-compatible endpoint, the

thinking: { type: 'disabled' } field the adapter emits is silently ignored there — so the

summarizer ALSO stamps the llama.cpp-native top-level reasoning_effort: "none", gated on

the exact same condition. One options object carries BOTH fields:

Endpoint family · Reads · Result

Real DeepSeek API · reasoningEffort:'off' → thinking:{type:'disabled'} · Thinking off ✅

llama.cpp / OAI-compatible · reasoning_effort:"none" (top-level) · enable_thinking=false ✅

Each family tolerates-and-ignores the foreign key, so emitting both is harmless. The field is

stamped in src/engine/summarizer.js (immediately before llm.stream(options)), NOT in the

llm/stream waterfall — a prior draft

…(truncated)

Rendered from the README published on npm. Formatted only, not edited.

Versions

Published on npm::30,最后更新 2026-10-30

Links

GitHub · Homepage · npm

Same category