dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
无人值守时没人回答 ask_user_question,也让会话继续走:站在问题 waterfall 前面,有人回答就原样放行;超过可配置窗口(默认 120 秒)后提交标了(推荐)/(Recommended) 的选项,或按 first/last 兜底;计划审批默认仍交给人,需显式开启。
Unattended DSH sessions don't stall on ask_user_question.
When nobody answers a question within a configurable window, this Host plugin claims
the request with the option the asker recommended — the (Recommended) / (推荐)
label — and the agent keeps working. If you do answer in time, your answer passes
through untouched and the plugin never intervenes.
Host-only bundle: nothing renders in the page, no browser half, no dependencies.
Known UI behaviour, by design — not a bug: with a browser page attached, the question card stays on screen after an automatic answer until you dismiss it (「提交」/「跳过」 or a page reload). The answer is already recorded and the turn has continued; see “The question card stays on screen after an automatic answer” below.
# from GitHub (no build step: the source is the artifact)
dsh plugin --profile web add github:AK-blank/dsh-plugin-auto-answer
# from a local checkout while developing
dsh plugin --profile web add /absolute/path/to/dsh-plugin-auto-answer
dsh plugin add writes the package into the profile and selects its bundle layer, so
the row shows up in the GUI's Plugins page and in dsh --profile web --dump-config
(# == dsh-plugin-auto-answer → id: auto-answer).
Installing a new bundle activates it through HMR. Replacing an installed copy of this
plugin needs a dsh web restart: Host module code is cached per process, so a changed
lib/index.js is not reloaded by a re-apply.
ask_user_question is dispatched as the user-questions/request waterfall. The browser
UI answers it by rendering a question card; in a headless run nothing answers it at all.
This plugin registers in front of that chain (prepend) and calls next() — it is a
proxy, not a veto:
| what happens | result |
|---|---|
| a human answers inside the window | their answer wins, unchanged |
| nobody answers before the deadline | the recommended option is submitted |
the next answerer fails outright (NO_PROVIDER with no page, transport ended) | the window keeps running, then the recommended option is submitted |
the tool's own timed window expired (ASK_TIMED_OUT) | the recommended option is submitted immediately instead of returning pending |
the turn is cancelled (ASK_ABORTED, signal aborted) | propagated — a cancelled turn is never answered |
The listener is registered with { global: true, prepend: true }. The global flag is not
optional: Agent events are scope-filtered by the context a listener was registered on, and
a plugin installed through the plugin manager is applied inside one agent's scope — without
it the plugin would only answer the session that installed it.
(Recommended), (推荐), (推荐) or (Recommended),
case-insensitively. The option does not have to be first.fallback decides: first (default), last, or none (never answer,
leave the question to a human).freeText: skip submits an empty
selection — the protocol's own "skipped" answer — while block leaves it open.plan-review intents are ignored by default: approving a plan is a decision with
consequences. planReview: approve / decline opt in explicitly.All keys are optional; the row's config overrides the defaults.
| key | default | meaning |
|---|---|---|
enabled | true | master switch; false registers no listener at all |
timeoutSeconds | 120 | window before the recommended option is chosen (5 – 86400) |
fallback | first | first | last | none when no option is marked |
freeText | skip | skip | block for questions without options |
planReview | ignore | ignore | approve | decline for plan reviews |
# in the profile's cordis.patch.yml, after every bundle layer
- id: auto-answer
name: 'dsh-plugin-auto-answer'
config:
timeoutSeconds: 90
fallback: first
With the tool's own timed mode, keep timeoutSeconds below tool-ask-user's
timeout; otherwise the tool returns pending first and this plugin's answer never
applies. The default blocking tool has no such constraint.
Host logs in dsh web are not visible in the terminal, so the plugin writes an optional
JSONL trace:
DSH_AUTO_ANSWER_LOG=/tmp/auto-answer.jsonl dsh web
{"at":"2026-10-18T03:31:56.138Z","event":"armed","agentId":"session-…","timed":false,"questions":1,"timeoutMs":20000,"picks":[{"id":"color","selected":["蓝色 (Recommended)"]}]}
{"at":"2026-10-18T03:32:16.141Z","event":"answered","agentId":"session-…","reason":"window-elapsed","timeoutMs":20000,"picks":[{"id":"color","selected":["蓝色 (Recommended)"]}]}
Events: armed, answered, delegated (a human answered), delegate_error, failed.
A broken trace path never breaks the question it describes.
Offline self-test (node selftest.mjs) — 39 checks over the package contract, config
normalisation, the recommendation rules, the registration options, the timer races, and
"No unhandled rejection / no leaked timer".
Real installation path: installed into a throwaway profile with dsh plugin add, confirmed
as a bundle layer and row in dsh --profile … --dump-config, and visible on the GUI's
Plugins page under 已安装 → 无人值守自动应答.
End-to-end on a live host (blocking tool as shipped):
armed →
answered exactly 20.003 s later with the recommended option, and the turn finished in
22 s with "你最终选择了蓝色(Recommended)。"armed → delegated (answered-by-ui), the turn finished with "你最终选了香蕉。",
and the card collapsed to 1/1 已回答 normally.Expected behaviour, by design. Please don't file an issue for it.
ask_user_question is answered through a waterfall: the browser Client renders the question
card and waits for the human's own submission, while the Host waits for whoever answers. This
plugin answers on the Host when the window elapses, and the Host has no message that tells
a Client its question was settled elsewhere. The card therefore stays where it was:
Nothing else is affected. The ask_user_question result already carries the picked answer,
the turn continues and finishes normally, and the recorded session data is correct — the
stale card is browser state, not session state.
Dismiss it by clicking 提交 (submit) or 跳过 (skip), or by reloading the page. Submitting a stale card is harmless: the request was already settled, so no late answer is injected and no error is raised (verified). Reloading also clears the session-row label.
A Host-side plugin cannot remove that card: the card belongs to the Client's own request, and only the Client settles it. If a future plugin should close it automatically, that needs a Client-side change.
The plugin does not touch approval/request (tool approvals): auto-approving a command is
a different risk class, and it is deliberately out of scope.
node selftest.mjs # offline: no Harness, no timer left behind, no browser
lib/index.js exports normalizeConfig, isRecommendedLabel, decideQuestion,
planRequest, createRuntime (with injectable now / setTimer / clearTimer / trace)
and apply — the self-test drives the same functions the Harness loads.
MIT.
Unofficial plugin: not affiliated with, endorsed by, or supported by DeepSeek. "DeepSeek" and "DeepSeek Harness" are names/trademarks of their respective owners.