dsh-decision-layer 0.6.3 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.en.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  `dsh-decision-layer` adds structured, explicitly scoped decisions to the DeepSeek Harness (DSH) agent loop, backed by a pluggable adjudication backend. Dangerous-call gating, output self-check, tool narrowing, and loop prevention hook into the agent loop as automatic interventions.
6
6
 
7
- > **0.6.3 is a preview release.** The plugin works, but how much real value the adjudication interventions add is still being explored — every threshold is an unvalidated heuristic default. Treat it as something to observe, not a proven guarantee of impact. See [ROADMAP.md](<ROADMAP.md>) for scope and progress.
7
+ > **0.7.0 is a preview release.** The plugin works, but how much real value the adjudication interventions add is still being explored — every threshold is an unvalidated heuristic default. Treat it as something to observe, not a proven guarantee of impact. See [ROADMAP.md](<ROADMAP.md>) for scope and progress.
8
8
 
9
9
  ## Installation
10
10
 
@@ -36,18 +36,18 @@ Restart `dsh web` and refresh after installing or updating: the host and client
36
36
 
37
37
  - **Manual verdicts** — `decision_evaluate` and the `decision-layer` skill submit `noul`, `score`, or `choice` questions; `decision_check_connection` tests connectivity. Neither counts as an automatic decision or changes agent behavior.
38
38
  - **Configurable backend** — defaults to `https://api.typesafe.ai` and `jev-latest`, with per-field URL/key/model overrides under the same protocol. No request without a key. Custom HTTP endpoints require address-bound plaintext-risk confirmation. For the full steps to run a local ollama + `tev1` backend (adjudication stays on-machine, nothing sent out), see [Running with a local tev1](<docs/en/deploy-tev1-with-plugin.md>).
39
- - **Dangerous-call gate** — before a destructive tool call, a redacted summary asks the backend for a verdict, using a **two-tier model**: only a high-confidence deny is enforced monotonically through the guard to block that call; every other case (a high-confidence allow/ask, low confidence, backend failure, or an invalid result) does not intervene and runs the host's original path. The gate is a safety net that only blocks when the model is confident of danger — it never authorizes on the host's behalf or downgrades approval. Rules are configurable.
40
- - **Output self-check** — scores the final output at turn end against a rubric (0–2, a probability-weighted mean across levels, so it can be fractional). Observe-only by default; an opt-in low-score re-prompt appends one prompt on your behalf when the score is low and the model is confident, at most once per turn.
41
- - **Task-completion review** — when the user spells out multiple delivery conditions (numbered / bulleted / multi-command), each is judged satisfied / unsatisfied / insufficient-evidence via a choice before turn end, with tool evidence primary and self-reported replies not counting as evidence; extraction is deterministic and never infers implicit expectations. Observe-only by default, steer configurable, coexisting with self-check and tracked as separate metrics.
39
+ - **Dangerous-call gate** — before a destructive tool call, a redacted summary asks the backend for a verdict, using a **two-tier model**: only a high-confidence deny is enforced monotonically through the guard to block that call; every other case (a high-confidence allow/ask, low confidence, backend failure, or an invalid result) does not intervene and runs the host's original path. The gate is a safety net that only blocks when the model is confident of danger — it never authorizes on the host's behalf or downgrades approval. Rules are configurable, and so is the **block confidence floor** (`gateSettings.minConfidence`, default 0.6): lower blocks more and may block legitimate commands, higher is more permissive.
40
+ - **Output self-check** — scores the final output at turn end against a rubric (0–2, a probability-weighted mean across levels, so it can be fractional). Observe-only by default; an opt-in low-score re-prompt appends one prompt on your behalf when the score is low and the model is confident, at most once per turn. **The rubric, the low-score threshold (default 1), and the re-prompt confidence floor (default 0.4) are all configurable.**
41
+ - **Task-completion review** — when the user spells out multiple delivery conditions (numbered / bulleted / multi-command), each is judged satisfied / unsatisfied / insufficient-evidence via a choice before turn end, with tool evidence primary and self-reported replies not counting as evidence; extraction is deterministic and never infers implicit expectations. Observe-only by default, steer configurable, coexisting with self-check and tracked as separate metrics. **The minimum condition count (default 2) and the re-prompt confidence floor (default 0.4) are configurable.**
42
42
  - **Output-quality trend alert** — a read-only reminder built on self-check data. After several consecutive high-confidence low scores, the trigger button's icon shifts from grey to amber to red, with a hover hint that the task may have grown harder or the model may be fluctuating and suggesting a prompt tweak or model swap. Purely a hint, never driving automatic intervention; the three thresholds (high-confidence bar / consecutive rounds / severe tier) are configurable (defaults 0.6 / 3 / 5), conservative, and pending real-data calibration.
43
43
  - **Tool narrowing** — at turn start, a noul judges each optional tool's relevance to the task and drops the ones not needed (relevance probability below the drop threshold, default 0.3, configurable), intersecting the host-allowed set and never expanding it. Enforced by default; switch to observe-only to log without changing the tool set. Three safeguards: core tools (read/write/edit/shell/search/todos, plus agent meta-abilities such as asking the user, goals, skills, delivery, background jobs, and teamwork) are always kept and never judged; more optional tools than the candidate cap (default 20, configurable) falls back to observe only; fewer than 5 tools remaining is treated as untrustworthy and skipped. Tools matching a **keep-prefix** allowlist (defaults to `mcp__openviking` and `team_task_`) are also always kept and never judged — good for resident, on-demand tools like memory, retrieval, and teamwork.
44
44
  - **Loop guard** — deterministic and backend-free; denies the same call repeated consecutively past a threshold. Always on and outside the per-feature switches.
45
- - **Session panel** — a dock trigger below the composer opens the panel with automatic-decision metrics (attempts, fallbacks, model suggestions vs actual outcomes), the master switch, and the decision log, with an empty state before any automatic decision. The master switch pauses only automatic intervention.
45
+ - **Session panel** — a dock trigger below the composer opens the panel (it appears together with the official context meter; while a session has no context reading yet, this row stays empty) with automatic-decision metrics (attempts, fallbacks, model suggestions vs actual outcomes), the master switch, and the decision log, with an empty state before any automatic decision. The master switch pauses only automatic intervention.
46
46
  - **Decision-analysis view** — an in-session "Decision analysis" tab (`conversation.view`, alongside chat and trajectory, naturally scoped per session) that reads the persisted log read-only and shows a process profile (per-point attempts and outcome distribution, mean self-check score), a quality-trend threshold backtest, and a decision-accuracy summary, and lets you rate each decision correct / wrong / unsure. Ratings share one source with the intervention panel: a rating on either surface writes to the same log, keyed by decision id, latest wins. Read-only over logs, append-only for annotations; it changes no decision behavior.
47
- - **Per-feature switches** — the config page has an independent switch for the danger gate, output self-check, and tool narrowing, all on by default; turning one off drops that intervention. The loop guard is not covered by these switches.
47
+ - **Per-feature switches and intervention thresholds** — the config page has an independent switch for the danger gate, output self-check, tool narrowing, and task-completion review, all on by default; turning one off drops that intervention. The loop guard is not covered by these switches. Every configurable decision point's threshold is adjustable under "Advanced settings" and stored in `~/.config/dsh-decision-layer/config.json` (editing that file directly also works, taking effect live with no restart): gate block confidence `gateSettings.minConfidence` (0.6), self-check low-score threshold `lowScoreThreshold` (1) / re-prompt confidence `minConfidence` (0.4) / trend thresholds `trendMinConfidence`·`trendRun`·`trendSevereRun` (0.6·3·5) / grading levels `rubric`, narrowing drop threshold `threshold` (0.3) / candidate cap `maxCandidates` (20) / batch strategy `batchMode`, completion minimum conditions `minConditions` (2) / re-prompt confidence `minConfidence` (0.4). The loop guard's repeat threshold (3) is deterministic local logic and is not covered. In the form, a blank or out-of-range value is clamped or falls back to its default; editing `config.json` by hand gets no such fallback — a bad value (out of range, misspelled field, wrong type) makes the whole config fail validation, which shows up as an unreadable config page and every decision point reverting to its own safe default (e.g. the gate back to 0.6 with the built-in rules), so hand-edit only valid values. The form corrects the consecutive-run pair whenever the severe tier would not sit above the warn tier.
48
48
  - **Persisted decision log** — beyond the in-memory panel, decisions are written in full per session to `~/.config/dsh-decision-layer/logs` for research. Files roll by running-instance port and date (`decisions-<port>-YYYY-MM-DD.jsonl`), are batched, and retained for 30 days. Writing is best-effort: a failed flush drops that batch and never breaks the decision path.
49
49
  - **Persisted session metrics** — the panel's live metrics (dock count, per-decision-point cards, recent decision log) no longer reset to zero after a restart. Each session's live state is mirrored, keyed by session id (not port), to `~/.config/dsh-decision-layer/state/<sessionId>.json`, written debounced and atomically on every change and retained for 30 days. A resumed session restores from that snapshot; if it has no snapshot yet but has persisted log history (a session predating this mechanism, or whose snapshot was pruned), a seed is reconstructed from the logs across all ports by session id — the one exception is "actual" gate outcomes (observed allow/deny), which are not in the log and resume from zero. Writing is likewise best-effort and never enters the decision path.
50
50
 
51
51
  ## Safety boundary and development
52
52
 
53
- Automatic intervention only subtracts: the gate only denies, narrowing only removes tools, and neither grants new permissions. The gate defers to native DSH approval on backend failure rather than allowing; self-check, narrowing, and loop-guard errors skip intervention. The redacted summary sent to the backend carries only tool name and command/path with secret redaction — never file content. Node.js `>=20.11`; `npm test` and `npm run build:client` run local checks. Rebuild and commit `lib/client.js` with any client change. 0.6.3 is a preview: the interventions work, but their real value and thresholds are still being explored — feedback on misjudgments and feel observed in the decision log is welcome.
53
+ Automatic intervention only subtracts: the gate only denies, narrowing only removes tools, and neither grants new permissions. The gate defers to native DSH approval on backend failure rather than allowing; self-check, narrowing, and loop-guard errors skip intervention. The redacted summary sent to the backend carries only tool name and command/path with secret redaction — never file content. Node.js `>=20.11`; `npm test` runs the tests, `npm run build:client` builds `lib/client.js` (this is also where strict `tsc` runs), and `npm run check` runs both. **Build output is not committed** ([ADR-0012](<docs/adr/0012-distribution-via-github-actions.md>)): `lib/` is gitignored and the source is the only source of truth. Releases run through `.github/workflows/release.yml`, which builds, gates, `npm pack`s and then asserts with `scripts/assert-pack.mjs` that the tarball really carries `lib/client.js` and leaks no sources — only then does it publish to npm or open a Release. That workflow is manual-only and defaults to `dry_run=true`, so a stray click publishes nothing. Architecture decisions live in [docs/adr/](<docs/adr/README.md>): why each rule exists and what was rejected. 0.7.0 is a preview: the interventions work, but their real value and thresholds are still being explored — feedback on misjudgments and feel observed in the decision log is welcome.
package/README.md CHANGED
@@ -4,11 +4,11 @@
4
4
 
5
5
  DeepSeek Harness(DSH)的结构化裁决插件。它把有明确判断标准的问题交给同协议的裁决后端,供 agent 在需要时使用,并在 agent loop 上接入危险门控、产出自检、工具收窄和防循环等自动介入。
6
6
 
7
- > **0.6.3 是体验版。** 插件功能已可用,但裁决介入能带来多少实际价值仍在探索中——各决策点的阈值都是未经验证的启发式默认值,建议先以观察心态体验,别当成经过验证的效果保证。功能与后续进度以 [ROADMAP.md](<ROADMAP.md>) 为准。
7
+ > **0.7.0 是体验版。** 插件功能已可用,但裁决介入能带来多少实际价值仍在探索中——各决策点的阈值都是未经验证的启发式默认值,建议先以观察心态体验,别当成经过验证的效果保证。功能与后续进度以 [ROADMAP.md](<ROADMAP.md>) 为准。
8
8
 
9
9
  ## 安装
10
10
 
11
- 已发布到 npm 与 GitHub。
11
+ 已发布到 npm 与 GitHub Release。
12
12
 
13
13
  从 npm 安装(补 `@latest`):
14
14
 
@@ -16,12 +16,14 @@ DeepSeek Harness(DSH)的结构化裁决插件。它把有明确判断标准
16
16
  dsh plugin --profile web add dsh-decision-layer@latest
17
17
  ```
18
18
 
19
- 或从 GitHub 安装(不带版本,跟随分支或 tag;仓库已含构建产物 `lib/client.js`):
19
+ 或从 GitHub Release 安装:下载对应版本的 tgz 附件,直接装本地包。
20
20
 
21
21
  ```sh
22
- dsh plugin --profile web add github:xbzbing/dsh-decision-layer
22
+ dsh plugin --profile web add https://github.com/xbzbing/dsh-decision-layer/releases/download/v<版本>/dsh-decision-layer-<版本>.tgz
23
23
  ```
24
24
 
25
+ > 仓库不再提交构建产物 `lib/client.js`([ADR-0012](<docs/adr/0012-distribution-via-github-actions.md>)),因此**不带 ref 的 `github:xbzbing/dsh-decision-layer` 安装不可用**——那样拿到的是没有 `lib/` 的源码树,host 半仍能加载,但面板不会出现。GitHub 侧请用上面的 Release 附件。
26
+
25
27
  也可从源码本地构建后用 `file:` 安装:
26
28
 
27
29
  ```sh
@@ -36,15 +38,15 @@ dsh plugin --profile web add file:/绝对路径/dsh-decision-layer
36
38
 
37
39
  - **手动裁决**:`decision_evaluate` 工具与 `decision-layer` skill 支持显式提交 `noul`、`score`、`choice` 问题,`decision_check_connection` 做连通测试。手动调用和连通测试不计入自动裁决指标,也不改变 agent 行为。
38
40
  - **可配置后端**:默认 `https://api.typesafe.ai`、`jev-latest`,URL、Key、model 可逐字段覆盖;仅支持相同的结构化裁决协议。未配置 Key 时不发送请求。自定义 HTTP 地址需针对实际目标确认明文传输风险,地址变更须重新确认。用本地 ollama + `tev1` 作为后端(裁决不出本机、无数据外发)的完整部署步骤见 [用本地 tev1 配合插件(部署指南)](<docs/zh/deploy-tev1-with-plugin.md>)。
39
- - **危险门控**:破坏性工具调用执行前用脱敏摘要请后端裁决,采用**两档模型**——只有模型高置信判定「拒绝」时才经监控守卫单调拦截该调用;其余情况(高置信放行 / 询问、低置信、后端失败或响应不合法)一律不介入,按宿主原路径执行。门控只做「确信危险才拦」的安全网,不替宿主授权、不降级审批。危险规则可增删配置。
40
- - **产出自检**:回合结束用评分量表给最终产出打分(0–2,按各档位概率加权,可能是小数)。默认只提示、不打断;可开启「低分补完」,得分偏低且模型有把握时以你的名义追加一次补完提示,同一回合最多补一次。
41
- - **任务完成核对**:当用户明确列出多个交付条件(编号 / 项目符号 / 多命令)时,回合结束前用单选逐项判定「已满足 / 未满足 / 证据不足」,工具证据优先、回复自述不算证据;确定性提取、不推断隐含期望。默认只观察、可配 steer,与产出自检并存、指标分列。
41
+ - **危险门控**:破坏性工具调用执行前用脱敏摘要请后端裁决,采用**两档模型**——只有模型高置信判定「拒绝」时才经监控守卫单调拦截该调用;其余情况(高置信放行 / 询问、低置信、后端失败或响应不合法)一律不介入,按宿主原路径执行。门控只做「确信危险才拦」的安全网,不替宿主授权、不降级审批。危险规则可增删配置;**拦截置信度门槛可配**(`gateSettings.minConfidence`,默认 0.6),调低更容易拦、也可能误拦正常命令,调高更宽松。
42
+ - **产出自检**:回合结束用评分量表给最终产出打分(0–2,按各档位概率加权,可能是小数)。默认只提示、不打断;可开启「低分补完」,得分偏低且模型有把握时以你的名义追加一次补完提示,同一回合最多补一次。**评分档位、低分阈值(默认 1)、补完置信度门槛(默认 0.4)均可配。**
43
+ - **任务完成核对**:当用户明确列出多个交付条件(编号 / 项目符号 / 多命令)时,回合结束前用单选逐项判定「已满足 / 未满足 / 证据不足」,工具证据优先、回复自述不算证据;确定性提取、不推断隐含期望。默认只观察、可配 steer,与产出自检并存、指标分列。**最少条件数(默认 2)与补完置信度门槛(默认 0.4)可配。**
42
44
  - **产出质量趋势告警**:建在自检数据上的只读提醒。连续多次高置信低分时,把输入框旁触发按钮的图标从灰变橙、变红,hover 提示可能是任务变难或模型波动、建议调整 prompt 或更换模型。纯提示、不驱动自动干预;高置信门槛 / 连续轮数 / 严重档三个阈值可配(默认 0.6 / 3 / 5),偏保守、待实测校准。
43
45
  - **工具收窄**:回合开始时用 noul 逐个判断可选工具与本轮任务的相关性,摘掉用不上的(相关性概率低于摘除阈值,默认 0.3、可配),只在宿主已允许的集合内取交集、不扩权。默认真正生效,可切到「仅观察」只记录不改工具集。三重保护:核心工具(读写、编辑、Shell、检索、待办,以及问用户、目标、技能、交付、后台作业、协作等 agent 元能力)始终保留、不参与判定;可选工具超过候选上限(默认 20,可配)时自动降为仅观察;保留下来不足 5 个时视为判定不可信、跳过。**保留工具前缀**白名单里的工具(默认含 `mcp__openviking`、`team_task_`)也始终保留、不参与判定,适合记忆 / 检索、协作这类常驻、按需触发的工具。**分批策略**按后端上下文容量自适应(`batchMode`,默认 `auto`):大上下文后端(如 Jev)一次请求判完全部工具;小上下文后端(如本地 tev1,约 2050 token 单请求上限)在遇到上下文超限错误时自动降级为「每工具一次请求、并发执行」并记住,之后直接走拆分,不再反复探测。也可显式设 `single`(始终整批)或 `split`(始终逐工具)。某个工具的拆分请求失败时该工具保守保留。
44
46
  - **防循环**:确定性判断,不走后端;同一调用连续重复超过阈值即拒绝,打断死循环。始终生效,不在决策点开关范围内。
45
- - **会话面板**:输入框下方的 dock 触发器弹出面板,展示自动裁决指标(评估数、失败回退、模型建议与实际结果分列)、会话总开关和决策日志;无自动裁决时显示空态。总开关关闭只暂停自动介入,不影响手动裁决。
47
+ - **会话面板**:输入框下方的 dock 触发器弹出面板(与官方上下文用量指示同时出现,会话刚开始、还没有上下文读数时这一行是空的),展示自动裁决指标(评估数、失败回退、模型建议与实际结果分列)、会话总开关和决策日志;无自动裁决时显示空态。总开关关闭只暂停自动介入,不影响手动裁决。
46
48
  - **决策分析页**:会话内「决策分析」tab(`conversation.view`,与对话/轨迹平级、天然按会话隔离),基于已落盘日志做只读聚合,展示过程画像(各决策点触发数与结果分布、自检平均分)、质量趋势阈值回测、判断准确度汇总,并可对每条决策标注「判对 / 判错 / 说不准」。标注与介入面板同源:任一处标注都写入同一份日志、按决策 id 关联、取最新。只读日志、只追加标注,不改任何决策行为。
47
- - **决策点开关**:详情页配置里,危险门控、产出自检、工具收窄各有独立开关,默认全开;关掉某个决策点就不再对应地介入。防循环不在此范围。
49
+ - **决策点开关与介入阈值**:详情页配置里,危险门控、产出自检、工具收窄、任务完成核对各有独立开关,默认全开;关掉某个决策点就不再对应地介入。防循环不在此范围。可配决策点的介入阈值都在配置页「高级配置」里可调,落到 `~/.config/dsh-decision-layer/config.json`(也可直接改该文件,热生效、无需重启):门控拦截置信度 `gateSettings.minConfidence`(0.6)、自检低分阈值 `lowScoreThreshold`(1)/ 补完置信度 `minConfidence`(0.4)/ 趋势门槛 `trendMinConfidence`·`trendRun`·`trendSevereRun`(0.6·3·5)/ 评分档位 `rubric`、收窄摘除阈值 `threshold`(0.3)/ 候选上限 `maxCandidates`(20)/ 分批策略 `batchMode`、完成核对最少条件数 `minConditions`(2)/ 补完置信度 `minConfidence`(0.4)。防循环的重复阈值(3)是确定性本地逻辑,不在此范围。在配置页填写时,留空或越界的值会被夹取或回落到默认;直接手改 `config.json` 不会兜底——写错值(越界、拼错字段名、类型不符)会让整份配置校验失败,表现为配置页读不出来、各决策点退回各自的安全默认(如门控回 0.6 与内置规则),所以手改只写合法值即可。连续次数要求「严重档 > 告警档」,配置页会自动纠正。
48
50
  - **决策日志落盘**:决策记录在内存面板之外,还按会话全量落盘到 `~/.config/dsh-decision-layer/logs`,供研究回看。文件按运行实例端口和日期滚动切分(`decisions-<端口>-YYYY-MM-DD.jsonl`),批量写入,保留 30 天。写盘为尽力而为,失败只丢当批、不影响决策路径。
49
51
  - **会话指标持久化**:面板的实时指标(dock 计数、各决策点卡片、最近决策日志)在重启后不再归零。每个会话的实时状态按会话 id(非端口)另存一份快照到 `~/.config/dsh-decision-layer/state/<会话id>.json`,每次计数变化防抖写盘、原子落盘,保留 30 天。同一会话恢复时优先读该快照续算;若尚无快照但有历史决策日志(如早于本机制、或快照已被清理的会话),则跨全部端口按会话 id 从日志重建种子续算——唯一例外是「实际结果」(gate 观测到的放行 / 拒绝)无法从日志重建,重启后从零重新累计。写盘同为尽力而为,失败绝不进入决策路径。
50
52
 
@@ -54,4 +56,8 @@ dsh plugin --profile web add file:/绝对路径/dsh-decision-layer
54
56
 
55
57
  ## 开发
56
58
 
57
- 服务端使用 Node.js `>=20.11`(`.mjs`,无需构建);客户端用 TypeScript + esbuild 构建。`npm test` 跑本地测试,`npm run build:client` 生成 `lib/client.js`。改动客户端后需重建并连同 `lib/client.js` 一起提交,否则 GitHub 安装拿到的是旧 bundle。0.6.3 为体验版:介入能力已可用,但实际价值与阈值仍在探索,欢迎反馈决策日志观察到的误判与体感。
59
+ 服务端使用 Node.js `>=20.11`(`.mjs`,无需构建);客户端用 TypeScript + esbuild 构建。`npm test` 跑本地测试,`npm run build:client` 生成 `lib/client.js`(`tsc` 严格模式就在这一步),`npm run check` 跑完两者。
60
+
61
+ **构建产物不入库**([ADR-0012](<docs/adr/0012-distribution-via-github-actions.md>)):`lib/` 已被 `.gitignore` 覆盖,源码是唯一事实来源。发布由 GitHub Actions 的 `release.yml` 完成——构建、跑门禁、`npm pack`,并用 `scripts/assert-pack.mjs` 断言产物里确实有 `lib/client.js` 且没有源码泄漏,之后才发 npm / 建 Release。该 workflow 只手动触发且默认 `dry_run=true`,误点不会发版。
62
+
63
+ 架构决策记录见 [docs/adr/](<docs/adr/README.md>):每条规则为什么存在、当时放弃了哪些备选。0.7.0 为体验版:介入能力已可用,但实际价值与阈值仍在探索,欢迎反馈决策日志观察到的误判与体感。