dsh-vibe-math 0.3.3 → 0.3.4

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
@@ -420,6 +420,7 @@ flowchart TB
420
420
  | `reportMode` | `file` | `file` = 写报告文件 / `push` = 推送主代理汇报 / `both` |
421
421
  | `promoteValueThreshold` | 0.7 | Propos 中「价值/关键性」≥ 该值且未决(0,1) 的命题自动加入 qs.json |
422
422
  | `priorityAdjust` | `none` | `none` / `deadend-deprioritize`(全死路降优先级)/ `survival-map`(按存活率重算) |
423
+ | `proposPriorityAdjust` | `none` | 命题优先级动态调整:`none` / `progress-graded`(按定论接近度+证明/证伪材料量重算,越接近定论越优先验证) |
423
424
  | `provider` / `model` | 空 | 子代理模型(空 = 继承根代理) |
424
425
  | `solverPersona` / `verifierPersona` | 空 | 注入求解器/验证器的额外要求 |
425
426
  | `solverToolAllow` / `solverToolDeny` | `[]` | 求解器允许/禁止的工具 |
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.3",
4
+ "version": "0.3.4",
5
5
  "type": "module",
6
6
  "main": "installer.js",
7
7
  "exports": {
@@ -312,6 +312,19 @@ export function apply(ctx) {
312
312
  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() } }
313
313
  async function pauseScheduler() { scheduler.running = false; logActivity('pause', 'scheduler paused'); await saveAll(); return { ok: true, message: 'scheduler paused' } }
314
314
  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 } }
315
+ // auto 模式语义 = 无人值守自动通过关键节点:切回 auto 时把仍挂起的人工决策按自动策略放行
316
+ async function autoResolvePending() {
317
+ const pending = decisionQueue.filter(function (d) { return d.status === 'pending' })
318
+ for (let i = 0; i < pending.length; i++) {
319
+ const d = pending[i]
320
+ try {
321
+ if (d.node === 'spawn') { await spawnChild(d.data.label, d.data.promptText, d.data.meta); d.status = 'resolved'; d.resolution = { action: 'approve', auto: true } }
322
+ else if (d.node === 'verdict') { await settleVerdict(d.data.task, d.data.verdict); delete tasks[d.data.task.id]; d.status = 'resolved'; d.resolution = { action: 'approve', auto: true } }
323
+ else if (d.node === 'promote') { await promoteUnit(d.data.objId); d.status = 'resolved'; d.resolution = { action: 'approve', auto: true } }
324
+ } catch (e) { console.error('vibe-math: auto-resolve decision failed: ' + String((e && e.message) || e)) }
325
+ }
326
+ if (pending.length > 0) { scheduler.gate = null; logActivity('mode', 'switched to auto — auto-resolved ' + pending.length + ' pending decision(s)'); await saveAll(); scheduleTick() }
327
+ }
315
328
  async function getStatus() { return { ok: true, initialized: rootAgent !== undefined, running: scheduler.running, project: currentProject, projects: await listDirsAt(vibeRoot(), 'Projects'), mode: params.mode, activeCount: scheduler.activeCount, maxParallelThreshold: params.maxParallelThreshold, frameworkRoot: frameworkRoot(), pendingDecisions: decisionQueue.filter(function (d) { return d.status === 'pending' }).length, openTasks: Object.keys(tasks).filter(function (k) { return tasks[k].status === 'spawning' || tasks[k].status === 'debating' || tasks[k].status === 'awaiting-verdict' }).length, registeredAgents: Object.keys(agentRegistry).length, recentActivity: activityLog.slice(-10), params: params } }
316
329
 
317
330
  // ================= projects =================
@@ -344,7 +357,7 @@ export function apply(ctx) {
344
357
  async function onChildEnd(info) { const meta = agentRegistry[info.id]; if (meta === undefined) return; scheduler.activeCount = Math.max(0, scheduler.activeCount - 1); const output = blocksToText(info.lastAssistantMessage); try { if (meta.role === 'brainstorm') await handleBrainstorm(info.id, meta, output); else if (meta.role === 'solver') await handleSolver(info.id, meta, output, info.stopReason); else if (meta.role === 'verifier') await handleVerifier(info.id, meta, output, info.stopReason); else if (meta.role === 'decider') await handleDecider(info.id, meta, output); else if (meta.role === 'derive') await handleDerive(info.id, meta, output) } catch (e) { console.error('vibe-math onChildEnd error: ' + String((e && e.stack) || e)) } await saveAll(); scheduleTick() }
345
358
  async function handleBrainstorm(childId, meta, output) { delete agentRegistry[childId]; const parsed = parseJson(output); const dirs = (parsed && parsed.directions) || []; if (dirs.length === 0) { logActivity('brainstorm', 'problem ' + meta.qid + ' brainstorm returned no directions'); await saveAll(); return } brainstormRetries[meta.qid] = 0; const prog = []; for (let i = 0; i < dirs.length; i++) { const d = dirs[i]; prog.push({ direction_id: 'd_' + shortId(), title: d.title || '', method: d.method || '', core_assumption: d.core_assumption || '', round: 0, status: 'active', survival_probability: (typeof d.feasibility === 'number') ? d.feasibility : 0.5, dead_end_reason: '', lemmas: [], sub_routes: [], aux_hypotheses: [], updated_at: String(now()) }) } logActivity('brainstorm', 'problem ' + meta.qid + ' → ' + prog.length + ' directions'); await writeProgress(meta.qid, prog) }
346
359
  async function handleDerive(childId, meta, output) { delete agentRegistry[childId]; const parsed = parseJson(output); const dirs = (parsed && parsed.directions) || []; if (dirs.length === 0) { logActivity('derive', 'problem ' + meta.qid + ' derived no new directions'); await saveAll(); return } const prog = await readProgress(meta.qid); for (let i = 0; i < dirs.length; i++) { const d = dirs[i]; prog.push({ direction_id: 'd_' + shortId(), title: d.title || '', method: d.method || '', core_assumption: d.core_assumption || (d.motivation || ''), round: 0, status: 'active', survival_probability: (typeof d.feasibility === 'number') ? d.feasibility : 0.5, dead_end_reason: '', lemmas: [], sub_routes: [], aux_hypotheses: [], updated_at: String(now()) }) } logActivity('derive', 'problem ' + meta.qid + ' derived ' + dirs.length + ' new directions'); await writeProgress(meta.qid, prog) }
347
- async function handleSolver(childId, meta, output, stopReason) { const qid = meta.qid; const direction = meta.direction; const parsed = parseJson(output); const prog = await readProgress(qid); const dir = prog.find(function (d) { return d.direction_id === direction }); if (!dir) { delete agentRegistry[childId]; return } const status = (parsed && parsed.status) || statusFromStop(stopReason); dir.round = meta.round; dir.status = status; if (parsed) { if (parsed.lemmas) dir.lemmas = parsed.lemmas; if (parsed.sub_routes) dir.sub_routes = parsed.sub_routes; if (parsed.aux_hypotheses) dir.aux_hypotheses = parsed.aux_hypotheses; if (typeof parsed.survival_probability === 'number') dir.survival_probability = parsed.survival_probability; if (parsed.dead_end_reason) dir.dead_end_reason = parsed.dead_end_reason } if (status === 'success') { dir.status = 'success'; delete agentRegistry[childId]; logActivity('solver', qid + '/' + direction + ' success at round ' + meta.round); await writePending(qid, dir, parsed) } else if (status === 'dead-end' || meta.round >= params.solverMaxRounds) { dir.status = 'dead-end'; if (!dir.dead_end_reason) dir.dead_end_reason = (status === 'dead-end' && !parsed) ? 'solver ended abnormally (' + stopReason + ')' : 'iteration cap reached'; delete agentRegistry[childId]; logActivity('solver', qid + '/' + direction + ' dead-end: ' + dir.dead_end_reason) } else { const q = { id: qid, description: meta.description || '' }; await followupChild(childId, solverPrompt(q, dir, meta.round + 1)); agentRegistry[childId].round = meta.round + 1; dir.round = meta.round + 1 } if (parsed && parsed.aux_hypotheses && parsed.aux_hypotheses.length > 0) await handleAuxHypotheses(qid, parsed.aux_hypotheses); dir.updated_at = String(now()); await writeProgress(qid, prog) }
360
+ async function handleSolver(childId, meta, output, stopReason) { const qid = meta.qid; const direction = meta.direction; const parsed = parseJson(output); const prog = await readProgress(qid); const dir = prog.find(function (d) { return d.direction_id === direction }); if (!dir) { delete agentRegistry[childId]; return } if (!parsed && !scheduler.running) { delete agentRegistry[childId]; return } const status = (parsed && parsed.status) || statusFromStop(stopReason); dir.round = meta.round; dir.status = status; if (parsed) { if (parsed.lemmas) dir.lemmas = parsed.lemmas; if (parsed.sub_routes) dir.sub_routes = parsed.sub_routes; if (parsed.aux_hypotheses) dir.aux_hypotheses = parsed.aux_hypotheses; if (typeof parsed.survival_probability === 'number') dir.survival_probability = parsed.survival_probability; if (parsed.dead_end_reason) dir.dead_end_reason = parsed.dead_end_reason } if (status === 'success') { dir.status = 'success'; delete agentRegistry[childId]; logActivity('solver', qid + '/' + direction + ' success at round ' + meta.round); await writePending(qid, dir, parsed) } else if (status === 'dead-end' || meta.round >= params.solverMaxRounds) { dir.status = 'dead-end'; if (!dir.dead_end_reason) dir.dead_end_reason = (status === 'dead-end' && !parsed) ? 'solver ended abnormally (' + stopReason + ')' : 'iteration cap reached'; delete agentRegistry[childId]; logActivity('solver', qid + '/' + direction + ' dead-end: ' + dir.dead_end_reason) } else { const q = { id: qid, description: meta.description || '' }; await followupChild(childId, solverPrompt(q, dir, meta.round + 1)); agentRegistry[childId].round = meta.round + 1; dir.round = meta.round + 1 } if (parsed && parsed.aux_hypotheses && parsed.aux_hypotheses.length > 0) await handleAuxHypotheses(qid, parsed.aux_hypotheses); dir.updated_at = String(now()); await writeProgress(qid, prog) }
348
361
  async function handleAuxHypotheses(qid, hyps) { const qs = await getQs(); for (let i = 0; i < hyps.length; i++) { const h = hyps[i]; if (!h || !h.title) continue; const subId = qid + '_sub_' + shortId(); qs.push({ id: subId, description: h.title + (h.statement ? ' - ' + h.statement : ''), priority: 1, status: 'unsolved', deps: [] }); dependencies[qid] = dependencies[qid] || []; dependencies[qid].push(subId); await writeQs(qs); logActivity('subquestion', qid + ' spawned sub-question ' + subId + ' (Aux_Hypothesis)') } }
349
362
  async function writePending(qid, dir, parsed) { const doc = { qid: qid, direction: dir.direction_id, solution: solutionText(parsed, dir), lemmas: (parsed && parsed.lemmas) || [], findings: (parsed && parsed.findings) || [], sub_routes: (parsed && parsed.sub_routes) || [], aux_hypotheses: (parsed && parsed.aux_hypotheses) || [], survival_probability: dir.survival_probability, created_at: String(now()) }; const id = uuid(); await writeText('Pending_Verification/' + id + '.csv', 'qid,direction,content_json,created_at\n' + csvRow([qid, dir.direction_id, JSON.stringify(doc), String(now())]) + '\n') }
350
363
 
@@ -405,6 +418,14 @@ export function apply(ctx) {
405
418
  const verdict = (parsed && parsed.verdict) || 'uncertain'
406
419
  let t = tasks['verify:' + unitId]
407
420
  if (!t) { t = { id: 'verify:' + unitId, type: 'verify', unitId: unitId, unit: meta.unit || { obj_id: unitId, title: unitId, content: '' }, status: 'debating', children: [], childResults: {}, round: 1, expectedCount: Math.max(3, params.verifierCount), createdAt: now() }; tasks[t.id] = t }
421
+ if (!parsed && !scheduler.running) {
422
+ // abort:被中断的验证器没有产出,丢弃该子代理并清理任务簿记(任务在 resume 时由 processVerification 重建)
423
+ delete agentRegistry[childId]
424
+ const ix = t.children.indexOf(childId); if (ix !== -1) t.children.splice(ix, 1)
425
+ delete t.childResults[childId]
426
+ if (t.children.length === 0 && t.id && tasks[t.id]) delete tasks[t.id]
427
+ return
428
+ }
408
429
  if (t.children.indexOf(childId) === -1) t.children.push(childId)
409
430
  t.childResults[childId] = { verdict: verdict, reason: (parsed && parsed.reason) || '', strictness: (parsed && parsed.strictness) || 'lenient', round: meta.round }
410
431
  delete agentRegistry[childId]
@@ -481,7 +502,7 @@ export function apply(ctx) {
481
502
  registerTool('vibe_math_abort', 'Abort the scheduler and interrupt all active children.', objParams({}), async function () { return await abortScheduler() })
482
503
  registerTool('vibe_math_status', 'Show scheduler status, params, active agents, projects, and recent activity.', objParams({}), async function () { return await getStatus() })
483
504
  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() })
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 } })
505
+ registerTool('vibe_math_set_mode', 'Switch between manual and auto (preset) mode. Switching to auto auto-resolves any pending manual decisions.', objParams({ mode: { type: 'string', enum: ['manual', 'auto'] } }, ['mode']), async function (args) { params.mode = args.mode; await saveAll(); if (params.mode === 'auto') await autoResolvePending(); return { ok: true, mode: params.mode } })
485
506
  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 } })
486
507
  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' } })
487
508
  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() })
@@ -504,7 +525,7 @@ export function apply(ctx) {
504
525
  if (cmd === 'abort') return await abortScheduler()
505
526
  if (cmd === 'status') return await getStatus()
506
527
  if (cmd === 'report') { await maybeWriteReport(true); return buildReport() }
507
- if (cmd === 'mode') { params.mode = (args[0] === 'manual') ? 'manual' : 'auto'; await saveAll(); return { ok: true, mode: params.mode } }
528
+ if (cmd === 'mode') { params.mode = (args[0] === 'manual') ? 'manual' : 'auto'; await saveAll(); if (params.mode === 'auto') await autoResolvePending(); return { ok: true, mode: params.mode } }
508
529
  if (cmd === 'setup') { 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' } }
509
530
  if (cmd === 'save') return await saveSettings()
510
531
  if (cmd === 'template') return await createTemplate(args[0] === 'project' ? 'project' : 'global')
@@ -51,6 +51,7 @@ export function apply(ctx) {
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
+ proposPriorityAdjust: 'none', // none | progress-graded(按定论接近度+证明/证伪材料量动态调命题优先级)
54
55
  tickIntervalMs: 2000, // 调度器心跳间隔(毫秒)
55
56
  activityLogCap: 100, // 活动日志保留条数(report.recentActivity 最多显示 30 条)
56
57
  maxExplorerRetries: 3, // explorer 重派生上限(拆方向失败重试次数)
@@ -135,6 +136,7 @@ export function apply(ctx) {
135
136
  { name: 'reportMode', type: 'enum', options: ['file', 'push', 'both'], description: 'file = 写报告文件;push = 推送消息让主代理主动汇报;both = 两者都做', suggestion: 'file' },
136
137
  { name: 'promoteValueThreshold', type: 'number', description: 'Propos 中「价值/关键性」≥ 该值且未决(0,1) 的命题自动加入 qs.json', suggestion: 0.7 },
137
138
  { name: 'priorityAdjust', type: 'enum', options: ['none', 'deadend-deprioritize', 'survival-map'], description: '优先级动态调整策略:none=不自动调;deadend-deprioritize=方向全死路时降优先级;survival-map=按最高方向存活率重算(存活率高越优先)', suggestion: 'none' },
139
+ { name: 'proposPriorityAdjust', type: 'enum', options: ['none', 'progress-graded'], description: '命题优先级动态调整:none=不自动调;progress-graded=按「定论接近度(|布尔估计-0.5|)+ 证明/证伪材料量」重算,越接近定论越优先验证', suggestion: 'none' },
138
140
  { name: 'tickIntervalMs', type: 'integer', description: '调度器心跳间隔(毫秒):多久扫描一次子代理状态并推进(越小越灵敏、越大越省资源)', suggestion: 2000 },
139
141
  { name: 'activityLogCap', type: 'integer', description: '活动日志保留条数(影响 report.recentActivity 的细节量,报告最多显示 30 条)', suggestion: 100 },
140
142
  { name: 'maxExplorerRetries', type: 'integer', description: 'explorer 拆方向失败的重派生上限(达到后该问题标记为方向耗尽)', suggestion: 3 },
@@ -175,6 +177,7 @@ export function apply(ctx) {
175
177
  else if (k === 'verdictMode') { out[k] = (v === 'flat' || v === 'forced') ? v : DEFAULT_PARAMS[k] }
176
178
  else if (k === 'reportMode') { out[k] = (v === 'file' || v === 'push' || v === 'both') ? v : DEFAULT_PARAMS[k] }
177
179
  else if (k === 'priorityAdjust') { out[k] = (v === 'none' || v === 'deadend-deprioritize' || v === 'survival-map') ? v : DEFAULT_PARAMS[k] }
180
+ else if (k === 'proposPriorityAdjust') { out[k] = (v === 'none' || v === 'progress-graded') ? v : DEFAULT_PARAMS[k] }
178
181
  else { out[k] = v }
179
182
  }
180
183
  return out
@@ -495,14 +498,15 @@ export function apply(ctx) {
495
498
  }
496
499
  // note 4: probability-1 rules
497
500
  async function processStatusUpdates() {
498
- let changed = false
499
501
  const qs = await getQs()
502
+ let qsChanged = false
500
503
  for (let i = 0; i < qs.length; i++) {
501
504
  const q = qs[i]
502
- if (q.解法列表 && q.解法列表.some(function (s) { return s.正确概率 === 1 })) { if (!q.已解决) changed = true; q.已解决 = true; q.优先级 = 'never' }
505
+ if (q.解法列表 && q.解法列表.some(function (s) { return s.正确概率 === 1 })) { if (!q.已解决) qsChanged = true; q.已解决 = true; q.优先级 = 'never' }
503
506
  }
504
- if (changed) { await writeQs(qs); logActivity('update', 'problems marked solved by probability-1 solutions') }
507
+ if (qsChanged) { await writeQs(qs); logActivity('update', 'problems marked solved by probability-1 solutions') }
505
508
  const propos = await getPropos()
509
+ let closedPromoted = false
506
510
  for (let i = 0; i < propos.length; i++) {
507
511
  const p = propos[i]
508
512
  let pChanged = false
@@ -511,32 +515,61 @@ export function apply(ctx) {
511
515
  if (proofOne && p.布尔估计 !== 1) { p.布尔估计 = 1; pChanged = true }
512
516
  else if (refuteOne && p.布尔估计 !== 0) { p.布尔估计 = 0; pChanged = true }
513
517
  if ((p.布尔估计 === 1 || p.布尔估计 === 0) && p.优先级 !== 'never') { p.优先级 = 'never'; pChanged = true }
514
- if (p.布尔估计 === 1 || p.布尔估计 === 0) { if (await writeVerifiedCardIfNeeded(p)) pChanged = true }
518
+ if (p.布尔估计 === 1 || p.布尔估计 === 0) {
519
+ if (await writeVerifiedCardIfNeeded(p)) pChanged = true
520
+ // 源命题已定论 → 关闭其晋升出的"僵尸"问题(避免永远未解决)
521
+ const srcMarker = '由命题 ' + p.id + '('
522
+ for (let j = 0; j < qs.length; j++) {
523
+ const qj = qs[j]
524
+ if (!qj.已解决 && String(qj.progress || '').indexOf(srcMarker) !== -1) { qj.已解决 = true; qj.优先级 = 'never'; closedPromoted = true }
525
+ }
526
+ }
515
527
  if (pChanged) await upsertProposition(p)
516
528
  }
529
+ if (closedPromoted) { await writeQs(qs); logActivity('update', 'promoted problems closed because their source proposition resolved') }
517
530
  }
518
531
  async function processPriorityAdjust() {
519
532
  const mode = params.priorityAdjust || 'none'
520
- if (mode === 'none') return
521
- const qs = await getQs()
522
- let changed = false
523
- for (let i = 0; i < qs.length; i++) {
524
- const q = qs[i]
525
- if (q.已解决 || q.优先级 === 'never') continue
526
- const prog = parseProgress(q)
527
- if (mode === 'deadend-deprioritize') {
528
- if (prog.directions.length > 0 && prog.directions.every(function (d) { return d.status === 'dead-end' })) {
529
- const cur = Number(q.优先级); if (Number.isFinite(cur) && cur < 10) { q.优先级 = 10; changed = true }
530
- }
531
- } else if (mode === 'survival-map') {
532
- if (prog.directions.length > 0) {
533
- const maxSurv = Math.max.apply(null, prog.directions.map(function (d) { return Number(d.survival) || 0 }))
534
- const target = Math.round(Math.max(0, Math.min(10, 10 - 10 * maxSurv)))
535
- if (q.优先级 !== target) { q.优先级 = target; changed = true }
533
+ if (mode !== 'none') {
534
+ const qs = await getQs()
535
+ let changed = false
536
+ for (let i = 0; i < qs.length; i++) {
537
+ const q = qs[i]
538
+ if (q.已解决 || q.优先级 === 'never') continue
539
+ const prog = parseProgress(q)
540
+ if (mode === 'deadend-deprioritize') {
541
+ if (prog.directions.length > 0 && prog.directions.every(function (d) { return d.status === 'dead-end' })) {
542
+ const cur = Number(q.优先级); if (Number.isFinite(cur) && cur < 10) { q.优先级 = 10; changed = true }
543
+ }
544
+ } else if (mode === 'survival-map') {
545
+ if (prog.directions.length > 0) {
546
+ const maxSurv = Math.max.apply(null, prog.directions.map(function (d) { return Number(d.survival) || 0 }))
547
+ const target = Math.round(Math.max(0, Math.min(10, 10 - 10 * maxSurv)))
548
+ if (q.优先级 !== target) { q.优先级 = target; changed = true }
549
+ }
536
550
  }
537
551
  }
552
+ if (changed) { await writeQs(qs); logActivity('priority', 'priorities auto-adjusted (' + mode + ')') }
553
+ }
554
+ const pMode = params.proposPriorityAdjust || 'none'
555
+ if (pMode === 'progress-graded') {
556
+ const propos = await getPropos()
557
+ const changedProps = []
558
+ for (let i = 0; i < propos.length; i++) {
559
+ const p = propos[i]
560
+ if (p.布尔估计 === 1 || p.布尔估计 === 0 || p.优先级 === 'never') continue
561
+ const closeness = Math.abs(Number(p.布尔估计) - 0.5)
562
+ const material = Math.min(5, (p.证明列表 || []).length + (p.证伪列表 || []).length)
563
+ const score = closeness * 1.2 + material * 0.08
564
+ const target = Math.round(Math.max(0, Math.min(10, 10 - 10 * score)))
565
+ const cur = Number(p.优先级)
566
+ if (Number.isFinite(cur) && cur !== target) { p.优先级 = target; changedProps.push(p) }
567
+ }
568
+ if (changedProps.length > 0) {
569
+ for (let i = 0; i < changedProps.length; i++) await upsertProposition(changedProps[i])
570
+ logActivity('priority', 'proposition priorities auto-adjusted (progress-graded)')
571
+ }
538
572
  }
539
- if (changed) { await writeQs(qs); logActivity('priority', 'priorities auto-adjusted (' + mode + ')') }
540
573
  }
541
574
  // note 3 + user 价值 field: promote high-value unresolved propositions into qs.json
542
575
  async function processPromote() {
@@ -583,7 +616,7 @@ export function apply(ctx) {
583
616
  for (let j = 0; j < sols.length; j++) {
584
617
  const s = sols[j]
585
618
  if (s.正确概率 === 1 || s.正确概率 === 0 || s.已验) continue
586
- out.push({ rId: 'r-' + q.id + '-s' + j, kind: 'problem-solution', qid: q.id, 概述: q.概述, process: s.完整解法 || '', idx: j, priority: q.优先级 === 'never' ? 999 : Number(q.优先级) })
619
+ out.push({ rId: 'r-' + q.id + '-s' + j, kind: 'problem-solution', qid: q.id, 概述: q.概述, process: s.完整解法 || '', idx: j, prob: Number(s.正确概率) || 0, priority: q.优先级 === 'never' ? 999 : Number(q.优先级) })
587
620
  }
588
621
  }
589
622
  const propos = await getPropos()
@@ -592,13 +625,13 @@ export function apply(ctx) {
592
625
  if (p.布尔估计 === 1 || p.布尔估计 === 0 || p.优先级 === 'never') continue
593
626
  const proofs = p.证明列表 || []; const refutes = p.证伪列表 || []
594
627
  if (proofs.length === 0 && refutes.length === 0) {
595
- out.push({ rId: 'r-' + p.id, kind: 'proposition', pId: p.id, 概述: p.概述, priority: p.优先级 === 'never' ? 999 : Number(p.优先级) })
628
+ out.push({ rId: 'r-' + p.id, kind: 'proposition', pId: p.id, 概述: p.概述, prob: Number(p.布尔估计) || 0, priority: p.优先级 === 'never' ? 999 : Number(p.优先级) })
596
629
  } else {
597
- for (let j = 0; j < proofs.length; j++) { if (proofs[j].正确概率 === 1 || proofs[j].正确概率 === 0 || proofs[j].已验) continue; out.push({ rId: 'r-' + p.id + '-pf' + j, kind: 'prop-proof', pId: p.id, 概述: p.概述, side: '证明', process: proofs[j].完整过程 || '', idx: j, priority: p.优先级 === 'never' ? 999 : Number(p.优先级) }) }
598
- for (let j = 0; j < refutes.length; j++) { if (refutes[j].正确概率 === 1 || refutes[j].正确概率 === 0 || refutes[j].已验) continue; out.push({ rId: 'r-' + p.id + '-rf' + j, kind: 'prop-proof', pId: p.id, 概述: p.概述, side: '证伪', process: refutes[j].完整过程 || '', idx: j, priority: p.优先级 === 'never' ? 999 : Number(p.优先级) }) }
630
+ for (let j = 0; j < proofs.length; j++) { if (proofs[j].正确概率 === 1 || proofs[j].正确概率 === 0 || proofs[j].已验) continue; out.push({ rId: 'r-' + p.id + '-pf' + j, kind: 'prop-proof', pId: p.id, 概述: p.概述, side: '证明', process: proofs[j].完整过程 || '', idx: j, prob: Number(proofs[j].正确概率) || 0, priority: p.优先级 === 'never' ? 999 : Number(p.优先级) }) }
631
+ for (let j = 0; j < refutes.length; j++) { if (refutes[j].正确概率 === 1 || refutes[j].正确概率 === 0 || refutes[j].已验) continue; out.push({ rId: 'r-' + p.id + '-rf' + j, kind: 'prop-proof', pId: p.id, 概述: p.概述, side: '证伪', process: refutes[j].完整过程 || '', idx: j, prob: Number(refutes[j].正确概率) || 0, priority: p.优先级 === 'never' ? 999 : Number(p.优先级) }) }
599
632
  }
600
633
  }
601
- out.sort(function (a, b) { return a.priority - b.priority })
634
+ out.sort(function (a, b) { if (a.priority !== b.priority) return a.priority - b.priority; return (b.prob || 0) - (a.prob || 0) })
602
635
  return out
603
636
  }
604
637
  async function backfillVerifiers(t) {
@@ -686,6 +719,7 @@ export function apply(ctx) {
686
719
  const prog = parseProgress(q)
687
720
  const dir = prog.directions.find(function (d) { return d.id === dirId })
688
721
  if (!dir) { delete agentRegistry[childId]; return }
722
+ if (!parsed && !scheduler.running) { delete agentRegistry[childId]; return } // abort:不把方向标记为死路,保留待 resume
689
723
  const status = (parsed && parsed.status) || statusFromStop(stopReason)
690
724
  dir.round = meta.round
691
725
  if (parsed) {
@@ -742,9 +776,11 @@ export function apply(ctx) {
742
776
  function statusFromStop(stopReason) { return (stopReason === 'completed' || stopReason === 'max-tokens') ? 'continue' : 'dead-end' }
743
777
  async function addLemmaAsProposition(qid, lemma) {
744
778
  if (!lemma || !lemma.title) return
779
+ let be = clamp01(lemma.布尔估计 != null ? lemma.布尔估计 : 0.6)
780
+ if (be >= 1) be = 0.99; else if (be <= 0) be = 0.01 // 写入时概率必须 <1 且 >0(待验证器验证)
745
781
  const p = {
746
782
  id: 'p-' + shortId(), 概述: lemma.statement || lemma.title,
747
- 布尔估计: clamp01(lemma.布尔估计 != null ? lemma.布尔估计 : 0.6),
783
+ 布尔估计: be,
748
784
  细类型: (lemma.细类型 && typeof lemma.细类型 === 'object') ? lemma.细类型 : { 未分类: {} },
749
785
  证明列表: [{ 完整过程: lemma.proof || '', 正确概率: clamp01(0.7), '支持信息/依据': '' }],
750
786
  证伪列表: [], 优先级: (lemma.优先级 != null) ? lemma.优先级 : 1,
@@ -785,6 +821,14 @@ export function apply(ctx) {
785
821
  const Reason = (parsed && parsed.Reason) || ''
786
822
  let t = tasks['verify:' + rId]
787
823
  if (!t) { t = { id: 'verify:' + rId, type: 'verify', r: { kind: 'proposition', pId: rId, 概述: rId }, rId: rId, status: 'debating', children: [], childResults: {}, round: 1, expectedCount: Math.max(2, params.verifierCount), createdAt: now() }; tasks[t.id] = t }
824
+ if (!parsed && !scheduler.running) {
825
+ // abort:被中断的验证器没有产出,丢弃该子代理并清理任务簿记(任务在 resume 时由 processVerify 重建)
826
+ delete agentRegistry[childId]
827
+ const ix = t.children.indexOf(childId); if (ix !== -1) t.children.splice(ix, 1)
828
+ delete t.childResults[childId]
829
+ if (t.children.length === 0 && t.id && tasks[t.id]) delete tasks[t.id]
830
+ return
831
+ }
788
832
  if (t.children.indexOf(childId) === -1) t.children.push(childId)
789
833
  t.childResults[childId] = { Result: Result, Reason: Reason, round: meta.round }
790
834
  delete agentRegistry[childId]
@@ -796,6 +840,7 @@ export function apply(ctx) {
796
840
  async function advanceVerification(t, round) {
797
841
  if (round < params.debateMaxRounds && !consensus(t) && t.children.length > 0) {
798
842
  if (!scheduler.running) { t.status = 'paused'; return } // resume will re-advance this task
843
+ if (scheduler.activeCount >= params.maxParallelThreshold) { t.status = 'paused'; return } // 并发门:等有空闲槽位再辩论(reconcileVerify 会重推进)
799
844
  t.round = round + 1
800
845
  const transcript = buildTranscript(t)
801
846
  const nextChildren = []
@@ -905,7 +950,7 @@ export function apply(ctx) {
905
950
  sol.已验 = true
906
951
  sol.验证记录 = sol.验证记录 || []
907
952
  sol.验证记录.push({ 结果: v, 时间: now(), 依据: strongestReason(t, v >= 0.5 ? 1 : 0) })
908
- if (v === 1) { q.已解决 = true; q.优先级 = 'never' }
953
+ if (v === 1) { q.已解决 = true; q.优先级 = 'never'; await writeVerifiedProblemCardIfNeeded(q, sol) }
909
954
  }
910
955
  await writeQs(qs)
911
956
  }
@@ -936,6 +981,16 @@ export function apply(ctx) {
936
981
  await writeJson('Verified/' + cat + '_Verified.json', list)
937
982
  return true
938
983
  }
984
+ async function writeVerifiedProblemCardIfNeeded(q, sol) {
985
+ if (!q || !q.已解决) return false
986
+ const cat = '问题'
987
+ const list = await readVerifiedCategory(cat)
988
+ if (list.some(function (c) { return c.id === q.id })) return false // idempotent
989
+ const card = { id: q.id, 概述: q.概述, 类型: '问题', 结论: true, 概率: 1, 内容: (sol && sol.完整解法) || '', 来源: q.id, 时间: now(), 分类: cat }
990
+ list.push(card)
991
+ await writeJson('Verified/' + cat + '_Verified.json', list)
992
+ return true
993
+ }
939
994
 
940
995
  // ================= child result dispatch =================
941
996
  async function onChildEnd(info) {
@@ -970,15 +1025,28 @@ export function apply(ctx) {
970
1025
  logActivity(fresh ? 'start' : 'resume', 'cleared ' + Object.keys(agentRegistry).length + ' agent(s) and ' + Object.keys(tasks).length + ' task(s) (' + (fresh ? 'restart' : 'stale from previous process') + ')')
971
1026
  agentRegistry = {}; tasks = {}
972
1027
  }
1028
+ scheduler.activeCount = 0 // 仅清空 registry/tasks 时归零;同进程 resume 保留存活计数(并发门才准确)
973
1029
  }
974
1030
  await writeJson('VibeMath_State/process_epoch.json', processEpoch)
975
- scheduler.activeCount = 0; await saveAll()
1031
+ await saveAll()
976
1032
  return { ok: true }
977
1033
  }
978
1034
  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() } }
979
1035
  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() } }
980
1036
  async function pauseScheduler() { scheduler.running = false; logActivity('pause', 'scheduler paused'); await saveAll(); return { ok: true, message: 'scheduler paused' } }
981
1037
  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 } }
1038
+ // auto 模式语义 = 无人值守自动通过关键节点:切回 auto 时把仍挂起的人工决策按自动策略放行
1039
+ async function autoResolvePending() {
1040
+ const pending = decisionQueue.filter(function (d) { return d.status === 'pending' })
1041
+ for (let i = 0; i < pending.length; i++) {
1042
+ const d = pending[i]
1043
+ try {
1044
+ if (d.node === 'spawn') { await spawnChild(d.data.label, d.data.promptText, d.data.meta); d.status = 'resolved'; d.resolution = { action: 'approve', auto: true } }
1045
+ else if (d.node === 'verdict') { await settleVerdict(d.data.task, d.data.verdict); delete tasks[d.data.task.id]; d.status = 'resolved'; d.resolution = { action: 'approve', auto: true } }
1046
+ } catch (e) { console.error('vibe-math-v2: auto-resolve decision failed: ' + String((e && e.message) || e)) }
1047
+ }
1048
+ if (pending.length > 0) { scheduler.gate = null; logActivity('mode', 'switched to auto — auto-resolved ' + pending.length + ' pending decision(s)'); await saveAll(); scheduleTick() }
1049
+ }
982
1050
  async function getStatus() {
983
1051
  const qs = await getQs(); const propos = await getPropos()
984
1052
  return {
@@ -990,7 +1058,7 @@ export function apply(ctx) {
990
1058
  propositions: { total: propos.length, resolved: propos.filter(function (p) { return p.布尔估计 === 1 || p.布尔估计 === 0 }).length },
991
1059
  pendingDecisions: decisionQueue.filter(function (d) { return d.status === 'pending' }).length,
992
1060
  registeredAgents: Object.keys(agentRegistry).length,
993
- recentActivity: activityLog.slice(-10), params: params,
1061
+ recentActivity: activityLog.slice(-Math.min(10, Number(params.activityLogCap) || 100)), params: params,
994
1062
  }
995
1063
  }
996
1064
 
@@ -1026,8 +1094,8 @@ export function apply(ctx) {
1026
1094
  registerTool('vibe_math_abort', 'Abort the scheduler and interrupt all active children.', objParams({}), async function () { return await abortScheduler() })
1027
1095
  registerTool('vibe_math_status', 'Show scheduler status, params, active agents, projects, and recent activity.', objParams({}), async function () { return await getStatus() })
1028
1096
  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() })
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 } })
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 } })
1097
+ registerTool('vibe_math_set_mode', 'Switch between manual and auto (preset) mode. Switching to auto auto-resolves any pending manual decisions.', objParams({ mode: { type: 'string', enum: ['manual', 'auto'] } }, ['mode']), async function (args) { params.mode = args.mode; await saveAll(); if (params.mode === 'auto') await autoResolvePending(); return { ok: true, mode: params.mode } })
1098
+ 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'] }, proposPriorityAdjust: { type: 'string', enum: ['none', 'progress-graded'] }, 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 } })
1031
1099
  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' } })
1032
1100
  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() })
1033
1101
  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') })
@@ -1054,7 +1122,7 @@ export function apply(ctx) {
1054
1122
  if (cmd === 'abort') return await abortScheduler()
1055
1123
  if (cmd === 'status') return await getStatus()
1056
1124
  if (cmd === 'report') { await maybeWriteReport(true); return await buildReport() }
1057
- if (cmd === 'mode') { params.mode = (args[0] === 'manual') ? 'manual' : 'auto'; await saveAll(); return { ok: true, mode: params.mode } }
1125
+ if (cmd === 'mode') { params.mode = (args[0] === 'manual') ? 'manual' : 'auto'; await saveAll(); if (params.mode === 'auto') await autoResolvePending(); return { ok: true, mode: params.mode } }
1058
1126
  if (cmd === 'setup') { 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' } }
1059
1127
  if (cmd === 'save') return await saveSettings()
1060
1128
  if (cmd === 'template') return await createTemplate(args[0] === 'project' ? 'project' : 'global')