mingdao-harness 0.6.11 → 0.6.12

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/docs/CONFIG.md CHANGED
@@ -406,6 +406,106 @@ completion 计费,防止推理吃满上限时空轮白烧)、`compactTrigger
406
406
  { "timeout": { "firstTokenMs": 600000, "streamIdleMs": 120000, "totalMs": 1800000 } }
407
407
  ```
408
408
 
409
+ #### 单请求超时之外的"回合级"护栏(v0.6.13)
410
+
411
+ 上面三个超时**都是单请求级**:一次请求最多耗到 `totalMs`。而一个回合最坏是
412
+ `maxRounds × stepLimit` 次请求(默认 3 × 24 = 72),`task` 子代理各自还有一整套预算且可递归派生——
413
+ 真机实测出现过「本地 35B 的审计回合跑了 4 小时 20 分、界面 0 步、`web-server.log` 只有一行」的现场
414
+ (`audit.jsonl` 里那 4 小时里有 610 次工具调用,绝大多数是**逐字重复**的失败调用)。
415
+ 所以补了一条回合级判据:
416
+
417
+ ```json
418
+ { "noProgressTimeoutMs": 3600000 }
419
+ ```
420
+
421
+ - **判据**:连续 N 分钟**既没有"成功且不重复的工具结果"、也没有新的正文/推理增量** → 主动中止整个
422
+ 回合,并如实报告「连续 N 分钟没有任何工具调用、也没有新内容,已中止」+ 已发生的模型轮次/工具调用数。
423
+ 重复调用(name+args 完全相同)与失败调用**不算进展**——真机现场正是它们把时间烧光的。
424
+ - **默认 60 分钟**的依据:现有单请求总量上限是本地 1800s;回合级阈值取它的 **2 倍**,
425
+ 保证"一次慢 prefill"永远由更具体的请求级超时(首帧/空闲/总量各有文案)先说话,看门狗不抢答;
426
+ 而真干活的回合每隔几秒就有工具结果或正文增量,60 分钟零增量在任何正常回合都不可能。
427
+ - 该值**不能**用 0/负数/Infinity 关掉(一律回落默认,fail-safe);子代理会**继承父回合的截止时刻**
428
+ (24 个并行子代理不会各跑各的几小时)。
429
+
430
+ #### 端点预检(v0.6.13,本地端点自动执行)
431
+
432
+ 对**本地端点**(baseUrl 是回环/内网,或 `customModels.<名>.local: true`)在开工前做一次轻量预检
433
+ (结果缓存 10 分钟,只读不写你的配置):
434
+
435
+ 1. 取 `/v1/models`,把**引擎实际加载的模型名**与配置项名对照(不一致会写出来,避免"配的是 A、跑的是 B");
436
+ 2. 发 **3 次**极小请求(1 条 user + 1 个工具声明 + `max_tokens: 256`),看 `tool_calls` 与 `finish_reason`,
437
+ 给出三态之一:**稳定支持**(3/3)/ **不稳定**(N/3,会提示"agent 任务可能步数为 0")/ **不支持**(0/3);
438
+ 被 `max_tokens` 截断的样本(`finish_reason: length`,思考型模型常见)判为**不可判定**,不当作"不支持";
439
+ 3. 再发一次 **参考 prefill**(约 2000 tokens 的提示)测耗时;
440
+ 4. 与本机历史值比对:**同一端点明显变慢**(≥3 倍)会提示"该端点可能仍在处理上一个请求,建议重启引擎"。
441
+
442
+ 预检结论会出现在:回合开始时的界面 banner、`web-server.log`(`预检 <模型> …` 行)、
443
+ 以及发送前的规模预告里。并且**按实测 TTFT 自适应**超时:首帧上限 = clamp(max(实测首帧×20, 参考prefill×5),
444
+ 既有默认, 1800s)、无进展看门狗 = clamp(max(实测首帧×100, 参考prefill×20), 10min, 60min);
445
+ **你显式配置的 `timeout.*` / `noProgressTimeoutMs` 永远优先**(显式 > 自适应)。
446
+
447
+ ### 用本地模型测 harness(测试者步骤清单)
448
+
449
+ > 这一段是**操作清单**,不是原理说明。按顺序做,能在几分钟内区分"端点不行"和"harness 不行"。
450
+
451
+ **第 0 步:确认引擎在跑、名字对不对**
452
+
453
+ ```bash
454
+ curl -s http://127.0.0.1:8081/v1/models | head -c 400 # 端口按你的部署改
455
+ ```
456
+
457
+ - 返回里应当看到**配置项名**对应的模型。若引擎回的是完整文件路径/别的名字(本机实测:
458
+ 配置 `MLocalModel3.6.2`,引擎回 `/Users/…/mLocalModel3.6.2.gguf`),预检会把两者都写出来——
459
+ 先确认"配的就是跑的那个",再谈性能。
460
+
461
+ **第 1 步:先跑预检(一条命令看到 TTFT 与工具支持)**
462
+
463
+ 预检在**每轮对话开始前自动执行**(仅本地端点),界面上会出现两行:
464
+
465
+ ```
466
+ 🔎 本地端点预检:✅ 稳定支持工具调用(3/3) · 首帧 1.22s · 参考 prefill 2000 tokens 9.71s · 引擎加载 …gguf
467
+ 自适应:首帧上限 600s、无进展看门狗 60 分钟(依据:预检实测 首帧 1220ms + 参考 prefill 9708ms)
468
+ ```
469
+
470
+ 同一条结论会落进 `~/.mingdao/logs/web-server.log`(`预检 <模型> <状态>(<toolState> N/M) ttft=… prefill2000=…`)。
471
+ 看到这些就说明通路与能力都测过了;**不要**跳过这步直接放大任务。
472
+
473
+ **第 2 步:小任务验证通路**
474
+
475
+ ```
476
+ 帮我看看这个仓库的 README,列出三层小标题
477
+ ```
478
+
479
+ 验收标准:几十秒内出现正文;`web-server.log` 里有 `chat 首帧 <taskId> <秒>` 与每 30s 一行的
480
+ `chat 进度 <taskId> 已跑 …阶段=… 模型轮次=… 工具调用=…`;界面状态条上有「工具调用 N 次」(0 也要显示为 0)。
481
+
482
+ **第 3 步:按模块切分,再放大**
483
+
484
+ 35B 级模型 + 131k 窗口做**全量仓库审计**时:上下文越大,prefill 越久(本机实测 35B Q4_K_M
485
+ 约 4.9ms/token:2 万 tokens ≈ 1.6 分钟;13 万窗口 ≈ 10 分钟以上,且会顶满引擎内存预算)。
486
+ 所以:
487
+
488
+ - 先用预设 `local-model`(`contextBudget` 65536)或自己在预设里调小 `contextBudget`;
489
+ - 一次只做一个模块/一个目录,别一次喂整仓;
490
+ - 真要长跑,把 `timeout.firstTokenMs` 调大(例如 900000)——但要知道**这只会让失败更晚被发现**,
491
+ 不会让 prefill 变快。
492
+
493
+ **第 4 步:认识四类"卡住"分别长什么样**
494
+
495
+ | 现象 | 内核会给什么信号 |
496
+ | --- | --- |
497
+ | 引擎没起来 / 端口不对 | 预检 `❌ 不可达:…`;请求以 `网络请求失败` 报错(几秒内) |
498
+ | 连上但不发首帧 | 到 `timeout.firstTokenMs` 报「首 token 等待超限(Ns,本地模型长上下文 prefill 可能很慢)——可调大 config.timeout.firstTokenMs…」 |
499
+ | 有帧但长时间没新数据 | 到 `timeout.streamIdleMs`(默认 120s)报「流式响应空闲超限(Ns 无新数据)」 |
500
+ | 每轮都能返回、但什么都没做成 | 到 `noProgressTimeoutMs`(默认 60min,快端点自适应到 10min)报「连续 N 分钟没有任何工具调用、也没有新内容,已中止」 |
501
+ | 上游 4xx/5xx(模板/内存/鉴权…) | 错误里带**上游原文**并附一条可操作判断(例如"该端点的模板不接受当前 messages 形态") |
502
+
503
+ **第 5 步:模型不支持工具调用时会怎样**
504
+
505
+ 若预检判定 **不支持/不稳定**,或整回合 0 次工具调用:回合结束时界面会明确写出
506
+ 「⚠ 本回合 0 次工具调用(共 N 轮模型请求 / M 步):该端点看起来不返回 tool_calls」——
507
+ 不会出现"看起来在工作、其实什么都没做"。此时换支持 function calling 的端点,或只把它用于纯问答。
508
+
409
509
  ### 文件访问边界(v0.4.1 P0 路径穿越防护)
410
510
 
411
511
  read/write/edit/ls/glob/grep/undo 默认限定在**工作目录**内——auto 权限模式下,模型(或被提示注入
package/docs/DEVELOPER.md CHANGED
@@ -25,7 +25,13 @@
25
25
 
26
26
  1. `<项目>/.mingdao/presets/<名>.json` — 项目级(随项目走)
27
27
  2. `~/.mingdao/presets/<名>.json` — 用户级(本机全局)
28
- 3. `presets/`(随 npm 包分发)— 内置参考(已内置 `local-audit` 示例)
28
+ 3. `presets/`(随 npm 包分发)— 内置参考,现内置两个**语义单一**的示例:
29
+ - `local-model` —— **只放"让本地模型跑得动"的参数**(`contextBudget`/`maxOutputTokens`/`maxRounds`)。
30
+ 本地模型只是替换云模型 API,**功能一致**:所以它不带人格、不限制工具、不建议权限档。
31
+ - `readonly-audit` —— 审计人格 + 只读工具白名单(`tools`)+ `recommendedPermission: "readonly"`(只是**建议**)。
32
+ - 老名字 `local-audit` 保留为**别名**(指向 `local-model`):按老名字调用仍可用,且会打印一次
33
+ 「已更名」提示(CLI/内核日志)并在 WebUI 用 banner 说明——改名兼容,但不静默。
34
+ 若你自己在项目级/用户级写了 `local-audit.json`,**以你的文件为准**(别名只在没找到同名预设时兜底)。
29
35
 
30
36
  ### 1.2 格式
31
37
 
@@ -37,6 +43,7 @@
37
43
  "systemPrompt": "你是代码审查员。只读审查,按严重度分级输出,每条带文件:行号证据。",
38
44
  "tools": ["read", "ls", "glob", "grep", "skill", "git", "fetch", "todo"],
39
45
  "permission": "auto",
46
+ "recommendedPermission": "readonly",
40
47
  "model": "deepseek-v4-flash",
41
48
  "temperature": 0.3,
42
49
  "maxOutputTokens": 4096,
@@ -49,6 +56,32 @@
49
56
  未知字段会**校验报错**(防拼写错误静默失效)。
50
57
  `model` 是**建议**:CLI 在未显式 `-m` 时采纳;WebUI 以用户当前选择的模型为准(预设不覆盖)。
51
58
 
59
+ `permission` 与 `recommendedPermission` **不是一回事**(v0.6.14 起):
60
+
61
+ | 字段 | 语义 | 谁该用 |
62
+ | --- | --- | --- |
63
+ | `permission` | **覆盖**本回合的权限档(仍受反提权规则约束:只能更保守,不能更宽松) | 第三方/老预设;**内置预设不得声明** |
64
+ | `recommendedPermission` | **建议**:只透出给界面/诊断,**不参与判定、不覆盖用户选择** | 内置预设想表达"建议只读"时用它 |
65
+
66
+ 只读的**硬约束**是 `tools` 白名单(不含 `write`/`edit`,模型连写工具都看不到),不是权限档。
67
+
68
+ #### 参数怎么给"本地模型"用(v0.6.15)
69
+
70
+ 给本地部署模型写预设时,**只调参数、别加人格**——本地模型与云模型功能一致,它需要的是
71
+ "预算合适",不是"换个角色":
72
+
73
+ ```json
74
+ { "name": "my-local", "label": "我的本地模型", "contextBudget": 65536, "maxOutputTokens": 4096, "maxRounds": 4 }
75
+ ```
76
+
77
+ - `contextBudget` 是**最要紧的一个**:本地引擎的 prefill 时间与内存随上下文线性上涨
78
+ (本机 35B Q4_K_M 实测约 4.9ms/token:2 万 tokens ≈ 1.6 分钟、13 万窗口 ≈ 10 分钟以上,
79
+ 且大上下文会顶满引擎内存预算)。给 32k–65k 通常就够单个模块级任务。
80
+ - 模型窗口/最大输出等**能力声明**请写在 `config.customModels.<模型名>`
81
+ (`contextWindow`/`maxOutputTokens`/`local`),不要再写一份进预设——两处会漂移。
82
+ - 想让"本地模型 + 只读审计"同时生效:两个预设**不能叠加**(一次只能选一个)。
83
+ 要么用 `readonly-audit` 并自己把 `contextBudget` 调小,要么复制一份按需合并。
84
+
52
85
  ### 1.3 使用
53
86
 
54
87
  - CLI:`mingdao --preset code-reviewer "审查 src/ 目录"`;交互模式 `mingdao --preset code-reviewer`。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mingdao-harness",
3
- "version": "0.6.11",
3
+ "version": "0.6.12",
4
4
  "description": "MingDao Harness —— 开源智能体框架(Agent Harness)。零依赖、开箱即用,针对 DeepSeek-V4 系列优化,开放主流模型接入。",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "local-model",
3
+ "label": "本地模型(保守参数)",
4
+ "description": "给**本地部署模型**用的保守参数预设。先说清两件事:① 本地模型与云模型**功能一致**——本预设不加人格、不限制工具、不建议权限档,只把「上下文预算 / 单次最大输出 / 轮次」调到本地推理跑得动的量级;② 它**不是**代码审计预设(审计人格与只读工具白名单在另一个预设 readonly-audit 里)。为什么只调这几个数:本地引擎的瓶颈在 prefill 与显存/内存预算(本机实测 35B Q4_K_M:约 4.9ms/token,2 万 tokens 上下文的 prefill ≈ 1.6 分钟,13 万窗口 ≈ 10 分钟以上,还会把引擎的内存预算顶满)——预算给小一点,任务跑得完、也更容易看清是哪一步慢。模型窗口/最大输出等**能力声明**请写在 config.customModels.<模型名>(contextWindow/maxOutputTokens),本预设只覆盖本回合参数。",
5
+ "contextBudget": 65536,
6
+ "maxOutputTokens": 4096,
7
+ "maxRounds": 4
8
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "readonly-audit",
3
+ "label": "只读代码审计",
4
+ "description": "只读代码审计预设:审计人格 + 只读工具白名单 + 保守参数。三点先说清:① 本预设**不启用审计日志/账本**——那是 config.audit 与 `mingdao ledger`,与本预设无关,别把它当合规审计开关;② 本预设**不覆盖你的权限档**——只读效果由 tools 白名单保证(里面没有 write/edit,模型根本看不到写工具),权限档始终以你的显式选择为准(recommendedPermission=readonly 只是建议,不参与判定);③ 它**不是**本地模型专用预设——要调本地模型的上下文/输出预算用 local-model(本预设与它相互独立)。",
5
+ "systemPrompt": "你是一名代码审计员。任务是对给定代码库做只读审计:先 ls/glob 摸清结构,再 read/grep 逐文件审查,可用 git 查看历史与 diff、fetch 抓取相关文档。对于大仓库可分模块派发只读子代理并行审查(task 工具传 readOnly:true,子代理同样只读:read/ls/glob/grep/skill)。输出审计报告:发现的缺陷按严重度分级,每条给出文件:行号证据;不做任何修改。若上下文紧张,先审查最关键的部分并明示未覆盖区域。",
6
+ "tools": ["read", "ls", "glob", "grep", "skill", "git", "fetch", "todo", "task"],
7
+ "recommendedPermission": "readonly",
8
+ "maxRounds": 4,
9
+ "maxOutputTokens": 4096
10
+ }