dsh-vibe-math 0.3.1 → 0.3.3

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,11 +74,29 @@ 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
+ 框架 = **一个主代理(助手)+ 一个代码调度器 + 五类子代理**。
59
80
 
60
- ![Vibe Math 架构图](示例图/框架图.png)
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)。
98
+
99
+ ![Vibe Math V1 架构图](示例图/框架图-v1.png)
61
100
 
62
101
  ```mermaid
63
102
  flowchart TB
@@ -108,6 +147,297 @@ 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
+ > 静态 PNG 预览 + 可编辑 Mermaid 图源(GitHub 原生渲染);生成脚本见 [docs/generate_framework_diagram_v2.py](docs/generate_framework_diagram_v2.py)。
157
+
158
+ ![Vibe Math V2 架构图](示例图/框架图-v2.png)
159
+
160
+ ```mermaid
161
+ flowchart TB
162
+ subgraph L1["👤 交互层"]
163
+ U["😀 用户(自然语言)"]
164
+ M["🤖 主代理(助手 + 汇报者)<br/>翻译需求 · 汇报进度 · 问答配置<br/>不求解 · 不调度"]
165
+ end
166
+
167
+ subgraph L2["⚙️ 调度层(插件代码 · 概率驱动)"]
168
+ SCHED["调度器 Scheduler<br/>唯一文件写者 · 按优先级调度<br/>explorer → 逐方向 solver → 验证器 → 收口<br/>断点持久化 · 人工决策门"]
169
+ end
170
+
171
+ subgraph L3["🧠 子代理层(continuable 持久会话)"]
172
+ EXP["🧭 Explorer<br/>拆方向 / 全死路时重派生(去死路 · 并集)"]
173
+ SOLV["✍️ Solver × N<br/>agent_self_iteration<br/>逐方向多轮迭代"]
174
+ VERI["🔬 Verifier × ≥3<br/>独立审查 → 辩论 → 裁决"]
175
+ end
176
+
177
+ subgraph L4["💾 数据层 · VibeMath/Projects/&lt;项目&gt;/"]
178
+ QS["📋 qs/qs.json<br/>问题 + 解法(正确概率)"]
179
+ PRP["📚 Propos/&lt;分类&gt;_Propos.json<br/>命题(布尔估计 · 证明/证伪列表)"]
180
+ VERD["✅ Verified/<br/>定论事实(0/1)"]
181
+ LOGS["🗄️ Verification_logs/ · Progress_Logs/<br/>· Reliable/ · VibeMath_State/"]
182
+ end
183
+
184
+ U -->|"求解 / 查进度 / 干预"| M
185
+ M -->|"vibe_math_* 工具"| SCHED
186
+
187
+ SCHED -->|"① 按优先级取问题"| QS
188
+ SCHED -->|"② 派 Explorer"| EXP
189
+ EXP -->|"方向集 M_q"| SCHED
190
+ SCHED -->|"③ 每方向一个"| SOLV
191
+ SOLV -->|"引理 → Propos(概率&lt;1)"| PRP
192
+ SOLV -->|"解法 → qs(概率&lt;1)"| QS
193
+ SOLV -.->|"卡死 → 重派生"| EXP
194
+ SCHED -->|"④ 选 r 派 ≥3 验证器"| VERI
195
+ VERI -->|"⑤ 裁决 0/1/中间"| SCHED
196
+ SCHED -->|"⑥ 概率=1 → 收口/晋升"| PRP
197
+ SCHED -->|"已解决 / 优先级 never"| QS
198
+ SCHED -->|"晋升定论"| VERD
199
+ SCHED <-->|"辩论记录 / 状态落盘"| LOGS
200
+ ```
201
+
202
+ **一句话流水线**:`qs.json` 按优先级取问题 → Explorer 拆方向(全死路则重派生)→ 每方向一个 Solver 多轮迭代(引理进 `Propos/`、解法回 `qs.json`,概率均 <1)→ 调度器选 r(命题 / 命题+证明·证伪 / 问题+解法)派 ≥3 验证器独立审查→辩论→裁决 → 概率=1 自动收口(问题 solved、命题 1/0,优先级置 `never`);全程状态落盘,`resume` 断点续跑,`reportMode` 可 file/push/both 汇报。
203
+
204
+ ---
205
+
206
+ ## 📁 目录结构
207
+
208
+ ### v1(经典)
209
+
210
+ ```
211
+ <会话工作区>/VibeMath/
212
+ ├─ current.json # 当前项目
213
+ ├─ vibe_math_setting.json # (可选,全局回退)默认参数 JSONC,含注释
214
+ └─ Projects/<项目>/
215
+ ├─ vibe_math_setting.json # 该项目默认参数
216
+ ├─ qs/qs.csv # 问题清单:id,description,priority,status,deps
217
+ ├─ Verified/ # 已验证可信知识库(绝对可信)
218
+ ├─ Pending_Verification/ # 待验证原始输出
219
+ ├─ Under_Verification/ # 拆解后的最小验证单元
220
+ ├─ Temp/ # 临时工作区
221
+ ├─ Temp_Validated/ # 已验证、待晋升
222
+ ├─ Progress_Logs/ # 每问题进度 + 辩论日志 + 定期报告
223
+ └─ VibeMath_State/ # 调度器私有持久状态(断点恢复用)
224
+ ```
225
+
226
+ ### v2(新架构)
227
+
228
+ ```
229
+ <会话工作区>/VibeMath/
230
+ ├─ current.json # 当前项目
231
+ ├─ vibe_math_setting.json # (可选,全局回退)默认参数 JSONC,含注释
232
+ └─ Projects/<项目>/
233
+ ├─ vibe_math_setting.json # 该项目默认参数
234
+ ├─ qs/qs.json # 问题清单:概述/已解决/解法列表(完整解法·正确概率)/优先级/progress
235
+ ├─ Propos/<分类>_Propos.json # 命题库:概述/布尔估计/细类型/证明·证伪列表/优先级/价值·关键性/progress
236
+ ├─ Reliable/ # 可信参考文献(只读,用户放入)
237
+ ├─ Verified/ # 定论事实索引(布尔估计=0/1 的命题)
238
+ ├─ Verification_logs/ # 每轮验证的辩论记录(审计用)
239
+ ├─ Progress_Logs/ # 定期进度报告 report.json
240
+ └─ VibeMath_State/ # 调度器私有持久状态(断点恢复用)
241
+ ```
242
+
243
+ **铁律(两版通用)**:调度器是**唯一文件写者**(子代理只返回结构化 JSON,从不写文件)。
244
+
245
+ ---
246
+
247
+ ## ⚡ 快速上手
248
+
249
+ ### 方式 A:直接对话(推荐,最省事)
250
+
251
+ 因为主代理内置了使用说明,你**直接说人话即可**:
252
+
253
+ ```
254
+ 帮我用 Vibe Math 证明 √2 是无理数。
255
+ ```
256
+
257
+ 主代理会自动:`vibe_math_add_problem` 加题 → `vibe_math_start` 启动 → 之后你随时问它进度。
258
+
259
+ ```
260
+ 现在进展怎么样了?
261
+ ```
262
+
263
+ 主代理会自动调用 `vibe_math_status` / `vibe_math_report` 并把结果用人话汇报给你。
264
+
265
+ ### 方式 B:命令 / 工具(精确控制)
266
+
267
+ 在对话里直接调用工具(参数为 JSON):
268
+
269
+ | 工具 | 作用 |
270
+ |---|---|
271
+ | `vibe_math_add_problem` | 加题(id/description/priority) |
272
+ | `vibe_math_add_proposition` / `vibe_math_list_propositions`(v2) | 添加 / 列出命题库(id/概述/布尔估计/细类型/价值·关键性) |
273
+ | `vibe_math_start` / `vibe_math_resume` | 启动 / 断点恢复调度器 |
274
+ | `vibe_math_pause` / `vibe_math_abort` | 暂停 / 终止(中断所有子代理) |
275
+ | `vibe_math_status` / `vibe_math_report` | 查看状态 / 完整进度报告 |
276
+ | `vibe_math_set_mode` | 切换 `auto` / `manual` |
277
+ | `vibe_math_set_params` | 运行时调参 |
278
+ | `vibe_math_setup` | 返回参数 schema(交互式配置用) |
279
+ | `vibe_math_save_settings` | 把当前参数存成新默认 |
280
+ | `vibe_math_template` | 生成默认参数模板文件 |
281
+ | `vibe_math_new_project` / `set_project` / `list_projects` | 项目管理 |
282
+ | `vibe_math_list_decisions` / `decide` | 查看 / 裁决人工决策 |
283
+ | `vibe_math_list_agents` / `message_agent` / `interrupt_agent` | 查看 / 发消息 / 中断子代理 |
284
+
285
+ 斜杠命令(与工具等价):`/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`
286
+
287
+ ---
288
+
289
+ ## 🎓 教学:让主代理替你干活
290
+
291
+ ### 1. 自然语言驱动(不用记命令)
292
+
293
+ 主代理的作用就是当你的「翻译官」。你只需描述**目标**,它会自己选择并调用工具:
294
+
295
+ | 你说的话 | 主代理做的事 |
296
+ |---|---|
297
+ | “求解 / 证明 XXX” | `add_problem` + `start`,之后汇报 |
298
+ | “现在进度怎么样 / 有哪些代理在跑” | `status` / `report` / `list_agents` 并总结 |
299
+ | “暂停 / 终止求解” | `pause` / `abort` |
300
+ | “切到人工模式,我要逐步把关” | `set_mode manual`,之后有决策就 `list_decisions` 提醒你 |
301
+ | “给 q1 的某个求解方向换个思路(比如改成构造性证明)” | `list_agents` 找到 childId → `message_agent` 注入新指令 |
302
+ | “中断某个卡住的子代理” | `interrupt_agent` |
303
+
304
+ ### 2. 问答式参数配置(/vibe setup)
305
+
306
+ 你甚至不用记参数名。说:
307
+
308
+ ```
309
+ 帮我配置一下参数。
310
+ ```
311
+
312
+ 主代理会调用 `vibe_math_setup` 拿到完整参数 schema(每项含**说明 / 选项 / 建议 / 当前值**),
313
+ 然后用 `ask_user_question` **逐项问你**(选项自带解释与建议),你选完它用 `vibe_math_set_params`
314
+ 应用,最后问你是否 `vibe_math_save_settings` 存为默认。
315
+
316
+ 也可以直接跑命令:`/vibe setup`(看 schema)→ 跟主代理说你要改哪些 → `/vibe save`(存默认)。
317
+
318
+ ### 3. 配置文件(vibe_math_setting.json)
319
+
320
+ - **生成模板**:`/vibe template`(生成到工作区)或 `/vibe template project`(生成到当前项目)——
321
+ 会产出一份**带 `//` 注释、逐项中文说明**的 JSON 模板,你手改后重启/resume 即生效。
322
+ - **保存当前值**:`/vibe save` 把当前生效参数写回该文件。
323
+
324
+ ---
325
+
326
+ ## 🌱 新手示例流程(以“证明 √2 是无理数”为例)
327
+
328
+ **Step 1 — 用一句话启动**
329
+
330
+ ```
331
+ 帮我用 Vibe Math 证明:√2 是无理数。
332
+ ```
333
+
334
+ 主代理执行 `vibe_math_add_problem {"id":"q1","description":"证明:√2 是无理数。","priority":0}`
335
+ 再执行 `vibe_math_start`,然后告诉你“已启动”。
336
+
337
+ **Step 2 — 询问进度**
338
+
339
+ ```
340
+ 进展如何?
341
+ ```
342
+
343
+ 主代理执行 `vibe_math_status` 并用人话汇报:当前活跃子代理数、正在验证的单元、是否有待决策等。
344
+
345
+ **Step 3 — 问答式调参(可选)**
346
+
347
+ ```
348
+ 我想让它用加权投票,并发数设成 6。
349
+ ```
350
+
351
+ 主代理 `vibe_math_set_params {"verdictMode":"weighted-vote","maxParallelThreshold":6}`,
352
+ 并问你是否 `vibe_math_save_settings` 保存。
353
+
354
+ **Step 4 — 中途干预(可选)**
355
+
356
+ ```
357
+ 切到人工模式,我要在每个关键节点把关。
358
+ ```
359
+
360
+ 主代理 `vibe_math_set_mode {"mode":"manual"}`。之后每到一个关键节点它会 `vibe_math_list_decisions`
361
+ 拿到决策,向你说明,等你 `vibe_math_decide {"id":"...","action":"approve"}`(或 `reject` / `override`)。
362
+
363
+ **Step 5 — 收尾**
364
+
365
+ ```
366
+ 结束了吗?结论是什么?
367
+ ```
368
+
369
+ 主代理 `vibe_math_status`:`qs.csv` 里 `q1` 已回写 `solved`,解法文件在 `Verified/` 里并被命名为
370
+ `q1-的解法_<唯一标识>.csv`。
371
+
372
+ > v2 对应的收尾是:`qs.json` 中 `q1.已解决 = true`,其解法 `正确概率 = 1`,相关命题进入 `Verified/`。
373
+
374
+ ---
375
+
376
+ ## 🖼️ 实际使用示例(长截图)
377
+
378
+ > 截图很长,这里默认**折叠**:点击下方「展开」才加载整张长图,避免它占满页面、遮挡前后文字。
379
+
380
+ <details>
381
+ <summary>📸 展开查看实际使用示例长截图</summary>
382
+
383
+ ![实际使用示例长截图](示例图/实际使用示例-长截图.png)
384
+
385
+ </details>
386
+
387
+ ---
388
+
389
+ ## ⚙️ 参数速查表
390
+
391
+ ### v1(经典)默认值
392
+
393
+ | 参数 | 默认 | 说明 |
394
+ |---|---|---|
395
+ | `mode` | `auto` | `auto` / `manual` |
396
+ | `maxParallelThreshold` | 4 | 全局最大并发子代理数 |
397
+ | `solverMaxRounds` | 20 | 每个求解方向最大迭代轮数 |
398
+ | `verifierCount` | 3 | 每验证单元独立验证器数(≥3) |
399
+ | `debateMaxRounds` | 5 | 验证辩论最大轮数 |
400
+ | `verdictMode` | `direct-veto` | `direct-veto` / `weighted-vote` |
401
+ | `provider` / `model` | 空 | 子代理模型(空 = 继承根代理) |
402
+ | `solverPersona` / `verifierPersona` | 空 | 注入求解器/验证器的额外要求 |
403
+ | `solverToolAllow` / `solverToolDeny` | `[]` | 求解器允许/禁止的工具(硬性 toolFilter) |
404
+ | `verifierToolAllow` / `verifierToolDeny` | `[]` | 验证器允许/禁止的工具 |
405
+ | `solverMaxToolCalls` / `verifierMaxToolCalls` | 0 | 每轮外部工具调用上限(0=不限,软性) |
406
+ | `reportIntervalMs` | 0 | 0 = 仅事件驱动(有代理状态更新等事件才写报告);>0 = 定时自动写(毫秒) |
407
+ | `tickIntervalMs` | 2000 | 调度器心跳间隔(毫秒) |
408
+ | `activityLogCap` | 100 | 活动日志保留条数(report 最多显示 30 条) |
409
+
410
+ ### v2(新架构)默认值
411
+
412
+ | 参数 | 默认 | 说明 |
413
+ |---|---|---|
414
+ | `mode` | `auto` | `auto` / `manual` |
415
+ | `maxParallelThreshold` | 4 | 全局最大并发子代理轮数(新派发前须 active < 阈值) |
416
+ | `solverMaxRounds` | 3 | 每个求解方向最大迭代轮数(agent_self_iteration 上限) |
417
+ | `verifierCount` | 3 | 每个验证对象的独立验证器数量 |
418
+ | `debateMaxRounds` | 5 | 验证辩论(交流群)最大轮数 |
419
+ | `verdictMode` | `flat` | `flat` = 均衡机制(不一致判 0.5)/ `forced` = 强制裁决(历史准确率+严谨性加权) |
420
+ | `reportMode` | `file` | `file` = 写报告文件 / `push` = 推送主代理汇报 / `both` |
421
+ | `promoteValueThreshold` | 0.7 | Propos 中「价值/关键性」≥ 该值且未决(0,1) 的命题自动加入 qs.json |
422
+ | `priorityAdjust` | `none` | `none` / `deadend-deprioritize`(全死路降优先级)/ `survival-map`(按存活率重算) |
423
+ | `provider` / `model` | 空 | 子代理模型(空 = 继承根代理) |
424
+ | `solverPersona` / `verifierPersona` | 空 | 注入求解器/验证器的额外要求 |
425
+ | `solverToolAllow` / `solverToolDeny` | `[]` | 求解器允许/禁止的工具 |
426
+ | `verifierToolAllow` / `verifierToolDeny` | `[]` | 验证器允许/禁止的工具 |
427
+ | `solverMaxToolCalls` / `verifierMaxToolCalls` | 0 | 每轮外部工具调用上限(0=不限) |
428
+ | `reportIntervalMs` | 0 | 0 = 仅事件驱动(有状态更新才写/推);>0 = 定时自动汇报(毫秒) |
429
+ | `tickIntervalMs` | 2000 | 调度器心跳间隔(毫秒) |
430
+ | `activityLogCap` | 100 | 活动日志保留条数(report 最多显示 30 条) |
431
+ | `maxExplorerRetries` | 3 | explorer 拆方向失败的重派生上限 |
432
+
433
+ ---
434
+
435
+ ## 📝 断点续跑 & 人工干预(两大硬性需求)
436
+
437
+ - **断点续跑**:所有状态落盘到 `VibeMath_State/*.json`,每个子代理都是 DSH 的 **continuable 持久会话**(对话由 DSH 自动保存)。重启后新开会话 → `vibe_math_resume` 即可续跑。v2 额外用**进程纪元**区分"同进程暂停→恢复"(保留存活子代理继续)与"跨进程重启"(清理陈旧任务)。
438
+ - **中途人工干预**:`manual` 模式在关键节点(v1:brainstorm/solver 派发、验证裁决、晋升 Verified;v2:explorer/solver 派发、验证裁决)挂起决策;可随时 `set_mode auto` 切回自动;可对任意子代理 `message_agent` / `interrupt_agent`。
439
+ - **进度汇报**:默认**事件驱动** —— 只有代理状态更新等事件发生时才会写 `Progress_Logs/report.json`(v2 的 `reportMode` 可 `file`/`push`/`both`,`push` 通过 `rootAgent.followup()` 唤醒主代理主动汇报);只有把 `reportIntervalMs` 设为 >0 才启动定时自动汇报(间隔毫秒)。
440
+
111
441
  ---
112
442
 
113
443
  ## 📚 规格文档
@@ -117,12 +447,18 @@ flowchart TB
117
447
 
118
448
  ---
119
449
 
120
- ## ⚠️ 已知边界
450
+ ## ⚠️ 已知边界(有意简化)
451
+
452
+ **v1**:
453
+ - `Pending_Verification` 按文件逐个拆解,未做跨文件的“去重 / 引用整合”(不损正确性)。
454
+ - `weighted-vote` 会记录每个验证器的历史准确率 + 严谨性权重,但最终裁决仍遵循“证伪优先 / 全 Uncertain→False”(数值权重仅用于审计)。
455
+ - manual 模式在第一个未决关键节点暂停整条主循环。
121
456
 
122
- - 两个预设的 preset 文件互相独立、可共存;同一会话同时只能选一个预设。
123
- - `vibe-math-v1` 的 `Pending_Verification` 按文件逐个拆解,未做跨文件去重。
124
- - `vibe-math-v2` 的 `flat` 裁决在辩论不一致时直接判 `0.5`;`forced` 按历史准确率+置信度加权。
457
+ **v2**:
125
458
  - 安装器只**补装缺失**的 preset 文件,不覆盖你已编辑的预设(删除对应目录即可重新安装)。
459
+ - `flat` 裁决在辩论不一致时直接判 `0.5`;`forced` 按历史准确率+置信度加权。
460
+ - `never` 优先级的问题/命题**永不调度**,且不阻塞严格终止(视为主动弃权)。
461
+ - 两个 preset 文件互相独立、可共存;同一会话同时只能选一个预设。
126
462
 
127
463
  ---
128
464
 
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.1",
4
+ "version": "0.3.3",
5
5
  "type": "module",
6
6
  "main": "installer.js",
7
7
  "exports": {
@@ -1,2 +1,2 @@
1
- name: Vibe Math
1
+ name: Vibe Math V1
2
2
  description: 多代理数学问题求解与验证框架(广度探索 → 深度迭代 → 交叉验证 → 知识沉淀)。具备标准模式的全部能力,并提供 vibe_math_* 工具集(20 个)与 /vibe 斜杠命令,用于数学问题的自动求解、多代理交叉验证、按项目隔离、断点续跑与人工/自动干预。
@@ -69,7 +69,9 @@ export function apply(ctx) {
69
69
  verifierToolDeny: [],
70
70
  solverMaxToolCalls: 0,
71
71
  verifierMaxToolCalls: 0,
72
- reportIntervalMs: 30000,
72
+ reportIntervalMs: 0, // 0 = 仅事件驱动(有代理状态更新等事件才写报告);>0 = 定时自动写(毫秒)
73
+ tickIntervalMs: 2000, // 调度器心跳间隔(毫秒):多久扫描一次状态并推进
74
+ activityLogCap: 100, // 活动日志保留条数(report.recentActivity 最多显示 30 条)
73
75
  }
74
76
  let params = Object.assign({}, DEFAULT_PARAMS)
75
77
  let scheduler = { running: false, activeCount: 0, startedAt: 0, lastCheckpoint: 0, gate: null }
@@ -152,7 +154,9 @@ export function apply(ctx) {
152
154
  { name: 'verifierToolDeny', type: 'string[]', description: '验证器禁止的工具名列表', suggestion: [] },
153
155
  { name: 'solverMaxToolCalls', type: 'integer', description: '求解器每轮外部工具调用上限(0 = 不限)', suggestion: 0 },
154
156
  { name: 'verifierMaxToolCalls', type: 'integer', description: '验证器每轮外部工具调用上限(0 = 不限)', suggestion: 0 },
155
- { name: 'reportIntervalMs', type: 'integer', description: '自动写进度报告 report.json 的最小间隔(毫秒)', suggestion: 30000 },
157
+ { name: 'reportIntervalMs', type: 'integer', description: '进度汇报间隔(毫秒):0 = 仅事件驱动(有代理状态更新等事件才写 report.json);>0 = 定时自动汇报', suggestion: 0 },
158
+ { name: 'tickIntervalMs', type: 'integer', description: '调度器心跳间隔(毫秒):多久扫描一次子代理状态并推进(越小越灵敏、越大越省资源)', suggestion: 2000 },
159
+ { name: 'activityLogCap', type: 'integer', description: '活动日志保留条数(影响 report.recentActivity 的细节量,报告最多显示 30 条)', suggestion: 100 },
156
160
  ]
157
161
 
158
162
  // ================= fs =================
@@ -178,7 +182,7 @@ export function apply(ctx) {
178
182
  // ================= settings file (JSONC) =================
179
183
  function sanitizeParams(obj) {
180
184
  const out = {}
181
- const intFields = ['maxParallelThreshold', 'solverMaxRounds', 'verifierCount', 'debateMaxRounds', 'solverMaxToolCalls', 'verifierMaxToolCalls', 'reportIntervalMs']
185
+ const intFields = ['maxParallelThreshold', 'solverMaxRounds', 'verifierCount', 'debateMaxRounds', 'solverMaxToolCalls', 'verifierMaxToolCalls', 'reportIntervalMs', 'tickIntervalMs', 'activityLogCap']
182
186
  const arrayFields = ['solverToolAllow', 'solverToolDeny', 'verifierToolAllow', 'verifierToolDeny']
183
187
  for (const k of Object.keys(DEFAULT_PARAMS)) {
184
188
  if (!(k in obj)) continue
@@ -231,7 +235,7 @@ export function apply(ctx) {
231
235
  async function saveAll() { await writeJson('VibeMath_State/params.json', params); await writeJson('VibeMath_State/scheduler_state.json', scheduler); await writeJson('VibeMath_State/agent_registry.json', agentRegistry); await writeJson('VibeMath_State/dependencies.json', dependencies); await writeJson('VibeMath_State/decision_queue.json', decisionQueue); await writeJson('VibeMath_State/tasks.json', tasks); await writeJson('VibeMath_State/solved_by_verified.json', solvedByVerified); await writeJson('VibeMath_State/promotion_queue.json', promotionQueue); await writeJson('VibeMath_State/verifier_accuracy.json', verifierAccuracy); scheduler.lastCheckpoint = now() }
232
236
 
233
237
  // ================= activity log / report =================
234
- function logActivity(event, detail) { activityLog.push({ at: now(), event: event, detail: String(detail || '') }); if (activityLog.length > 100) activityLog.shift(); reportDirty = true }
238
+ function logActivity(event, detail) { activityLog.push({ at: now(), event: event, detail: String(detail || '') }); const cap = Number(params.activityLogCap) || 100; if (activityLog.length > cap) activityLog.shift(); reportDirty = true }
235
239
  function buildReport() {
236
240
  const openTasks = Object.keys(tasks).filter(function (k) { const t = tasks[k]; return t.status === 'spawning' || t.status === 'debating' || t.status === 'awaiting-verdict' })
237
241
  return {
@@ -246,13 +250,14 @@ export function apply(ctx) {
246
250
  pendingDecisions: decisionQueue.filter(function (d) { return d.status === 'pending' }).map(function (d) { return { id: d.id, node: d.node, context: d.context } }),
247
251
  openTasks: openTasks.length,
248
252
  registeredAgents: Object.keys(agentRegistry).length,
249
- recentActivity: activityLog.slice(-30),
253
+ recentActivity: activityLog.slice(-Math.min(30, Number(params.activityLogCap) || 100)),
250
254
  params: params,
251
255
  }
252
256
  }
253
257
  async function maybeWriteReport(force) {
254
- if (!force && !reportDirty) return
255
- if (!force && (now() - lastReportWrite) < (Number(params.reportIntervalMs) || 30000)) return
258
+ const interval = Number(params.reportIntervalMs) || 0
259
+ if (!force && interval > 0 && (now() - lastReportWrite) < interval) return
260
+ if (!force && interval <= 0 && !reportDirty) return
256
261
  await writeJson('Progress_Logs/report.json', buildReport())
257
262
  lastReportWrite = now()
258
263
  reportDirty = false
@@ -458,7 +463,7 @@ export function apply(ctx) {
458
463
 
459
464
  // ================= events / timer =================
460
465
  ctx.on('subagent/end', function (info) { onChildEnd(info).catch(function (e) { console.error('vibe-math onChildEnd reject: ' + String((e && e.stack) || e)) }) })
461
- ctx.effect(() => { const t = setInterval(function () { scheduleTick() }, 2000); return () => clearInterval(t) })
466
+ ctx.effect(() => { const t = setInterval(function () { scheduleTick() }, Math.max(200, Number(params.tickIntervalMs) || 2000)); return () => clearInterval(t) })
462
467
 
463
468
  // ================= tools =================
464
469
  function objParams(props, required) { return { type: 'object', properties: props, additionalProperties: false, required: required || [] } }
@@ -477,7 +482,7 @@ export function apply(ctx) {
477
482
  registerTool('vibe_math_status', 'Show scheduler status, params, active agents, projects, and recent activity.', objParams({}), async function () { return await getStatus() })
478
483
  registerTool('vibe_math_report', 'Return the full progress report (status + recent activity + params) and write it to Progress_Logs/report.json.', objParams({}), async function () { await maybeWriteReport(true); return buildReport() })
479
484
  registerTool('vibe_math_set_mode', 'Switch between manual and auto (preset) mode.', objParams({ mode: { type: 'string', enum: ['manual', 'auto'] } }, ['mode']), async function (args) { params.mode = args.mode; await saveAll(); return { ok: true, mode: params.mode } })
480
- registerTool('vibe_math_set_params', 'Update scheduler parameters (partial).', objParams({ maxParallelThreshold: { type: 'integer' }, solverMaxRounds: { type: 'integer' }, verifierCount: { type: 'integer' }, debateMaxRounds: { type: 'integer' }, verdictMode: { type: 'string', enum: ['direct-veto', 'weighted-vote'] }, provider: { type: 'string' }, model: { type: 'string' }, solverPersona: { type: 'string' }, verifierPersona: { type: 'string' }, solverToolAllow: { type: 'array', items: { type: 'string' } }, solverToolDeny: { type: 'array', items: { type: 'string' } }, verifierToolAllow: { type: 'array', items: { type: 'string' } }, verifierToolDeny: { type: 'array', items: { type: 'string' } }, solverMaxToolCalls: { type: 'integer' }, verifierMaxToolCalls: { type: 'integer' }, reportIntervalMs: { type: 'integer' } }), async function (args) { params = Object.assign({}, params, args); await saveAll(); return { ok: true, params: params } })
485
+ registerTool('vibe_math_set_params', 'Update scheduler parameters (partial).', objParams({ maxParallelThreshold: { type: 'integer' }, solverMaxRounds: { type: 'integer' }, verifierCount: { type: 'integer' }, debateMaxRounds: { type: 'integer' }, verdictMode: { type: 'string', enum: ['direct-veto', 'weighted-vote'] }, provider: { type: 'string' }, model: { type: 'string' }, solverPersona: { type: 'string' }, verifierPersona: { type: 'string' }, solverToolAllow: { type: 'array', items: { type: 'string' } }, solverToolDeny: { type: 'array', items: { type: 'string' } }, verifierToolAllow: { type: 'array', items: { type: 'string' } }, verifierToolDeny: { type: 'array', items: { type: 'string' } }, solverMaxToolCalls: { type: 'integer' }, verifierMaxToolCalls: { type: 'integer' }, reportIntervalMs: { type: 'integer' }, tickIntervalMs: { type: 'integer' }, activityLogCap: { type: 'integer' } }), async function (args) { params = Object.assign({}, params, args); await saveAll(); return { ok: true, params: params } })
481
486
  registerTool('vibe_math_setup', 'Return the interactive parameter schema (each param: name, type, current, default, description, options, suggestion) for guided configuration.', objParams({}), async function () { const list = PARAM_SCHEMA.map(function (p) { const out = Object.assign({}, p); out.current = params[p.name]; out.default = DEFAULT_PARAMS[p.name]; return out }); return { ok: true, parameters: list, saveTo: frameworkRoot() + '/vibe_math_setting.json' } })
482
487
  registerTool('vibe_math_save_settings', 'Write the current params to vibe_math_setting.json (JSON with comments) as new defaults.', objParams({}), async function () { return await saveSettings() })
483
488
  registerTool('vibe_math_template', 'Create a fresh vibe_math_setting.json template (with defaults + comments) in the workspace (global) or current project folder.', objParams({ where: { type: 'string', enum: ['global', 'project'] } }), async function (args) { return await createTemplate((args && args.where) || 'global') })
@@ -47,10 +47,13 @@ export function apply(ctx) {
47
47
  verifierToolDeny: [],
48
48
  solverMaxToolCalls: 0,
49
49
  verifierMaxToolCalls: 0,
50
- reportIntervalMs: 30000,
50
+ reportIntervalMs: 0, // 0 = 仅事件驱动(有代理状态更新等事件才写/推报告);>0 = 定时自动汇报(毫秒)
51
51
  reportMode: 'file', // file | push | both
52
52
  promoteValueThreshold: 0.7, // Propos → qs auto-promotion threshold (价值/关键性)
53
53
  priorityAdjust: 'none', // none | deadend-deprioritize | survival-map
54
+ tickIntervalMs: 2000, // 调度器心跳间隔(毫秒)
55
+ activityLogCap: 100, // 活动日志保留条数(report.recentActivity 最多显示 30 条)
56
+ maxExplorerRetries: 3, // explorer 重派生上限(拆方向失败重试次数)
54
57
  }
55
58
  let params = Object.assign({}, DEFAULT_PARAMS)
56
59
  let scheduler = { running: false, activeCount: 0, startedAt: 0, lastCheckpoint: 0, gate: null }
@@ -128,10 +131,13 @@ export function apply(ctx) {
128
131
  { name: 'verifierToolDeny', type: 'string[]', description: '验证器禁止的工具名列表', suggestion: [] },
129
132
  { name: 'solverMaxToolCalls', type: 'integer', description: '求解器每轮外部工具调用上限(0 = 不限)', suggestion: 0 },
130
133
  { name: 'verifierMaxToolCalls', type: 'integer', description: '验证器每轮外部工具调用上限(0 = 不限)', suggestion: 0 },
131
- { name: 'reportIntervalMs', type: 'integer', description: '进度汇报最小间隔(毫秒)', suggestion: 30000 },
134
+ { name: 'reportIntervalMs', type: 'integer', description: '进度汇报间隔(毫秒):0 = 仅事件驱动(有代理状态更新等事件才写/推报告);>0 = 同时按该间隔定时自动汇报', suggestion: 0 },
132
135
  { name: 'reportMode', type: 'enum', options: ['file', 'push', 'both'], description: 'file = 写报告文件;push = 推送消息让主代理主动汇报;both = 两者都做', suggestion: 'file' },
133
136
  { name: 'promoteValueThreshold', type: 'number', description: 'Propos 中「价值/关键性」≥ 该值且未决(0,1) 的命题自动加入 qs.json', suggestion: 0.7 },
134
137
  { name: 'priorityAdjust', type: 'enum', options: ['none', 'deadend-deprioritize', 'survival-map'], description: '优先级动态调整策略:none=不自动调;deadend-deprioritize=方向全死路时降优先级;survival-map=按最高方向存活率重算(存活率高越优先)', suggestion: 'none' },
138
+ { name: 'tickIntervalMs', type: 'integer', description: '调度器心跳间隔(毫秒):多久扫描一次子代理状态并推进(越小越灵敏、越大越省资源)', suggestion: 2000 },
139
+ { name: 'activityLogCap', type: 'integer', description: '活动日志保留条数(影响 report.recentActivity 的细节量,报告最多显示 30 条)', suggestion: 100 },
140
+ { name: 'maxExplorerRetries', type: 'integer', description: 'explorer 拆方向失败的重派生上限(达到后该问题标记为方向耗尽)', suggestion: 3 },
135
141
  ]
136
142
 
137
143
  // ================= fs =================
@@ -156,7 +162,7 @@ export function apply(ctx) {
156
162
  // ================= settings =================
157
163
  function sanitizeParams(obj) {
158
164
  const out = {}
159
- const intFields = ['maxParallelThreshold', 'solverMaxRounds', 'verifierCount', 'debateMaxRounds', 'solverMaxToolCalls', 'verifierMaxToolCalls', 'reportIntervalMs']
165
+ const intFields = ['maxParallelThreshold', 'solverMaxRounds', 'verifierCount', 'debateMaxRounds', 'solverMaxToolCalls', 'verifierMaxToolCalls', 'reportIntervalMs', 'tickIntervalMs', 'activityLogCap', 'maxExplorerRetries']
160
166
  const numFields = ['promoteValueThreshold']
161
167
  const arrayFields = ['solverToolAllow', 'solverToolDeny', 'verifierToolAllow', 'verifierToolDeny']
162
168
  for (const k of Object.keys(DEFAULT_PARAMS)) {
@@ -275,7 +281,7 @@ export function apply(ctx) {
275
281
  async function reliableFiles() { return await listFiles('Reliable') }
276
282
 
277
283
  // ================= reporting =================
278
- function logActivity(event, detail) { activityLog.push({ at: now(), event: event, detail: String(detail || '') }); if (activityLog.length > 100) activityLog.shift(); reportDirty = true }
284
+ function logActivity(event, detail) { activityLog.push({ at: now(), event: event, detail: String(detail || '') }); const cap = Number(params.activityLogCap) || 100; if (activityLog.length > cap) activityLog.shift(); reportDirty = true }
279
285
  async function buildReport() {
280
286
  const qs = await getQs()
281
287
  const propos = await getPropos()
@@ -287,21 +293,28 @@ export function apply(ctx) {
287
293
  propositions: { total: propos.length, resolved: propos.filter(function (p) { return p.布尔估计 === 1 || p.布尔估计 === 0 }).length },
288
294
  pendingDecisions: decisionQueue.filter(function (d) { return d.status === 'pending' }).map(function (d) { return { id: d.id, node: d.node, context: d.context } }),
289
295
  registeredAgents: Object.keys(agentRegistry).length,
290
- recentActivity: activityLog.slice(-30),
296
+ recentActivity: activityLog.slice(-Math.min(30, Number(params.activityLogCap) || 100)),
291
297
  params: params,
292
298
  }
293
299
  }
294
300
  async function maybeWriteReport(force) {
295
- if (!force && !reportDirty) return
296
- if (!force && (now() - lastReportWrite) < (Number(params.reportIntervalMs) || 30000)) return
301
+ const interval = Number(params.reportIntervalMs) || 0
302
+ if (!force && interval > 0 && (now() - lastReportWrite) < interval) return
303
+ if (!force && interval <= 0 && !reportDirty) return
297
304
  await writeJson('Progress_Logs/report.json', await buildReport())
298
305
  lastReportWrite = now(); reportDirty = false
299
306
  }
300
307
  async function maybePushReport(force) {
301
308
  const mode = params.reportMode || 'file'
302
309
  if (mode !== 'push' && mode !== 'both') return
303
- // heartbeat: push on interval (or force), independent of reportDirty so 'both' mode works
304
- if (!force && (now() - lastPushReport) < (Number(params.reportIntervalMs) || 30000)) return
310
+ const interval = Number(params.reportIntervalMs) || 0
311
+ if (interval > 0) {
312
+ // heartbeat: push on interval (or force), independent of reportDirty so 'both' mode works
313
+ if (!force && (now() - lastPushReport) < interval) return
314
+ } else if (!force && !reportDirty) {
315
+ // event-driven: only push when an event happened since the last report
316
+ return
317
+ }
305
318
  if (!rootAgent || typeof rootAgent.followup !== 'function') return
306
319
  try {
307
320
  const report = await buildReport()
@@ -310,7 +323,7 @@ export function apply(ctx) {
310
323
  '活跃代理轮数=' + report.activeCount + ',待人工决策=' + report.pendingDecisions.length + '。' +
311
324
  '请调用 vibe_math_report 汇总当前进展及各代理状态,并用人话简要汇报(不打断用户,简短即可)。'
312
325
  rootAgent.followup({ id: uuid(), role: 'user', content: [textBlock(text)], source: { kind: 'plugin', plugin: 'vibe-math-v2' } })
313
- lastPushReport = now(); reportDirty = false
326
+ lastPushReport = now()
314
327
  } catch (e) {
315
328
  console.error('vibe-math-v2: push report failed: ' + String((e && e.message) || e))
316
329
  }
@@ -455,8 +468,8 @@ export function apply(ctx) {
455
468
  await processVerify()
456
469
  await reconcileVerify()
457
470
  await processSolve()
458
- await maybeWriteReport(false)
459
471
  await maybePushReport(false)
472
+ await maybeWriteReport(false)
460
473
  const qs = await getQs()
461
474
  const unsolved = qs.filter(function (q) { return !q.已解决 && q.优先级 !== 'never' })
462
475
  if (unsolved.length === 0 && Object.keys(agentRegistry).length === 0 && Object.keys(tasks).length === 0) {
@@ -469,7 +482,7 @@ export function apply(ctx) {
469
482
  const prog = parseProgress(unsolved[i])
470
483
  const exhaustedAll = prog.directions.length > 0 && prog.directions.every(function (d) { return d.status === 'dead-end' || d.status === 'success' })
471
484
  const hasActive = prog.directions.some(function (d) { return d.status === 'active' })
472
- const blocked = (prog.directions.length === 0 || exhaustedAll) && (explorerRetries[unsolved[i].id] || 0) >= 3
485
+ const blocked = (prog.directions.length === 0 || exhaustedAll) && (explorerRetries[unsolved[i].id] || 0) >= (Number(params.maxExplorerRetries) || 3)
473
486
  if (hasActive || !blocked) { allBlocked = false; break }
474
487
  }
475
488
  if (allBlocked) {
@@ -623,10 +636,11 @@ export function apply(ctx) {
623
636
  const prog = parseProgress(q)
624
637
  const allExhausted = prog.directions.length > 0 && prog.directions.every(function (d) { return d.status === 'dead-end' || d.status === 'success' })
625
638
  if (prog.directions.length === 0 || allExhausted) {
626
- if ((explorerRetries[q.id] || 0) >= 3) {
627
- if (prog.directions.length === 0) prog.directions.push({ id: 'd_' + shortId(), title: 'explorer 失败', method: '', core_assumption: '', feasibility: 0, status: 'dead-end', round: 0, survival: 0, routes: [], blockers: [], dead_end_reason: 'explorer 连续 3 次未产出方向' })
639
+ const explorerCap = Number(params.maxExplorerRetries) || 3
640
+ if ((explorerRetries[q.id] || 0) >= explorerCap) {
641
+ if (prog.directions.length === 0) prog.directions.push({ id: 'd_' + shortId(), title: 'explorer 失败', method: '', core_assumption: '', feasibility: 0, status: 'dead-end', round: 0, survival: 0, routes: [], blockers: [], dead_end_reason: 'explorer 连续 ' + explorerCap + ' 次未产出方向' })
628
642
  await saveProgress(q.id, prog)
629
- logActivity('explorer', 'problem ' + q.id + ' explorer exhausted (3 failed attempts)')
643
+ logActivity('explorer', 'problem ' + q.id + ' explorer exhausted (' + explorerCap + ' failed attempts)')
630
644
  continue
631
645
  }
632
646
  explorerRetries[q.id] = (explorerRetries[q.id] || 0) + 1
@@ -995,7 +1009,7 @@ export function apply(ctx) {
995
1009
 
996
1010
  // ================= events / timer =================
997
1011
  ctx.on('subagent/end', function (info) { onChildEnd(info).catch(function (e) { console.error('vibe-math-v2 onChildEnd reject: ' + String((e && e.stack) || e)) }) })
998
- ctx.effect(() => { const t = setInterval(function () { scheduleTick() }, 2000); return () => clearInterval(t) })
1012
+ ctx.effect(() => { const t = setInterval(function () { scheduleTick() }, Math.max(200, Number(params.tickIntervalMs) || 2000)); return () => clearInterval(t) })
999
1013
 
1000
1014
  // ================= tools =================
1001
1015
  function objParams(props, required) { return { type: 'object', properties: props, additionalProperties: false, required: required || [] } }
@@ -1013,7 +1027,7 @@ export function apply(ctx) {
1013
1027
  registerTool('vibe_math_status', 'Show scheduler status, params, active agents, projects, and recent activity.', objParams({}), async function () { return await getStatus() })
1014
1028
  registerTool('vibe_math_report', 'Return the full progress report and write it to Progress_Logs/report.json.', objParams({}), async function () { await maybeWriteReport(true); return await buildReport() })
1015
1029
  registerTool('vibe_math_set_mode', 'Switch between manual and auto (preset) mode.', objParams({ mode: { type: 'string', enum: ['manual', 'auto'] } }, ['mode']), async function (args) { params.mode = args.mode; await saveAll(); return { ok: true, mode: params.mode } })
1016
- registerTool('vibe_math_set_params', 'Update scheduler parameters (partial).', objParams({ maxParallelThreshold: { type: 'integer' }, solverMaxRounds: { type: 'integer' }, verifierCount: { type: 'integer' }, debateMaxRounds: { type: 'integer' }, verdictMode: { type: 'string', enum: ['flat', 'forced'] }, reportMode: { type: 'string', enum: ['file', 'push', 'both'] }, promoteValueThreshold: { type: 'number' }, priorityAdjust: { type: 'string', enum: ['none', 'deadend-deprioritize', 'survival-map'] }, provider: { type: 'string' }, model: { type: 'string' }, solverPersona: { type: 'string' }, verifierPersona: { type: 'string' }, solverToolAllow: { type: 'array', items: { type: 'string' } }, solverToolDeny: { type: 'array', items: { type: 'string' } }, verifierToolAllow: { type: 'array', items: { type: 'string' } }, verifierToolDeny: { type: 'array', items: { type: 'string' } }, solverMaxToolCalls: { type: 'integer' }, verifierMaxToolCalls: { type: 'integer' }, reportIntervalMs: { type: 'integer' } }), async function (args) { params = Object.assign({}, params, sanitizeParams(args)); await saveAll(); return { ok: true, params: params } })
1030
+ registerTool('vibe_math_set_params', 'Update scheduler parameters (partial).', objParams({ maxParallelThreshold: { type: 'integer' }, solverMaxRounds: { type: 'integer' }, verifierCount: { type: 'integer' }, debateMaxRounds: { type: 'integer' }, verdictMode: { type: 'string', enum: ['flat', 'forced'] }, reportMode: { type: 'string', enum: ['file', 'push', 'both'] }, promoteValueThreshold: { type: 'number' }, priorityAdjust: { type: 'string', enum: ['none', 'deadend-deprioritize', 'survival-map'] }, provider: { type: 'string' }, model: { type: 'string' }, solverPersona: { type: 'string' }, verifierPersona: { type: 'string' }, solverToolAllow: { type: 'array', items: { type: 'string' } }, solverToolDeny: { type: 'array', items: { type: 'string' } }, verifierToolAllow: { type: 'array', items: { type: 'string' } }, verifierToolDeny: { type: 'array', items: { type: 'string' } }, solverMaxToolCalls: { type: 'integer' }, verifierMaxToolCalls: { type: 'integer' }, reportIntervalMs: { type: 'integer' }, tickIntervalMs: { type: 'integer' }, activityLogCap: { type: 'integer' }, maxExplorerRetries: { type: 'integer' } }), async function (args) { params = Object.assign({}, params, sanitizeParams(args)); await saveAll(); return { ok: true, params: params } })
1017
1031
  registerTool('vibe_math_setup', 'Return the interactive parameter schema for guided configuration.', objParams({}), async function () { const list = PARAM_SCHEMA.map(function (p) { const out = Object.assign({}, p); out.current = params[p.name]; out.default = DEFAULT_PARAMS[p.name]; return out }); return { ok: true, parameters: list, saveTo: frameworkRoot() + '/vibe_math_setting.json' } })
1018
1032
  registerTool('vibe_math_save_settings', 'Write the current params to vibe_math_setting.json (JSON with comments) as new defaults.', objParams({}), async function () { return await saveSettings() })
1019
1033
  registerTool('vibe_math_template', 'Create a fresh vibe_math_setting.json template (with defaults + comments) in the workspace (global) or current project folder.', objParams({ where: { type: 'string', enum: ['global', 'project'] } }), async function (args) { return await createTemplate((args && args.where) || 'global') })
@@ -1045,6 +1059,8 @@ export function apply(ctx) {
1045
1059
  if (cmd === 'save') return await saveSettings()
1046
1060
  if (cmd === 'template') return await createTemplate(args[0] === 'project' ? 'project' : 'global')
1047
1061
  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' } }
1062
+ 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)) } }
1063
+ 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 } }) } }
1048
1064
  if (cmd === 'project') {
1049
1065
  if (args.length === 0 || args[0] === 'list') return { ok: true, current: currentProject, projects: await listDirsAt(vibeRoot(), 'Projects') }
1050
1066
  if (args[0] === 'new') return await setProject(slugify(args.slice(1).join(' ')), true)
@@ -1052,12 +1068,12 @@ export function apply(ctx) {
1052
1068
  }
1053
1069
  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 } }) }
1054
1070
  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 } }
1055
- 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)') }
1071
+ 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)') }
1056
1072
  }
1057
1073
  ctx.effect(() => commands.register({
1058
1074
  name: 'vibe',
1059
- description: 'control the Vibe Math V2 solver (start/pause/projects/setup/save/decisions/agents)',
1060
- 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]' },
1075
+ description: 'control the Vibe Math V2 solver (start/pause/projects/setup/save/decisions/agents/propositions)',
1076
+ 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]' },
1061
1077
  handler: async function (invocation) {
1062
1078
  const line = String(invocation && invocation.rawInput ? invocation.rawInput : '').trim()
1063
1079
  const parts = line.length > 0 ? line.split(/\s+/) : []