dsh-vibe-math 0.3.0 → 0.3.2

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.md CHANGED
@@ -15,9 +15,25 @@
15
15
 
16
16
  ---
17
17
 
18
+ ## ✨ 功能特色
19
+
20
+ - **多代理自动求解**:主代理把问题交给调度器,调度器派发 brainstorm / solver / verifier / decider(v1)或 explorer / solver / verifier(v2)等子代理协同求解,**你无需逐节点手操**。
21
+ - **多代理交叉验证**:每个结论交给 ≥3 个「严苛审稿人」**独立审查 → 辩论(交流群)→ 裁决**。
22
+ - **知识沉淀**:验证通过的结论晋升进 `Verified/` 可信知识库(v2 另有 `Propos/` 命题库),供后续方向复用。
23
+ - **断点续跑**:调度状态、任务栈、代理注册表、决策队列、验证器历史准确率等全部落盘;重启后 `resume` 即可恢复(v2 用进程纪元区分"同进程暂停→恢复"与"跨进程重启")。
24
+ - **中途人工干预(并继续)**:`auto / manual` 模式随时切换;manual 在关键节点挂起决策等你 approve/reject/override;可对任意子代理发消息 / 中断。
25
+ - **按项目隔离**:每个数学问题一个独立项目文件夹,互不干扰,可随时切换。
26
+ - **子代理权限可调控**:可限制子代理允许/禁止的工具、每轮外部工具调用上限,并明确告知其可读 `Verified/`、`Propos/`、`Reliable/` 与进度日志。
27
+ - **可配置**:`vibe_math_setting.json`(含注释)自定义默认参数;`/vibe setup` 交互式问答配置。
28
+ - **自然语言控制**:主代理充当「助手 + 汇报者」,你把需求说成人话,它自己调用工具、汇报进度、配置参数。
29
+
30
+ ---
31
+
18
32
  ## 🚀 安装
19
33
 
20
- **方式 A:插件包一键安装(推荐)** —— 同时装出两个预设:
34
+ 两种安装方式,任选其一(也可并存):
35
+
36
+ ### 方式 A:作为插件包一键安装(推荐,同时装出两个预设)
21
37
 
22
38
  ```sh
23
39
  dsh plugin --profile <你的 profile> add dsh-vibe-math
@@ -25,17 +41,22 @@ dsh plugin --profile <你的 profile> add dsh-vibe-math
25
41
  dsh plugin --profile <你的 profile> add github:ChongCyrus/Vibe-Mathematics
26
42
  ```
27
43
 
28
- 安装时插件会自动把两个 preset 写入 `~/.dsh/.agent-presets/`:
29
- `vibe-math-v1/` 与 `vibe-math-v2/`。之后新建会话,预设选择器里选择 **Vibe Math** **Vibe Math V2** 即可。
44
+ 安装时插件会自动把两个 preset 写入 `~/.dsh/.agent-presets/`:`vibe-math-v1/` 与 `vibe-math-v2/`。
45
+ 之后新建会话,预设选择器里选择 **Vibe Math**(v1)或 **Vibe Math V2**(v2)即可。
30
46
 
31
- **方式 B:手动复制**(任选其一)
47
+ ### 方式 B:作为 agent preset 手动安装
32
48
 
33
- ```
34
- C:\Users\<你>\.dsh\.agent-presets\vibe-math-v1\ ← 复制 vibe-math-v1/ 下的 agent.cordis.yml / preset.yml / vibe-math.js
35
- C:\Users\<你>\.dsh\.agent-presets\vibe-math-v2\ ← 复制 vibe-math-v2/ 下的 agent.cordis.yml / preset.yml / vibe-math-v2.js
36
- ```
49
+ 1. 把本仓库对应目录的文件复制到 preset 目录:
50
+
51
+ ```
52
+ C:\Users\<你>\.dsh\.agent-presets\vibe-math-v1\ ← 复制 vibe-math-v1/ 下的 agent.cordis.yml / preset.yml / vibe-math.js
53
+ C:\Users\<你>\.dsh\.agent-presets\vibe-math-v2\ ← 复制 vibe-math-v2/ 下的 agent.cordis.yml / preset.yml / vibe-math-v2.js
54
+ ```
37
55
 
38
- > 修改 preset 文件后需**重启 DSH 进程**再开新会话(standing mount 缓存到进程退出)。
56
+ 2. 新建一个会话,在 preset 选择器里选 **「Vibe Math」** **「Vibe Math V2」**。
57
+ 3. 会话启动后即可使用:工具列表里会出现 `vibe_math_*` 工具,输入框键入 `/vibe` 有自动补全。
58
+
59
+ > 修改 preset 文件后需**重启 DSH 进程**再开新会话(preset 的 standing mount 会缓存到进程退出)。
39
60
 
40
61
  ---
41
62
 
@@ -53,9 +74,27 @@ C:\Users\<你>\.dsh\.agent-presets\vibe-math-v2\ ← 复制 vibe-math-v2/ 下
53
74
 
54
75
  ---
55
76
 
56
- ## 🧩 架构图(v1
77
+ ## 🧠 架构与分工(v1 · 经典)
57
78
 
58
- > Mermaid 原生渲染;可编辑图源见 [docs/架构图.md](docs/架构图.md)。
79
+ 框架 = **一个主代理(助手)+ 一个代码调度器 + 五类子代理**。
80
+
81
+ | 角色 | 类型 | 职责 |
82
+ |---|---|---|
83
+ | **主代理** | LLM(会话里的那个助手) | **自然语言接口 + 汇报者 + 助手**。它**自己不求解、不调度**,只负责:把你的话翻译成 `vibe_math_*` 工具调用、汇报进展、问答式配置参数、执行调控命令。 |
84
+ | **调度器** | 插件代码(非模型) | 唯一主控:读 `qs.csv`、派发子代理、写文件、推进状态机。**所有调度靠编程,不靠代理**。 |
85
+ | **Brainstorm 子代理** | 子代理 | 元认知头脑风暴:约束分解、边界测试、相似问题映射,把问题拆成多个「大相径庭」的求解方向。 |
86
+ | **Solver 子代理** | 子代理 | 每个方向一个专属求解器,**同一会话内多轮迭代**,产出引理(含证明)、子路线、存活概率、完整解法。 |
87
+ | **Derive 子代理** | 子代理 | 当某问题的所有方向都走进死路仍未解决时,基于历史痛点**派生 1~3 个全新方向**。 |
88
+ | **Verifier 子代理** | 子代理 | 每个验证单元 ≥3 个独立「严苛审稿人」,独立审查 → 辩论(交流群)→ 裁决。 |
89
+ | **Decider 子代理** | 子代理 | `Verified/` 出现新结论时,判断它是否解决了某未解决问题,回写 `qs.csv` 并重命名解法文件。 |
90
+
91
+ > 一句话分工:**主代理负责“和人对话”,调度器负责“干活”,子代理负责“动脑”。**
92
+
93
+ ---
94
+
95
+ ## 🧩 架构图 · v1(经典)
96
+
97
+ > 静态 PNG 预览 + 可编辑 Mermaid 图源(GitHub 原生渲染);完整流程说明见 [docs/架构图.md](docs/架构图.md)。
59
98
 
60
99
  ![Vibe Math 架构图](示例图/框架图.png)
61
100
 
@@ -108,6 +147,288 @@ flowchart TB
108
147
  SCHED <-->|"状态落盘 / 断点恢复"| STATE
109
148
  ```
110
149
 
150
+ **一句话流水线**:`qs.csv` → Brainstorm 拆方向 → 每方向一个 Solver 多轮迭代(卡死则 Derive 派生新方向)→ 输出拆成最小验证单元 → ≥3 个 Verifier 独立审查 → 辩论 → 裁决 → 通过晋升 `Verified/` → Decider 回写 `qs.csv`;全程状态落盘 `VibeMath_State/`,`resume` 断点续跑,`manual` 模式在派发/裁决/晋升处挂起人工决策。
151
+
152
+ ---
153
+
154
+ ## 🧩 架构图 · v2(新架构 · 概率驱动)
155
+
156
+ ```mermaid
157
+ flowchart TB
158
+ subgraph L1["👤 交互层"]
159
+ U["😀 用户(自然语言)"]
160
+ M["🤖 主代理(助手 + 汇报者)<br/>翻译需求 · 汇报进度 · 问答配置<br/>不求解 · 不调度"]
161
+ end
162
+
163
+ subgraph L2["⚙️ 调度层(插件代码 · 概率驱动)"]
164
+ SCHED["调度器 Scheduler<br/>唯一文件写者 · 按优先级调度<br/>explorer → 逐方向 solver → 验证器 → 收口<br/>断点持久化 · 人工决策门"]
165
+ end
166
+
167
+ subgraph L3["🧠 子代理层(continuable 持久会话)"]
168
+ EXP["🧭 Explorer<br/>拆方向 / 全死路时重派生(去死路 · 并集)"]
169
+ SOLV["✍️ Solver × N<br/>agent_self_iteration<br/>逐方向多轮迭代"]
170
+ VERI["🔬 Verifier × ≥3<br/>独立审查 → 辩论 → 裁决"]
171
+ end
172
+
173
+ subgraph L4["💾 数据层 · VibeMath/Projects/&lt;项目&gt;/"]
174
+ QS["📋 qs/qs.json<br/>问题 + 解法(正确概率)"]
175
+ PRP["📚 Propos/&lt;分类&gt;_Propos.json<br/>命题(布尔估计 · 证明/证伪列表)"]
176
+ VERD["✅ Verified/<br/>定论事实(0/1)"]
177
+ LOGS["🗄️ Verification_logs/ · Progress_Logs/<br/>· Reliable/ · VibeMath_State/"]
178
+ end
179
+
180
+ U -->|"求解 / 查进度 / 干预"| M
181
+ M -->|"vibe_math_* 工具"| SCHED
182
+
183
+ SCHED -->|"① 按优先级取问题"| QS
184
+ SCHED -->|"② 派 Explorer"| EXP
185
+ EXP -->|"方向集 M_q"| SCHED
186
+ SCHED -->|"③ 每方向一个"| SOLV
187
+ SOLV -->|"引理 → Propos(概率&lt;1)"| PRP
188
+ SOLV -->|"解法 → qs(概率&lt;1)"| QS
189
+ SOLV -.->|"卡死 → 重派生"| EXP
190
+ SCHED -->|"④ 选 r 派 ≥3 验证器"| VERI
191
+ VERI -->|"⑤ 裁决 0/1/中间"| SCHED
192
+ SCHED -->|"⑥ 概率=1 → 收口/晋升"| PRP
193
+ SCHED -->|"已解决 / 优先级 never"| QS
194
+ SCHED -->|"晋升定论"| VERD
195
+ SCHED <-->|"辩论记录 / 状态落盘"| LOGS
196
+ ```
197
+
198
+ **一句话流水线**:`qs.json` 按优先级取问题 → Explorer 拆方向(全死路则重派生)→ 每方向一个 Solver 多轮迭代(引理进 `Propos/`、解法回 `qs.json`,概率均 <1)→ 调度器选 r(命题 / 命题+证明·证伪 / 问题+解法)派 ≥3 验证器独立审查→辩论→裁决 → 概率=1 自动收口(问题 solved、命题 1/0,优先级置 `never`);全程状态落盘,`resume` 断点续跑,`reportMode` 可 file/push/both 汇报。
199
+
200
+ ---
201
+
202
+ ## 📁 目录结构
203
+
204
+ ### v1(经典)
205
+
206
+ ```
207
+ <会话工作区>/VibeMath/
208
+ ├─ current.json # 当前项目
209
+ ├─ vibe_math_setting.json # (可选,全局回退)默认参数 JSONC,含注释
210
+ └─ Projects/<项目>/
211
+ ├─ vibe_math_setting.json # 该项目默认参数
212
+ ├─ qs/qs.csv # 问题清单:id,description,priority,status,deps
213
+ ├─ Verified/ # 已验证可信知识库(绝对可信)
214
+ ├─ Pending_Verification/ # 待验证原始输出
215
+ ├─ Under_Verification/ # 拆解后的最小验证单元
216
+ ├─ Temp/ # 临时工作区
217
+ ├─ Temp_Validated/ # 已验证、待晋升
218
+ ├─ Progress_Logs/ # 每问题进度 + 辩论日志 + 定期报告
219
+ └─ VibeMath_State/ # 调度器私有持久状态(断点恢复用)
220
+ ```
221
+
222
+ ### v2(新架构)
223
+
224
+ ```
225
+ <会话工作区>/VibeMath/
226
+ ├─ current.json # 当前项目
227
+ ├─ vibe_math_setting.json # (可选,全局回退)默认参数 JSONC,含注释
228
+ └─ Projects/<项目>/
229
+ ├─ vibe_math_setting.json # 该项目默认参数
230
+ ├─ qs/qs.json # 问题清单:概述/已解决/解法列表(完整解法·正确概率)/优先级/progress
231
+ ├─ Propos/<分类>_Propos.json # 命题库:概述/布尔估计/细类型/证明·证伪列表/优先级/价值·关键性/progress
232
+ ├─ Reliable/ # 可信参考文献(只读,用户放入)
233
+ ├─ Verified/ # 定论事实索引(布尔估计=0/1 的命题)
234
+ ├─ Verification_logs/ # 每轮验证的辩论记录(审计用)
235
+ ├─ Progress_Logs/ # 定期进度报告 report.json
236
+ └─ VibeMath_State/ # 调度器私有持久状态(断点恢复用)
237
+ ```
238
+
239
+ **铁律(两版通用)**:调度器是**唯一文件写者**(子代理只返回结构化 JSON,从不写文件)。
240
+
241
+ ---
242
+
243
+ ## ⚡ 快速上手
244
+
245
+ ### 方式 A:直接对话(推荐,最省事)
246
+
247
+ 因为主代理内置了使用说明,你**直接说人话即可**:
248
+
249
+ ```
250
+ 帮我用 Vibe Math 证明 √2 是无理数。
251
+ ```
252
+
253
+ 主代理会自动:`vibe_math_add_problem` 加题 → `vibe_math_start` 启动 → 之后你随时问它进度。
254
+
255
+ ```
256
+ 现在进展怎么样了?
257
+ ```
258
+
259
+ 主代理会自动调用 `vibe_math_status` / `vibe_math_report` 并把结果用人话汇报给你。
260
+
261
+ ### 方式 B:命令 / 工具(精确控制)
262
+
263
+ 在对话里直接调用工具(参数为 JSON):
264
+
265
+ | 工具 | 作用 |
266
+ |---|---|
267
+ | `vibe_math_add_problem` | 加题(id/description/priority) |
268
+ | `vibe_math_add_proposition` / `vibe_math_list_propositions`(v2) | 添加 / 列出命题库(id/概述/布尔估计/细类型/价值·关键性) |
269
+ | `vibe_math_start` / `vibe_math_resume` | 启动 / 断点恢复调度器 |
270
+ | `vibe_math_pause` / `vibe_math_abort` | 暂停 / 终止(中断所有子代理) |
271
+ | `vibe_math_status` / `vibe_math_report` | 查看状态 / 完整进度报告 |
272
+ | `vibe_math_set_mode` | 切换 `auto` / `manual` |
273
+ | `vibe_math_set_params` | 运行时调参 |
274
+ | `vibe_math_setup` | 返回参数 schema(交互式配置用) |
275
+ | `vibe_math_save_settings` | 把当前参数存成新默认 |
276
+ | `vibe_math_template` | 生成默认参数模板文件 |
277
+ | `vibe_math_new_project` / `set_project` / `list_projects` | 项目管理 |
278
+ | `vibe_math_list_decisions` / `decide` | 查看 / 裁决人工决策 |
279
+ | `vibe_math_list_agents` / `message_agent` / `interrupt_agent` | 查看 / 发消息 / 中断子代理 |
280
+
281
+ 斜杠命令(与工具等价):`/vibe start|resume|pause|abort|status|report|mode <auto|manual>|setup|save|template [global|project]|add <id> <desc>|add-proposition <id> <概述>|list-propositions|project [list|new <name>|<name>]|decisions|agents`
282
+
283
+ ---
284
+
285
+ ## 🎓 教学:让主代理替你干活
286
+
287
+ ### 1. 自然语言驱动(不用记命令)
288
+
289
+ 主代理的作用就是当你的「翻译官」。你只需描述**目标**,它会自己选择并调用工具:
290
+
291
+ | 你说的话 | 主代理做的事 |
292
+ |---|---|
293
+ | “求解 / 证明 XXX” | `add_problem` + `start`,之后汇报 |
294
+ | “现在进度怎么样 / 有哪些代理在跑” | `status` / `report` / `list_agents` 并总结 |
295
+ | “暂停 / 终止求解” | `pause` / `abort` |
296
+ | “切到人工模式,我要逐步把关” | `set_mode manual`,之后有决策就 `list_decisions` 提醒你 |
297
+ | “给 q1 的某个求解方向换个思路(比如改成构造性证明)” | `list_agents` 找到 childId → `message_agent` 注入新指令 |
298
+ | “中断某个卡住的子代理” | `interrupt_agent` |
299
+
300
+ ### 2. 问答式参数配置(/vibe setup)
301
+
302
+ 你甚至不用记参数名。说:
303
+
304
+ ```
305
+ 帮我配置一下参数。
306
+ ```
307
+
308
+ 主代理会调用 `vibe_math_setup` 拿到完整参数 schema(每项含**说明 / 选项 / 建议 / 当前值**),
309
+ 然后用 `ask_user_question` **逐项问你**(选项自带解释与建议),你选完它用 `vibe_math_set_params`
310
+ 应用,最后问你是否 `vibe_math_save_settings` 存为默认。
311
+
312
+ 也可以直接跑命令:`/vibe setup`(看 schema)→ 跟主代理说你要改哪些 → `/vibe save`(存默认)。
313
+
314
+ ### 3. 配置文件(vibe_math_setting.json)
315
+
316
+ - **生成模板**:`/vibe template`(生成到工作区)或 `/vibe template project`(生成到当前项目)——
317
+ 会产出一份**带 `//` 注释、逐项中文说明**的 JSON 模板,你手改后重启/resume 即生效。
318
+ - **保存当前值**:`/vibe save` 把当前生效参数写回该文件。
319
+
320
+ ---
321
+
322
+ ## 🌱 新手示例流程(以“证明 √2 是无理数”为例)
323
+
324
+ **Step 1 — 用一句话启动**
325
+
326
+ ```
327
+ 帮我用 Vibe Math 证明:√2 是无理数。
328
+ ```
329
+
330
+ 主代理执行 `vibe_math_add_problem {"id":"q1","description":"证明:√2 是无理数。","priority":0}`
331
+ 再执行 `vibe_math_start`,然后告诉你“已启动”。
332
+
333
+ **Step 2 — 询问进度**
334
+
335
+ ```
336
+ 进展如何?
337
+ ```
338
+
339
+ 主代理执行 `vibe_math_status` 并用人话汇报:当前活跃子代理数、正在验证的单元、是否有待决策等。
340
+
341
+ **Step 3 — 问答式调参(可选)**
342
+
343
+ ```
344
+ 我想让它用加权投票,并发数设成 6。
345
+ ```
346
+
347
+ 主代理 `vibe_math_set_params {"verdictMode":"weighted-vote","maxParallelThreshold":6}`,
348
+ 并问你是否 `vibe_math_save_settings` 保存。
349
+
350
+ **Step 4 — 中途干预(可选)**
351
+
352
+ ```
353
+ 切到人工模式,我要在每个关键节点把关。
354
+ ```
355
+
356
+ 主代理 `vibe_math_set_mode {"mode":"manual"}`。之后每到一个关键节点它会 `vibe_math_list_decisions`
357
+ 拿到决策,向你说明,等你 `vibe_math_decide {"id":"...","action":"approve"}`(或 `reject` / `override`)。
358
+
359
+ **Step 5 — 收尾**
360
+
361
+ ```
362
+ 结束了吗?结论是什么?
363
+ ```
364
+
365
+ 主代理 `vibe_math_status`:`qs.csv` 里 `q1` 已回写 `solved`,解法文件在 `Verified/` 里并被命名为
366
+ `q1-的解法_<唯一标识>.csv`。
367
+
368
+ > v2 对应的收尾是:`qs.json` 中 `q1.已解决 = true`,其解法 `正确概率 = 1`,相关命题进入 `Verified/`。
369
+
370
+ ---
371
+
372
+ ## 🖼️ 实际使用示例(长截图)
373
+
374
+ > 截图很长,这里默认**折叠**:点击下方「展开」才加载整张长图,避免它占满页面、遮挡前后文字。
375
+
376
+ <details>
377
+ <summary>📸 展开查看实际使用示例长截图</summary>
378
+
379
+ ![实际使用示例长截图](示例图/实际使用示例-长截图.png)
380
+
381
+ </details>
382
+
383
+ ---
384
+
385
+ ## ⚙️ 参数速查表
386
+
387
+ ### v1(经典)默认值
388
+
389
+ | 参数 | 默认 | 说明 |
390
+ |---|---|---|
391
+ | `mode` | `auto` | `auto` / `manual` |
392
+ | `maxParallelThreshold` | 4 | 全局最大并发子代理数 |
393
+ | `solverMaxRounds` | 20 | 每个求解方向最大迭代轮数 |
394
+ | `verifierCount` | 3 | 每验证单元独立验证器数(≥3) |
395
+ | `debateMaxRounds` | 5 | 验证辩论最大轮数 |
396
+ | `verdictMode` | `direct-veto` | `direct-veto` / `weighted-vote` |
397
+ | `provider` / `model` | 空 | 子代理模型(空 = 继承根代理) |
398
+ | `solverPersona` / `verifierPersona` | 空 | 注入求解器/验证器的额外要求 |
399
+ | `solverToolAllow` / `solverToolDeny` | `[]` | 求解器允许/禁止的工具(硬性 toolFilter) |
400
+ | `verifierToolAllow` / `verifierToolDeny` | `[]` | 验证器允许/禁止的工具 |
401
+ | `solverMaxToolCalls` / `verifierMaxToolCalls` | 0 | 每轮外部工具调用上限(0=不限,软性) |
402
+ | `reportIntervalMs` | 30000 | 自动写进度报告的最小间隔 |
403
+
404
+ ### v2(新架构)默认值
405
+
406
+ | 参数 | 默认 | 说明 |
407
+ |---|---|---|
408
+ | `mode` | `auto` | `auto` / `manual` |
409
+ | `maxParallelThreshold` | 4 | 全局最大并发子代理轮数(新派发前须 active < 阈值) |
410
+ | `solverMaxRounds` | 3 | 每个求解方向最大迭代轮数(agent_self_iteration 上限) |
411
+ | `verifierCount` | 3 | 每个验证对象的独立验证器数量 |
412
+ | `debateMaxRounds` | 5 | 验证辩论(交流群)最大轮数 |
413
+ | `verdictMode` | `flat` | `flat` = 均衡机制(不一致判 0.5)/ `forced` = 强制裁决(历史准确率+严谨性加权) |
414
+ | `reportMode` | `file` | `file` = 写报告文件 / `push` = 推送主代理汇报 / `both` |
415
+ | `promoteValueThreshold` | 0.7 | Propos 中「价值/关键性」≥ 该值且未决(0,1) 的命题自动加入 qs.json |
416
+ | `priorityAdjust` | `none` | `none` / `deadend-deprioritize`(全死路降优先级)/ `survival-map`(按存活率重算) |
417
+ | `provider` / `model` | 空 | 子代理模型(空 = 继承根代理) |
418
+ | `solverPersona` / `verifierPersona` | 空 | 注入求解器/验证器的额外要求 |
419
+ | `solverToolAllow` / `solverToolDeny` | `[]` | 求解器允许/禁止的工具 |
420
+ | `verifierToolAllow` / `verifierToolDeny` | `[]` | 验证器允许/禁止的工具 |
421
+ | `solverMaxToolCalls` / `verifierMaxToolCalls` | 0 | 每轮外部工具调用上限(0=不限) |
422
+ | `reportIntervalMs` | 30000 | 进度汇报最小间隔(毫秒) |
423
+
424
+ ---
425
+
426
+ ## 📝 断点续跑 & 人工干预(两大硬性需求)
427
+
428
+ - **断点续跑**:所有状态落盘到 `VibeMath_State/*.json`,每个子代理都是 DSH 的 **continuable 持久会话**(对话由 DSH 自动保存)。重启后新开会话 → `vibe_math_resume` 即可续跑。v2 额外用**进程纪元**区分"同进程暂停→恢复"(保留存活子代理继续)与"跨进程重启"(清理陈旧任务)。
429
+ - **中途人工干预**:`manual` 模式在关键节点(v1:brainstorm/solver 派发、验证裁决、晋升 Verified;v2:explorer/solver 派发、验证裁决)挂起决策;可随时 `set_mode auto` 切回自动;可对任意子代理 `message_agent` / `interrupt_agent`。
430
+ - **进度汇报**:定时 / 有变动时写 `Progress_Logs/report.json`;v2 的 `reportMode` 还能 `push` —— 调度器通过 `rootAgent.followup()` 唤醒主代理主动汇报。
431
+
111
432
  ---
112
433
 
113
434
  ## 📚 规格文档
@@ -117,12 +438,18 @@ flowchart TB
117
438
 
118
439
  ---
119
440
 
120
- ## ⚠️ 已知边界
441
+ ## ⚠️ 已知边界(有意简化)
442
+
443
+ **v1**:
444
+ - `Pending_Verification` 按文件逐个拆解,未做跨文件的“去重 / 引用整合”(不损正确性)。
445
+ - `weighted-vote` 会记录每个验证器的历史准确率 + 严谨性权重,但最终裁决仍遵循“证伪优先 / 全 Uncertain→False”(数值权重仅用于审计)。
446
+ - manual 模式在第一个未决关键节点暂停整条主循环。
121
447
 
122
- - 两个预设的 preset 文件互相独立、可共存;同一会话同时只能选一个预设。
123
- - `vibe-math-v1` 的 `Pending_Verification` 按文件逐个拆解,未做跨文件去重。
124
- - `vibe-math-v2` 的 `flat` 裁决在辩论不一致时直接判 `0.5`;`forced` 按历史准确率+置信度加权。
448
+ **v2**:
125
449
  - 安装器只**补装缺失**的 preset 文件,不覆盖你已编辑的预设(删除对应目录即可重新安装)。
450
+ - `flat` 裁决在辩论不一致时直接判 `0.5`;`forced` 按历史准确率+置信度加权。
451
+ - `never` 优先级的问题/命题**永不调度**,且不阻塞严格终止(视为主动弃权)。
452
+ - 两个 preset 文件互相独立、可共存;同一会话同时只能选一个预设。
126
453
 
127
454
  ---
128
455
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-vibe-math",
3
3
  "description": "Multi-agent mathematical problem-solving & verification frameworks for DeepSeek Harness — TWO agent presets in one install: vibe-math-v1 (classic pipeline: brainstorm → solver iteration → multi-verifier debate → Verified) and vibe-math-v2 (new probability-driven architecture: qs.json + Propos knowledge base + explorer→solver→review/debate verdict). Installing this bundle auto-installs both presets into the DSH preset root.",
4
- "version": "0.3.0",
4
+ "version": "0.3.2",
5
5
  "type": "module",
6
6
  "main": "installer.js",
7
7
  "exports": {
@@ -64,6 +64,10 @@ export function apply(ctx) {
64
64
  let reportDirty = false
65
65
  let tickInFlight = false
66
66
  let explorerRetries = {}
67
+ // Process epoch: written to state at init; a DIFFERENT persisted epoch means a
68
+ // previous DSH process wrote this state (in-flight children are gone), while an
69
+ // equal epoch means same-process pause→resume (children may still be alive).
70
+ const processEpoch = String(Date.now()) + '-' + Math.random().toString(36).slice(2, 8)
67
71
 
68
72
  // ================= helpers =================
69
73
  function textBlock(t) { return { type: 'text', text: String(t) } }
@@ -374,6 +378,7 @@ export function apply(ctx) {
374
378
  return 'id ' + d.id + '「' + d.title + '」method=' + d.method + ' | round=' + d.round + ' status=' + d.status +
375
379
  ' survival=' + d.survival +
376
380
  (d.routes && d.routes.length ? ' | routes: ' + d.routes.map(function (r) { return r.title + '[' + (r.feasibility_signal || '') + ']' }).join('; ') : '') +
381
+ (d.lessons && d.lessons.length ? ' | lessons: ' + d.lessons.join('; ') : '') +
377
382
  (d.blockers && d.blockers.length ? ' | blockers: ' + d.blockers.join('; ') : '')
378
383
  }
379
384
  function solverPrompt(q, dir, round, progressText) {
@@ -384,11 +389,12 @@ export function apply(ctx) {
384
389
  head += '\nStart from the last recorded node of direction ' + dir.id + ' (inherit progress, or branch a sub-route under it). Each round you MUST produce, even if incomplete:\n' +
385
390
  '- new lemmas / intermediate conclusions WITH full proofs (these go to the Propos/ knowledge base);\n' +
386
391
  '- each concrete sub-route tried, its progress overview, an EXPLICIT feasibility signal (e.g. "unremovable singularity", "conflicts with known theorem X"), and any blocker;\n' +
392
+ '- lessons learned from failed attempts (what to avoid, what did not work and why);\n' +
387
393
  '- an updated survival probability for this direction.\n'
388
394
  head += '\nIf you encounter an EXTREMELY complex auxiliary conjecture/sub-problem q_sub: list it in "sub_questions", TEMPORARILY ASSUME it holds, and continue the main line — every later proposition MUST then be stated as "若 <q_sub 标题> 成立,则:..." so the dependency is explicit.\n'
389
395
  head += '\nIf you obtain a COMPLETE solution: adversarially self-check (construct counterexamples, test boundary conditions) BEFORE declaring success; put the full solution text in "solution".\n'
390
396
  head += '\nRespond with ONLY a single JSON object wrapped in a ```json code fence — no prose and no braces { } outside the JSON:\n' +
391
- '{"status":"continue|success|dead-end","solution":"complete solution text, or null","solution_probability":0.85,"lemmas":[{"title":"...","statement":"...","proof":"...","细类型":{"分类名":{}},"布尔估计":0.6,"价值/关键性":0.5,"优先级":1}],"routes":[{"title":"...","progress":"...","feasibility_signal":"...","blocker":"..."}],"survival_probability":0.5,"dead_end_reason":"... or null","sub_questions":[{"title":"...","statement":"..."}]}'
397
+ '{"status":"continue|success|dead-end","solution":"complete solution text, or null","solution_probability":0.85,"lemmas":[{"title":"...","statement":"...","proof":"...","细类型":{"分类名":{}},"布尔估计":0.6,"价值/关键性":0.5,"优先级":1}],"routes":[{"title":"...","progress":"...","feasibility_signal":"...","blocker":"..."}],"lessons":["..."],"survival_probability":0.5,"dead_end_reason":"... or null","sub_questions":[{"title":"...","statement":"..."}]}'
392
398
  return head
393
399
  }
394
400
  function verifierReviewPrompt(r) {
@@ -595,7 +601,12 @@ export function apply(ctx) {
595
601
  const ids = Object.keys(tasks)
596
602
  for (let i = 0; i < ids.length; i++) {
597
603
  const t = tasks[ids[i]]
598
- if (t.type !== 'verify' || t.status !== 'spawning') continue
604
+ if (t.type !== 'verify') continue
605
+ if (t.status === 'paused') {
606
+ const allReported = t.children.length > 0 && t.children.every(function (cid) { const r = t.childResults[cid]; return r && r.round === t.round })
607
+ if (allReported) { t.status = 'debating'; await advanceVerification(t, t.round); continue }
608
+ }
609
+ if (t.status !== 'spawning') continue
599
610
  if (scheduler.activeCount >= params.maxParallelThreshold) break
600
611
  await backfillVerifiers(t)
601
612
  }
@@ -665,6 +676,7 @@ export function apply(ctx) {
665
676
  dir.round = meta.round
666
677
  if (parsed) {
667
678
  if (parsed.routes) dir.routes = (dir.routes || []).concat(parsed.routes)
679
+ if (parsed.lessons) dir.lessons = (dir.lessons || []).concat(parsed.lessons)
668
680
  if (parsed.dead_end_reason) dir.dead_end_reason = parsed.dead_end_reason
669
681
  if (typeof parsed.survival_probability === 'number') dir.survival = clamp01(parsed.survival_probability)
670
682
  if (parsed.lemmas && parsed.lemmas.length) { for (let i = 0; i < parsed.lemmas.length; i++) await addLemmaAsProposition(qid, parsed.lemmas[i]) }
@@ -696,14 +708,19 @@ export function apply(ctx) {
696
708
  logActivity('solver', qid + '/' + dirId + ' dead-end: ' + dir.dead_end_reason)
697
709
  } else {
698
710
  const progressText = prog.directions.map(directionSummary).join('\n')
699
- try {
700
- await followupChild(childId, solverPrompt(q, dir, meta.round + 1, progressText))
701
- agentRegistry[childId].round = meta.round + 1
702
- dir.round = meta.round + 1
703
- } catch (e) {
704
- console.error('vibe-math-v2: solver followup failed: ' + String((e && e.message) || e))
705
- dir.status = 'dead-end'; dir.dead_end_reason = dir.dead_end_reason || '求解器续轮失败(followup 异常)'
711
+ if (!scheduler.running) {
712
+ // paused/aborted: stop the follow-up chain; keep the direction active for resume
706
713
  delete agentRegistry[childId]
714
+ } else {
715
+ try {
716
+ await followupChild(childId, solverPrompt(q, dir, meta.round + 1, progressText))
717
+ agentRegistry[childId].round = meta.round + 1
718
+ dir.round = meta.round + 1
719
+ } catch (e) {
720
+ console.error('vibe-math-v2: solver followup failed: ' + String((e && e.message) || e))
721
+ dir.status = 'dead-end'; dir.dead_end_reason = dir.dead_end_reason || '求解器续轮失败(followup 异常)'
722
+ delete agentRegistry[childId]
723
+ }
707
724
  }
708
725
  }
709
726
  await saveProgress(qid, prog)
@@ -764,6 +781,7 @@ export function apply(ctx) {
764
781
  }
765
782
  async function advanceVerification(t, round) {
766
783
  if (round < params.debateMaxRounds && !consensus(t) && t.children.length > 0) {
784
+ if (!scheduler.running) { t.status = 'paused'; return } // resume will re-advance this task
767
785
  t.round = round + 1
768
786
  const transcript = buildTranscript(t)
769
787
  const nextChildren = []
@@ -922,23 +940,29 @@ export function apply(ctx) {
922
940
 
923
941
  // ================= init / control =================
924
942
  async function resolveRootAgent(agent) { if (rootAgent) return rootAgent; if (agent) { rootAgent = agent; return rootAgent } try { const roots = agents.roots ? agents.roots() : []; if (roots && roots.length > 0) { rootAgent = roots[0]; return rootAgent } } catch (e) {} return rootAgent }
925
- async function init(agent) {
943
+ async function init(agent, fresh) {
926
944
  await resolveRootAgent(agent); if (!rootAgent) return { ok: false, message: 'no root agent available' }
927
945
  currentProject = await readCurrentProject(); await ensureDirs()
928
946
  if ((await readJson('qs/qs.json')) === undefined) await writeJson('qs/qs.json', [])
929
947
  params = Object.assign({}, DEFAULT_PARAMS); await loadSettings(); await loadState()
930
- // In-flight children of a previous process are gone after restart: drop stale
931
- // registrations so scheduling is not blocked by phantom entries. Completed work
932
- // already lives in qs.json / Propos / progress; only the interrupted turn is lost.
933
- if (Object.keys(agentRegistry).length > 0 || Object.keys(tasks).length > 0) {
934
- logActivity('resume', 'cleared ' + Object.keys(agentRegistry).length + ' stale agent(s) and ' + Object.keys(tasks).length + ' in-flight task(s) from previous process')
935
- agentRegistry = {}; tasks = {}
948
+ // Distinguish same-process continue from cross-process restart via processEpoch:
949
+ // equal epoch = same process (pause→resume; children may still be alive), different
950
+ // epoch = previous process wrote this state (in-flight children are gone).
951
+ const prevEpoch = await readJson('VibeMath_State/process_epoch.json')
952
+ const stale = typeof prevEpoch === 'string' && prevEpoch !== processEpoch
953
+ if (fresh || stale) {
954
+ if (fresh) { const ids = Object.keys(agentRegistry); for (let i = 0; i < ids.length; i++) await interruptChild(ids[i]) }
955
+ if (Object.keys(agentRegistry).length > 0 || Object.keys(tasks).length > 0) {
956
+ logActivity(fresh ? 'start' : 'resume', 'cleared ' + Object.keys(agentRegistry).length + ' agent(s) and ' + Object.keys(tasks).length + ' task(s) (' + (fresh ? 'restart' : 'stale from previous process') + ')')
957
+ agentRegistry = {}; tasks = {}
958
+ }
936
959
  }
960
+ await writeJson('VibeMath_State/process_epoch.json', processEpoch)
937
961
  scheduler.activeCount = 0; await saveAll()
938
962
  return { ok: true }
939
963
  }
940
- async function startScheduler(agent) { const r = await init(agent); if (!r.ok) return r; scheduler.running = true; scheduler.startedAt = now(); scheduler.gate = null; logActivity('start', 'scheduler started for project ' + currentProject); await saveAll(); await maybeWriteReport(true); scheduleTick(); return { ok: true, message: 'scheduler started', project: currentProject, frameworkRoot: frameworkRoot() } }
941
- async function resumeScheduler(agent) { const r = await init(agent); if (!r.ok) return r; scheduler.running = true; scheduler.gate = null; logActivity('resume', 'scheduler resumed'); await saveAll(); await maybeWriteReport(true); scheduleTick(); return { ok: true, message: 'scheduler resumed', project: currentProject, frameworkRoot: frameworkRoot() } }
964
+ async function startScheduler(agent) { const r = await init(agent, true); if (!r.ok) return r; scheduler.running = true; scheduler.startedAt = now(); scheduler.gate = null; logActivity('start', 'scheduler started for project ' + currentProject); await saveAll(); await maybeWriteReport(true); scheduleTick(); return { ok: true, message: 'scheduler started', project: currentProject, frameworkRoot: frameworkRoot() } }
965
+ async function resumeScheduler(agent) { const r = await init(agent, false); if (!r.ok) return r; scheduler.running = true; scheduler.gate = null; logActivity('resume', 'scheduler resumed'); await saveAll(); await maybeWriteReport(true); scheduleTick(); return { ok: true, message: 'scheduler resumed', project: currentProject, frameworkRoot: frameworkRoot() } }
942
966
  async function pauseScheduler() { scheduler.running = false; logActivity('pause', 'scheduler paused'); await saveAll(); return { ok: true, message: 'scheduler paused' } }
943
967
  async function abortScheduler() { scheduler.running = false; const ids = Object.keys(agentRegistry); for (let i = 0; i < ids.length; i++) await interruptChild(ids[i]); scheduler.activeCount = 0; logActivity('abort', 'scheduler aborted, ' + ids.length + ' child(ren) interrupted'); await saveAll(); return { ok: true, message: 'scheduler aborted', interrupted: ids.length } }
944
968
  async function getStatus() {
@@ -1021,6 +1045,8 @@ export function apply(ctx) {
1021
1045
  if (cmd === 'save') return await saveSettings()
1022
1046
  if (cmd === 'template') return await createTemplate(args[0] === 'project' ? 'project' : 'global')
1023
1047
  if (cmd === 'add') { const id = args[0]; const desc = args.slice(1).join(' '); if (!id || !desc) return { ok: false, message: 'usage: /vibe add <id> <description>' }; const qs = await getQs(); if (qs.some(function (q) { return q.id === id })) return { ok: false, message: 'problem id already exists' }; qs.push({ id: id, 概述: desc, 已解决: false, 解法列表: [], 优先级: 0, progress: '' }); await writeQs(qs); scheduleTick(); return { ok: true, message: 'problem added' } }
1048
+ if (cmd === 'add-proposition') { const id = args[0]; const desc = args.slice(1).join(' '); if (!id || !desc) return { ok: false, message: 'usage: /vibe add-proposition <id> <概述>' }; const p = { id: id, 概述: desc, 布尔估计: 0.5, 细类型: { 未分类: {} }, 证明列表: [], 证伪列表: [], 优先级: 1, '价值/关键性': 0.5, progress: '用户通过 /vibe 添加。' }; await upsertProposition(p); scheduleTick(); return { ok: true, proposition: p, file: proposFile(categoryOf(p)) } }
1049
+ if (cmd === 'list-propositions') { const all = await getPropos(); return { ok: true, count: all.length, propositions: all.map(function (p) { return { id: p.id, 概述: p.概述, 布尔估计: p.布尔估计, 优先级: p.优先级, '价值/关键性': p['价值/关键性'], category: p._category } }) } }
1024
1050
  if (cmd === 'project') {
1025
1051
  if (args.length === 0 || args[0] === 'list') return { ok: true, current: currentProject, projects: await listDirsAt(vibeRoot(), 'Projects') }
1026
1052
  if (args[0] === 'new') return await setProject(slugify(args.slice(1).join(' ')), true)
@@ -1028,12 +1054,12 @@ export function apply(ctx) {
1028
1054
  }
1029
1055
  if (cmd === 'decisions') return { ok: true, decisions: decisionQueue.filter(function (d) { return d.status === 'pending' }).map(function (d) { return { id: d.id, node: d.node, context: d.context } }) }
1030
1056
  if (cmd === 'agents') { const out = []; const ids = Object.keys(agentRegistry); for (let i = 0; i < ids.length; i++) { const m = agentRegistry[ids[i]]; out.push({ childId: ids[i], role: m.role, qid: m.qid, direction: m.direction, round: m.round }) } return { ok: true, agents: out } }
1031
- return { ok: false, usage: 'start | resume | pause | abort | status | report | mode <auto|manual> | setup | save | template [global|project] | add <id> <desc> | project [list|new <name>|<name>] | decisions | agents', message: 'unknown /vibe subcommand: ' + (cmd || '(empty)') }
1057
+ return { ok: false, usage: 'start | resume | pause | abort | status | report | mode <auto|manual> | setup | save | template [global|project] | add <id> <desc> | add-proposition <id> <概述> | list-propositions | project [list|new <name>|<name>] | decisions | agents', message: 'unknown /vibe subcommand: ' + (cmd || '(empty)') }
1032
1058
  }
1033
1059
  ctx.effect(() => commands.register({
1034
1060
  name: 'vibe',
1035
- description: 'control the Vibe Math V2 solver (start/pause/projects/setup/save/decisions/agents)',
1036
- input: { hint: '[start|resume|pause|abort|status|report|mode <auto|manual>|setup|save|template [global|project]|add <id> <desc>|project [list|new <name>|<name>]|decisions|agents]' },
1061
+ description: 'control the Vibe Math V2 solver (start/pause/projects/setup/save/decisions/agents/propositions)',
1062
+ input: { hint: '[start|resume|pause|abort|status|report|mode <auto|manual>|setup|save|template [global|project]|add <id> <desc>|add-proposition <id> <概述>|list-propositions|project [list|new <name>|<name>]|decisions|agents]' },
1037
1063
  handler: async function (invocation) {
1038
1064
  const line = String(invocation && invocation.rawInput ? invocation.rawInput : '').trim()
1039
1065
  const parts = line.length > 0 ? line.split(/\s+/) : []