dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
DSH (DeepSeek Harness) compatibility guard plugin: fixes reasoning-model compaction truncation, doomed sandbox-escalation fail-close, and missing tool description for GPT/Qwen/third-party models
A compatibility guard plugin for DeepSeek Harness (DSH) that repairs four frequent failure modes when driving DSH with non-DeepSeek models (GPT, Qwen-thinking, self-hosted reasoning models, ...). Zero-config out of the box; every fix can be toggled in ~/.dsh/compat-guard.json.
Symptom: summarization truncated at the token cap (incomplete checkpoint) — compaction aborts on every attempt
(upstream Discussion #3465).
Root cause: dsh-compaction-basic summarizes with a hard maxTokens cap (default 8192) and fails closed when the
summary hits it. Reasoning models spend invisible thinking tokens inside that same output budget, so any model that
thinks heavily truncates and compaction aborts.
Fix: intercepts purpose === "compaction" LLM requests on the llm/stream waterfall and
maxTokens to 32768 (configurable); clamps only when a provider explicitly exposes hardMaxTokens, never from DSH's defaultMaxTokens;off > minimal > low);UNSUPPORTED_REASONING_EFFORT).Symptom (upstream Discussion #3877):
Error: sandbox escalation to "danger-full-access" is not strictly wider than this call's current "danger-full-access" mode
Error: invalid justification: expected a non-empty sentence
Root cause: when a sandbox executor is attached, the bash/write/edit tool schemas advertise a
sandbox_permissions field globally, but the effective mode is resolved per session. Execution requires the request to
be strictly wider plus a non-empty justification, otherwise the whole call fails closed. GPT/Claude-class models attach
the field speculatively and blow up in danger-full-access sessions.
Fix: the tools/execute hook resolves the session's standing mode and strips sandbox_permissions +
justification when the request is doomed (same mode / narrower / no sandbox service / unknown mode), executing at
the standing mode — semantically identical, because the model already has what it asked for. Strictly-wider requests are
preserved and go through the normal approval flow.
stripEscalation: "redundant" (default — only strip doomed requests) | "always" (strip even legal escalations,
for sessions with approval prompts disabled) | "off".
missing required property "description"Root cause: bash / run_code / subagent declare a required description argument (used as the UI label);
strict JSON-Schema validation rejects the whole call when the model omits it.
Fix: on tools/execute, before strict validation, synthesize the description from the call payload when required
and missing:
bash → first line of the command (Run: cd /tmp && rm -rf build)run_code → first effective code line (comments / braces skipped)subagent / subagent_fork → first line of the promptworkflow → fills the nested meta.description tooCalls that already carry a usable description are untouched.
Symptom (upstream Discussion #1605):
Error: code run failed (exception): Expected ',', got '<eof>'
Error: code run failed (exception): TypeError: b.stdout.slice is not a function
Root cause: (a) the model emits a syntactically incomplete TypeScript program — unbalanced quotes/backticks/brackets or truncated code, so the type-stripping parser (amaro/SWC) hits end-of-file while expecting a comma; (b) the model treats the bash result's stdout as a string — it is a structured object { text, truncated, spillPath? }; the correct read is res.stdout.text. Both stem from models unadapted to PTC's "call every tool from TypeScript" convention, amplified by the harness reporting only a one-line error with no position.
Fix: the llm/stream hook detects code-mode requests (when run_code is the single wired tool) and appends a compact discipline block to the end of the system prompt: tool results are plain JSON values (no .result() wrapper), the correct bash result shapes, and closure hygiene for complete programs. Appending at the end keeps every provider prefix (and prompt cache) intact.
codeDiscipline: "off" (default — use native AGENTS.md) | "auto" / "always" for legacy mutable request objects; frozen requests skip safely.
~/.dsh/compat-guard.json:
{
"compactionMaxTokens": 32768,
"compactionEffort": "auto",
"compactionStripTools": false,
"compactionPurposes": ["compaction"],
"fillDescription": true,
"descriptionTools": ["bash", "run_code", "subagent", "subagent_fork", "workflow"],
"codeDiscipline": "off",
"stripEscalation": "redundant",
"unknownPolicy": "preserve",
"modelInfoTtlMs": 300000,
"modelInfoTimeoutMs": 5000,
"logFixes": true
}
compactionEffort: "auto" (cheapest level) | "keep" (leave untouched) | an explicit effort id.compactionStripTools: when true, drops the tools list from compaction requests (prevents the model from calling
tools mid-summary; costs the prefix KV cache).codeDiscipline: "off" (default; native AGENTS.md is preferred) | "auto" | "always" for legacy mutable-request compatibility.Apply config changes with systemctl restart dsh-web (or restart your dsh web process). Look for
compat-guard: lines in the logs to see every applied fix.
From the marketplace (Settings → Plugins → Marketplace, searchable as dsh-model-compat-guard) or directly:
dsh plugin --profile web add github:782042369/dsh-model-compat-guard#v0.4.0
Restart dsh web afterwards. Uninstall: dsh plugin --profile web remove dsh-model-compat-guard.
node test/smoke.mjs # mock-driven assertions for all four fixes