dsh-vibe-math 1.3.7 → 1.3.9
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
|
@@ -58,7 +58,11 @@
|
|
|
58
58
|
>
|
|
59
59
|
> 🔧 **v1.3.6 修复 v4 preset 选择后跳回原 preset**:v4 插件的 `apply` 读取 `ctx.subagents/agents/fs/tools/commands` 却**未声明 `inject`**,被 DSH 守卫以"未声明依赖"拒绝 → 组合无法挂载 → 选择后自动回退。已补 `export const inject = [...]`,并把心跳定时器从全局 `setTimeout/clearTimeout`(插件沙箱里不存在)改为 **`timer` 服务(`ctx.timeout`)**。
|
|
60
60
|
>
|
|
61
|
-
> 🔧 **v1.3.7 哲学回归(清晰提示词 + 真实交流群 +
|
|
61
|
+
> 🔧 **v1.3.7 哲学回归(清晰提示词 + 真实交流群 + 直接写文件)**:常驻首轮注入完整 `contextBrief`(背景/使命、工作模式、文件与格式、工具、规则);会议把其他常驻实际发言(input)转给每个人看,常驻日常轮的 `input` 经 `relayToGroup` 转发到其它常驻邮箱(像群聊);常驻**直接用 fs 写自己的 md**;去固定约束改为团队讨论涌现。详见 §20。
|
|
62
|
+
>
|
|
63
|
+
> 🔧 **v1.3.8 基于真实测试的诊断修复**:**① 共识验证真正"全体一致"**——`finalizeVerify` 现在要求**全体在册常驻都投了票**才可判"一致",否则辩论或保留为未定论(实测曾出现 2/4 投票却被判"全体一致为真",已修);**② 会议必须全体发言**——`continueMeetingRound` 按"是否已发言"收口,`allSolved`(stop)要求全员发言+全票 true,杜绝缺席成员被带偏;**③ 背景只在首轮讲一次**——`contextBrief` 只在 `brainstormPrompt`(首轮)注入完整版,后续 normal/meeting/verify/CHECKPOINT 用极简当前状态,不再每轮重复长背景(省上下文);**④ 验证目标按提出者精确定位**(`targetOwner` + `findSourceRel` 优先提出者库,避免同名 id 撞车);**⑤ 主代理放权**——persona 明确"让常驻自组织(hands-off)",不注议程/优先级/分工/验证决定,只 read status/report,用户明确要求或明显僵死时才 message/meeting 且只促成不决定。详见 §21。
|
|
64
|
+
>
|
|
65
|
+
> 🔧 **v1.3.9 进一步按哲学打磨**:**① 会议议程来源**确认是非 bug(r-1 的 `propose_meeting` 发起);**② 压缩后重申核心规则**——每次压缩触发时在提示开头重申短核心规则(治"压缩遗忘规则"),其余轮仍极简;**③ 验证 `verdict` 明确为 0–1 正确概率**——1=绝对为真/判真、0=绝对为假/判假、0.5=不确定,"全体一致判真(verdict=1)/判假(verdict=0)才算数",未全票留库附平均正确概率(兼容旧字符串);**④ 创建项目不立即启动**——新增 `vibe_v4_configure {project?, problem?, params?}` 只建/配项目与参数(持久化 `State/settings.json`)不唤醒常驻,随后 `vibe_v4_start` 才启动;支持设置**项目名**。详见 §22。
|
|
62
66
|
|
|
63
67
|
---
|
|
64
68
|
|
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 — FOUR agent presets in one install: vibe-math-v1 (classic pipeline), vibe-math-v2 (probability-driven: qs.json + Propos knowledge base + explorer→solver→review/debate verdict), vibe-math-v3 (THIRD-generation, recommended: paper-style Markdown knowledge base with Problems/Progress/Propos/Methods/Verified + planner-agent scheduling that decides the next N actions + universal theory/method invention library + agents write their own Markdown directly via a per-file write lock), and vibe-math-v4 (FOURTH-generation: persistent self-organizing resident subagents that message & meet to decide all tasks, verify only by unanimous consensus, /compact at a context threshold, and stop only when all agree the problem is solved). Installing this bundle auto-installs all four presets into the DSH preset root.",
|
|
4
|
-
"version": "1.3.
|
|
4
|
+
"version": "1.3.9",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "installer.js",
|
|
7
7
|
"exports": {
|
|
@@ -36,6 +36,14 @@
|
|
|
36
36
|
team genuinely discusses/debates), convenes and records meetings, exposes a shared task
|
|
37
37
|
board, and stops the run only when the whole team agrees the problem is solved.
|
|
38
38
|
|
|
39
|
+
**YOUR ROLE — LET THEM SELF-ORGANIZE (hands-off):** you are NOT a moderator/coordinator.
|
|
40
|
+
Do NOT inject agendas, priorities, division-of-labor, or verification decisions, and do
|
|
41
|
+
NOT direct the residents' work. After `vibe_v4_start`, stay passive: read `vibe_v4_status`
|
|
42
|
+
/ `vibe_v4_report` and summarize in plain language when asked. Use `vibe_v4_message` /
|
|
43
|
+
`vibe_v4_meeting` ONLY when the user explicitly asks you to intervene, or when the group
|
|
44
|
+
is visibly deadlocked (all idle & nothing progressing for a long time) — and even then,
|
|
45
|
+
only relay/nudge the group to decide, never decide for them.
|
|
46
|
+
|
|
39
47
|
Data lives under {{cwd}}/VibeMath/Projects/<project>/:
|
|
40
48
|
Problems/ (original problem card), Progress/<resident>/ (each resident's progress),
|
|
41
49
|
Propos/<resident>/ (each resident's propositions, "- ID: p-<id>" / "- 概率:" / "- 价值程度:" ...),
|
|
@@ -43,16 +51,16 @@
|
|
|
43
51
|
task board / debates), Verified/ (read-only, ONLY after unanimous consensus),
|
|
44
52
|
State/ (framework-private), Reliable/ (references), Notes/.
|
|
45
53
|
|
|
46
|
-
Main controls:
|
|
47
|
-
-
|
|
48
|
-
-
|
|
49
|
-
-
|
|
54
|
+
Main controls (recommended flow: configure FIRST, then start):
|
|
55
|
+
- vibe_v4_configure {project?, problem?, params?} — create/configure the project (name, problem, params) WITHOUT starting a run; set everything here first.
|
|
56
|
+
- vibe_v4_start {problem?, residentCount?, seedDirections?} — begin the run (spawn residents, brainstorm). If problem was configured, omit it.
|
|
57
|
+
- vibe_v4_set {residentCount, compactThreshold, compactAfterRounds, meetingKeepEvery, maxParallel, activityTimeoutMs, verdictMaxRounds} — tune params (persisted to the settings file).
|
|
58
|
+
- vibe_v4_resume / vibe_v4_pause / vibe_v4_abort / vibe_v4_status / vibe_v4_report.
|
|
50
59
|
- vibe_v4_message {to|all, content} — inject a message to a resident (human/assistant intervention).
|
|
51
60
|
- vibe_v4_meeting {agenda} — force a meeting.
|
|
52
61
|
- vibe_v4_add_member {direction?} / vibe_v4_remove_member {id} — add / close a resident.
|
|
53
62
|
- vibe_v4_list_members — list residents.
|
|
54
|
-
|
|
55
|
-
A /v4 slash command mirrors the main controls.
|
|
63
|
+
A /v4 slash command mirrors the main controls (configure|start|resume|pause|abort|status|report|meeting|members|add|remove|set).
|
|
56
64
|
|
|
57
65
|
TRUST RULE: only Verified/ (and Propos/ entries marked 已验证·真/假) are absolutely
|
|
58
66
|
trustworthy; everything else — unverified resident claims, Progress/, Method claims —
|
|
@@ -157,6 +157,13 @@ export function apply(ctx) {
|
|
|
157
157
|
s.push('- 退出时**只**输出一个 JSON 对象(放在 ```json 代码围栏内;围栏外不要有文字)。')
|
|
158
158
|
return s.join('\n')
|
|
159
159
|
}
|
|
160
|
+
// A SHORT core-rules recap, re-injected ONLY right after a compaction so the resident
|
|
161
|
+
// never loses the ground rules (they are told fully once at brainstorm, but a /compact
|
|
162
|
+
// could blank them).
|
|
163
|
+
function coreRulesBrief(){
|
|
164
|
+
const base=frameworkRoot()
|
|
165
|
+
return '[核心规则重申] 只有 Verified/(及标记"已验证·真/假")算已确立;验证须全组一致(全真或全假)才作数,否则留库附平均概率;你只写自己的库('+base+'/ 的 Progress/<你>/、Propos/<你>/、Methods/<你>/、Subproblems/<你>/),可只读任何人的库;任务分工由团队讨论决定;退出只输出一个 JSON 对象。'
|
|
166
|
+
}
|
|
160
167
|
function brainstormPrompt(r){
|
|
161
168
|
return (params.residentPersona?params.residentPersona+'\n':'')
|
|
162
169
|
+contextBrief(r,'full')+'\n'
|
|
@@ -169,38 +176,34 @@ export function apply(ctx) {
|
|
|
169
176
|
}
|
|
170
177
|
async function normalPrompt(r){
|
|
171
178
|
return (params.residentPersona?params.residentPersona+'\n':'')
|
|
172
|
-
+
|
|
173
|
-
+'## 你的第 '+r.rounds+' 轮\n'
|
|
174
|
-
+'这一轮你自己决定做什么:推进你的方向、验证你的结论、给某常驻发消息、提议/认领任务、或发起会议/验证。**一切由你和团队讨论决定,没有外部派活。**\n'
|
|
175
|
-
+'动手前先**读读别人的库**(Read-only)知道大家做到哪、对齐事实、避免重复;然后**直接把你的进展/新结论用 fs 写进你自己的文件**。\n'
|
|
176
|
-
+'若你有话要对团队说(想让大家看到、讨论),在回复的 "input" 里写出来——它会被转发给其他常驻(如同一场群聊)。\n'
|
|
179
|
+
+'Resident researcher '+r.rId+' — 第 '+r.rounds+' 轮。一切由你和团队讨论决定。动手前先**读别人的库**对齐事实、避免重复;把新进展/结论**直接用 fs 写进你自己的文件**;想对团队说的话放 "input"(会转给其他常驻)。\n'
|
|
177
180
|
+'\n团队成员:\n'+banner()+'\n'
|
|
178
181
|
+'New items:\n'+ (await inboxText(r.rId)) +'\n'
|
|
179
182
|
+'Reply with ONLY a JSON object:\n'
|
|
180
|
-
+'{"summary":"<what you did / decided this round, 1-3 sentences>","input":"<optional: a message to the whole team, or
|
|
183
|
+
+'{"summary":"<what you did / decided this round, 1-3 sentences>","input":"<optional: a message to the whole team, or \\"\\">","solved":false,"propose_verify":"<id|null>","propose_meeting":"<agenda|null>","propose_task":"<task title|null>","claim_task":"<task id|null>","task_done":"<task id|null>","contextPct":40}'
|
|
181
184
|
}
|
|
182
185
|
function meetingPrompt(r, st){
|
|
183
186
|
const prior=Object.entries(st.inputs).filter(([k])=>k!==r.rId).map(([k,iv])=>' ['+k+'] '+String(iv.input||iv.summary||'')).join('\n')
|
|
184
187
|
return (params.residentPersona?params.residentPersona+'\n':'')
|
|
185
|
-
+
|
|
186
|
-
+'
|
|
187
|
-
+
|
|
188
|
-
+'\n这是一场**真实讨论**:下面已有人发言(框架把各常驻的 input 转给你),请先看,然后**加入讨论/补充/反驳/表决**。'
|
|
188
|
+
+'Resident '+r.rId+' — 团队会议进行中。 A meeting is in progress (agenda: '+st.agenda+').'
|
|
189
|
+
+(st.type==='verify'?('\n团队正在验证对象:'+st.targetId+'('+st.targetType+',提出者 '+st.targetOwner+')。请先看他人意见,再给独立判断。'):'')
|
|
190
|
+
+'\n这是一场真实讨论:下面已有人发言(转给你),请先看,然后**加入讨论/补充/反驳/表决**。'
|
|
189
191
|
+(prior?('\n\n### 已有发言(他人 input,已转发给你)\n'+prior):'\n(目前还没人发言,你先说。)')
|
|
190
192
|
+'\n\n你可以:提议任务(propose_task)、认领开放任务(claim_task)、提议验证对象(propose_verify)、或对"原问题是否已解决"表决(voteSolved)。请把**你的实际发言**写进 "input"。'
|
|
191
193
|
+'\nReply with ONLY a JSON object:\n'
|
|
192
194
|
+'{"input":"<your real contribution to this discussion>","propose_task":"<task title or null>","task_desc":"...","claim_task":"<task id or null>","propose_verify":"<id or null>","voteSolved":true}'
|
|
193
195
|
}
|
|
194
196
|
function verifyPrompt(r, vs){
|
|
195
|
-
const others=Object.entries(vs.verdicts).map(([k,v])=>'- '+k+': '+v.verdict+' ('+v.
|
|
197
|
+
const others=Object.entries(vs.verdicts).map(([k,v])=>'- '+k+': '+(v.verdict==='TRUE'?'判真':v.verdict==='FALSE'?'判假':'不确定')+' (正确概率 '+String(v.prob!=null?Number(v.prob).toFixed(2):0.5)+') '+v.reason).join('\n')
|
|
196
198
|
return (params.residentPersona?params.residentPersona+'\n':'')
|
|
197
|
-
+
|
|
198
|
-
+'
|
|
199
|
-
+'
|
|
199
|
+
+'Resident '+r.rId+' — 团队验证。 The group is verifying object '+vs.targetId+'('+vs.targetType+',提出者 '+vs.targetOwner+')。\n'
|
|
200
|
+
+'请给出你对「该对象为真」的正确概率 `verdict`,取值范围 **0–1**:**1 = 绝对为真(判真)**, **0 = 绝对为假(判假)**, **0.5 = 完全不确定**, 介于其间按倾向。\n'
|
|
201
|
+
+'只有**全体常驻一致判真(正确概率 verdict 为 1)或一致判假(正确概率 verdict 为 0)**才算数;否则该对象留库并附上全组平均正确概率(不写入 Verified/)。\n'
|
|
202
|
+
+'请给出你**诚实独立的判断**'
|
|
200
203
|
+(vs.stage==='debate'?',并参考他人意见:\n':'。\n')
|
|
201
204
|
+(vs.stage==='debate'&&others?('### 他人意见(已转发给你)\n'+others+'\n'):'')
|
|
202
205
|
+'\nReply with ONLY a JSON object:\n'
|
|
203
|
-
+'{"vote":{"verdict":
|
|
206
|
+
+'{"vote":{"verdict":0.9,"reason":"<your logic>"}}'
|
|
204
207
|
}
|
|
205
208
|
|
|
206
209
|
// ---- resident lifecycle ----
|
|
@@ -222,7 +225,8 @@ export function apply(ctx) {
|
|
|
222
225
|
// framework uses as the next context seed (equivalent to /compact's "consolidate & forget").
|
|
223
226
|
let prompt = promptText
|
|
224
227
|
if(r.needCompact || (Number(r.contextPct)>=Number(params.compactThreshold)) || (r.roundsSinceCompact>=Number(params.compactAfterRounds))){
|
|
225
|
-
prompt =
|
|
228
|
+
prompt = coreRulesBrief() + '\n' +
|
|
229
|
+
'[CONTEXT COMPACT — your conversation is at/near the limit. Do NOT re-derive history.\n' +
|
|
226
230
|
'Condense your current working state into ONE tight self-summary (findings so far, active direction, key artifacts you recorded, next concrete steps, open questions), then answer this round in the normal JSON format as usual.\n' +
|
|
227
231
|
'Set "contextPct": 15 (your post-compact usage) and "compacted": true in the reply so the framework records the condensed seed.]\n\n' + promptText
|
|
228
232
|
r.needCompact = true
|
|
@@ -294,15 +298,16 @@ export function apply(ctx) {
|
|
|
294
298
|
}
|
|
295
299
|
async function continueMeetingRound(){
|
|
296
300
|
if(!meetingState) return
|
|
297
|
-
const ids=Array.from(residents.keys()); const
|
|
298
|
-
if(
|
|
299
|
-
// only wake IDLE
|
|
300
|
-
const id=ids.find(x=>meetingState.
|
|
301
|
-
|
|
301
|
+
const ids=Array.from(residents.keys()); const allSpoke=ids.every(id=>meetingState.inputs[id]!==undefined)
|
|
302
|
+
if(allSpoke){ await finalizeMeeting(); return }
|
|
303
|
+
// only wake IDLE un-spoken residents; in-flight ones re-trigger this on end.
|
|
304
|
+
const id=ids.find(x=>meetingState.inputs[x]===undefined && !busy.has(x)); if(!id) return
|
|
305
|
+
const r=residents.get(id)
|
|
302
306
|
await wakeResident(r, meetingPrompt(r,meetingState), 'meeting'); await saveAll()
|
|
303
307
|
}
|
|
304
308
|
async function finalizeMeeting(){
|
|
305
309
|
const st=meetingState
|
|
310
|
+
const ids=Array.from(residents.keys()); const allSpoke=ids.length>0 && ids.every(id=>st.inputs[id]!==undefined)
|
|
306
311
|
const lines=['# 会议 '+st.id+'|'+fmtTime(),'','**议程**:'+st.agenda,'']
|
|
307
312
|
for(const [id,iv] of Object.entries(st.inputs)){ lines.push('### '+id); lines.push(iv.input||''); lines.push('') }
|
|
308
313
|
await writeText('Shared/meetings/'+st.id+'.md', lines.join('\n'))
|
|
@@ -315,8 +320,8 @@ export function apply(ctx) {
|
|
|
315
320
|
if(iv.propose_verify) pendingVerify={targetId:iv.propose_verify,targetType:guessTargetType(iv.propose_verify),proposer:id,at:now()}
|
|
316
321
|
}
|
|
317
322
|
const votes=Object.values(st.inputs).map(x=>x.voteSolved).filter(v=>typeof v==='boolean')
|
|
318
|
-
const allSolved=votes.length>0 && votes.every(v=>v===true)
|
|
319
|
-
logActivity('meeting', 'concluded'+(allSolved?' → ALL agree solved':''))
|
|
323
|
+
const allSolved = allSpoke && votes.length>0 && votes.every(v=>v===true)
|
|
324
|
+
logActivity('meeting', 'concluded'+(allSolved?' → ALL agree solved':' (no unanimous solved vote)'))
|
|
320
325
|
if(allSolved){ running=false; autoDone=true; phase='done'; logActivity('stop','all residents agree: problem solved'); await saveAll(); return }
|
|
321
326
|
meetingState=null; wakeKind.clear(); await saveAll(); await scheduleNext()
|
|
322
327
|
}
|
|
@@ -325,39 +330,40 @@ export function apply(ctx) {
|
|
|
325
330
|
async function beginVerify(pv){
|
|
326
331
|
clearHeartbeat()
|
|
327
332
|
pendingVerify=null
|
|
328
|
-
verifyState={targetId:pv.targetId,targetType:pv.targetType,stage:'independent',round:0,asked:[],verdicts:{},transcript:[]}
|
|
333
|
+
verifyState={targetId:pv.targetId,targetType:pv.targetType,targetOwner:pv.proposer||'',stage:'independent',round:0,asked:[],verdicts:{},transcript:[]}
|
|
329
334
|
logActivity('verify','debate begin: '+pv.targetId+' ('+pv.targetType+')'); await saveAll(); await scheduleNext()
|
|
330
335
|
}
|
|
331
336
|
async function continueVerifyRound(){
|
|
332
337
|
if(!verifyState) return
|
|
333
|
-
const ids=Array.from(residents.keys()); const
|
|
334
|
-
if(
|
|
335
|
-
|
|
336
|
-
const
|
|
337
|
-
verifyState.asked.push(id); const r=residents.get(id)
|
|
338
|
+
const ids=Array.from(residents.keys()); const allVoted=ids.every(id=>verifyState.verdicts[id]!==undefined)
|
|
339
|
+
if(allVoted){ await finalizeVerify(); return }
|
|
340
|
+
const id=ids.find(x=>verifyState.verdicts[x]===undefined && !busy.has(x)); if(!id) return
|
|
341
|
+
const r=residents.get(id)
|
|
338
342
|
await wakeResident(r, verifyPrompt(r,verifyState), verifyState.stage==='independent'?'verif-ind':'verif-deb'); await saveAll()
|
|
339
343
|
}
|
|
340
344
|
async function finalizeVerify(){
|
|
341
|
-
const vs=verifyState; const
|
|
342
|
-
const
|
|
343
|
-
const
|
|
345
|
+
const vs=verifyState; const expected=Array.from(residents.keys()).length
|
|
346
|
+
const allVoted = expected>0 && Object.keys(vs.verdicts).length>=expected
|
|
347
|
+
const vals=Object.values(vs.verdicts)
|
|
348
|
+
const allTrue = allVoted && vals.every(x=>x.verdict==='TRUE')
|
|
349
|
+
const allFalse = allVoted && vals.every(x=>x.verdict==='FALSE')
|
|
344
350
|
if(allTrue||allFalse){ await closeVerify(vs,allTrue); return }
|
|
345
351
|
if(vs.round+1<params.verdictMaxRounds){ vs.stage='debate'; vs.round+=1; vs.asked=[]; logActivity('verify',vs.targetId+' round '+vs.round+' → debate'); await saveAll(); await scheduleNext(); return }
|
|
346
|
-
const avg=vals.length? vals.reduce((a,x)=>a+(x.
|
|
347
|
-
await writeDebateDoc(vs,false,avg); await rewriteSourceProb(vs.targetId, avg); logActivity('verify',vs.targetId+' NOT unanimous → kept unverified (avg '+avg.toFixed(2)+')')
|
|
352
|
+
const avg=vals.length? vals.reduce((a,x)=>a+(x.prob!=null?x.prob:0.5),0)/vals.length : 0.5
|
|
353
|
+
await writeDebateDoc(vs,false,avg); await rewriteSourceProb(vs.targetId, avg, vs.targetOwner); logActivity('verify',vs.targetId+' NOT unanimous → kept unverified (avg '+avg.toFixed(2)+')')
|
|
348
354
|
verifyState=null; wakeKind.clear(); await saveAll(); await scheduleNext()
|
|
349
355
|
}
|
|
350
356
|
async function closeVerify(vs,isTrue){
|
|
351
357
|
await writeDebateDoc(vs,true,isTrue?1:0)
|
|
352
358
|
const target=vs.targetId
|
|
353
359
|
await writeVerifiedCard(vs,isTrue)
|
|
354
|
-
await rewriteSource(target,isTrue)
|
|
360
|
+
await rewriteSource(target,isTrue,vs.targetOwner)
|
|
355
361
|
logActivity('verify',target+' → Verified ('+(isTrue?'真':'假')+') by unanimous consensus')
|
|
356
362
|
verifyState=null; wakeKind.clear(); await saveAll(); await scheduleNext()
|
|
357
363
|
}
|
|
358
364
|
async function writeDebateDoc(vs,done,val){
|
|
359
365
|
const lines=['# 验证辩论|'+vs.targetId+'('+vs.targetType+')|'+fmtTime(),'',(done?('**结论**:'+(val===1?'全体一致为真':'全体一致为假')):('**未达成全体一致**,平均概率 '+val.toFixed(2))),'','## 各常驻意见']
|
|
360
|
-
for(const [k,v] of Object.entries(vs.verdicts)){ lines.push('### '+k+'|'+v.verdict+'
|
|
366
|
+
for(const [k,v] of Object.entries(vs.verdicts)){ lines.push('### '+k+'|'+(v.verdict==='TRUE'?'判真':v.verdict==='FALSE'?'判假':'不确定')+'|正确概率 '+(v.prob!=null?Number(v.prob).toFixed(2):'0.50')); lines.push(v.reason||''); lines.push('') }
|
|
361
367
|
await writeText('Shared/debates/'+vs.targetId+'.md', lines.join('\n'))
|
|
362
368
|
}
|
|
363
369
|
async function writeVerifiedCard(vs,isTrue){
|
|
@@ -367,27 +373,27 @@ export function apply(ctx) {
|
|
|
367
373
|
const text='# 已验证|'+vs.targetId+'\n- ID: '+vs.targetId+'\n- 类型: '+type+'\n- 结论: '+(isTrue?'真':'假')+'\n- 概率: '+(isTrue?1:0)+'\n- 来源: 全体常驻一致\n## 陈述\n参见来源卡。\n'
|
|
368
374
|
await writeText('Verified/'+dir+'/'+vs.targetId+'.md', text)
|
|
369
375
|
}
|
|
370
|
-
async function findSourceRel(target){
|
|
371
|
-
|
|
372
|
-
|
|
376
|
+
async function findSourceRel(target, owner){
|
|
377
|
+
// Prefer the OWNER's library (avoids id collisions across residents), then others.
|
|
378
|
+
const order = owner ? [owner, ...Array.from(residents.keys()).filter(k=>k!==owner)] : Array.from(residents.keys())
|
|
379
|
+
for(const rid of order){
|
|
373
380
|
for(const base of ['Propos','Methods','Subproblems']){
|
|
374
|
-
const cand=base+'/'+rid+'/'+target+'.md'; if((await readText(cand))!==undefined){
|
|
381
|
+
const cand=base+'/'+rid+'/'+target+'.md'; if((await readText(cand))!==undefined){ return cand }
|
|
375
382
|
}
|
|
376
|
-
if(rel) break
|
|
377
383
|
}
|
|
378
|
-
return
|
|
384
|
+
return 'Propos/'+target+'.md'
|
|
379
385
|
}
|
|
380
386
|
// non-unanimous verification: keep the object in its library but write back the
|
|
381
387
|
// average probability (design §8: "留库附概率"), so the card reflects the consensus estimate.
|
|
382
|
-
async function rewriteSourceProb(target,prob){
|
|
383
|
-
const rel=await findSourceRel(target)
|
|
388
|
+
async function rewriteSourceProb(target,prob,owner){
|
|
389
|
+
const rel=await findSourceRel(target,owner)
|
|
384
390
|
let text=(await readText(rel))||''
|
|
385
391
|
text=text.replace(/(^|\n)- 概率:.*/m,'$1- 概率: '+Number(prob).toFixed(2))
|
|
386
392
|
await writeText(rel,text)
|
|
387
393
|
}
|
|
388
|
-
async function rewriteSource(target,isTrue){
|
|
394
|
+
async function rewriteSource(target,isTrue,owner){
|
|
389
395
|
// find & update the source card status/prob; best effort across per-resident libs
|
|
390
|
-
const rel=await findSourceRel(target)
|
|
396
|
+
const rel=await findSourceRel(target,owner)
|
|
391
397
|
let text=(await readText(rel))||''
|
|
392
398
|
text=text.replace(/(^|\n)- 状态:.*/m,'$1'+(isTrue?'- 状态: 已验证·真':'- 状态: 已验证·假'))
|
|
393
399
|
.replace(/(^|\n)- 概率:.*/m,'$1'+(isTrue?'- 概率: 1':'- 概率: 0'))
|
|
@@ -402,8 +408,7 @@ export function apply(ctx) {
|
|
|
402
408
|
// of infinite token-burning, matching the "framework never assigns work" philosophy.
|
|
403
409
|
function heartbeatPrompt(r){
|
|
404
410
|
return (params.residentPersona?params.residentPersona+'\n':'')
|
|
405
|
-
+
|
|
406
|
-
+'## CHECKPOINT(空闲)—— 团队在等待方向。\n'
|
|
411
|
+
+'Resident researcher '+r.rId+' — CHECKPOINT(空闲):团队在等待方向。'
|
|
407
412
|
+'请用一句话说明你下一步做什么;若你已无产出、或认为问题已解决/接近解决,请**提议开会(propose_meeting)**、**提议验证(propose_verify)**、或**声明 solved=true**,让团队能做出决定——不要产出填充性工作。\n'
|
|
408
413
|
+'Reply with ONLY a JSON object:\n'
|
|
409
414
|
+'{"summary":"<what you do next or a declaration>","solved":false,"propose_verify":"<id|null>","propose_meeting":"<agenda|null>","claim_task":"<id|null>"}'
|
|
@@ -490,8 +495,15 @@ export function apply(ctx) {
|
|
|
490
495
|
}
|
|
491
496
|
if((kind==='verif-ind'||kind==='verif-deb') && verifyState){
|
|
492
497
|
const v=(parsed&&parsed.vote)||{}
|
|
493
|
-
|
|
494
|
-
|
|
498
|
+
// verdict = 0-1 probability the object is TRUE (1=绝对真, 0=绝对假, 0.5=不确定);
|
|
499
|
+
// also accept legacy 'TRUE'/'FALSE' strings.
|
|
500
|
+
let p
|
|
501
|
+
if(typeof v.verdict==='number'){ p=clamp01(v.verdict) }
|
|
502
|
+
else if(/^TRUE$/i.test(String(v.verdict))){ p=1 }
|
|
503
|
+
else if(/^FALSE$/i.test(String(v.verdict))){ p=0 }
|
|
504
|
+
else { p=clamp01(Number(v.confidence)) }
|
|
505
|
+
const verdict= p>0.5?'TRUE': p<0.5?'FALSE':'UNCERTAIN'
|
|
506
|
+
verifyState.verdicts[r.rId]={verdict,prob:p,confidence:p,reason:String(v.reason||parsed.summary||'')}
|
|
495
507
|
await saveAll(); await continueVerifyRound(); return
|
|
496
508
|
}
|
|
497
509
|
// normal turn
|
|
@@ -515,10 +527,12 @@ export function apply(ctx) {
|
|
|
515
527
|
|
|
516
528
|
// ---- controls ----
|
|
517
529
|
async function start({problem,residentCount,seedDirections}){
|
|
518
|
-
|
|
530
|
+
await loadSettings()
|
|
519
531
|
currentProject=await readCurrentProject(); if(!currentProject||currentProject==='default'){ currentProject='default'; }
|
|
520
532
|
await ensureDirs()
|
|
521
|
-
|
|
533
|
+
if(problem) problemText=String(problem)
|
|
534
|
+
if(!problemText) return {ok:false,message:'problem text required (pass problem, or use vibe_v4_configure first)'}
|
|
535
|
+
problemId=slugify(problemText.slice(0,40))||'problem'
|
|
522
536
|
if(residentCount) params.residentCount=Number(residentCount)||4
|
|
523
537
|
running=true; autoDone=false; phase='brainstorm'
|
|
524
538
|
await writeText('Problems/'+problemId+'.md','# 问题|'+problemId+'\n- ID: '+problemId+'\n- 类型: 问题\n- 状态: 求解中\n- 优先级: 1\n- 依赖: []\n\n## 陈述\n'+problemText+'\n')
|
|
@@ -549,14 +563,26 @@ export function apply(ctx) {
|
|
|
549
563
|
recentActivity: activityLog.slice(-8) } }
|
|
550
564
|
async function addMember(direction){ const r=newResident(direction||''); await spawnResident(r); return {ok:true,id:r.rId,direction:r.direction} }
|
|
551
565
|
async function removeMember(id){ const r=residents.get(id); if(!r) return {ok:false}; if(r.childId){ try{ subagents.interrupt(r.childId,{kind:'ancestor',agent:rootAgent}) }catch(e){} } residents.delete(id); busy.delete(id); mailboxes.delete(id); await saveAll(); return {ok:true} }
|
|
552
|
-
function setParams(upd){ for(const k of Object.keys(upd||{})){ if(k in params) params[k]=upd[k] } return {ok:true} }
|
|
566
|
+
function setParams(upd){ for(const k of Object.keys(upd||{})){ if(k in params) params[k]=upd[k] } saveSettings().catch(()=>{}); return {ok:true} }
|
|
567
|
+
// ---- create / configure (no auto-start) + settings-file persistence ----
|
|
568
|
+
async function loadSettings(){ const s=await readJson('State/settings.json'); if(s&&typeof s==='object'){ for(const k of Object.keys(s)){ if(k in params) params[k]=s[k] } } }
|
|
569
|
+
async function saveSettings(){ await writeJson('State/settings.json', params) }
|
|
570
|
+
// Create/configure a project and set params/problem WITHOUT starting any resident.
|
|
571
|
+
// The intended flow: vibe_v4_configure {project?, problem?, params?} → vibe_v4_start {}.
|
|
572
|
+
async function configure(cfg){
|
|
573
|
+
if(cfg && cfg.project && String(cfg.project).trim()) currentProject=String(cfg.project).trim()
|
|
574
|
+
if(cfg && cfg.problem) problemText=String(cfg.problem)
|
|
575
|
+
if(cfg && cfg.params && typeof cfg.params==='object') for(const k of Object.keys(cfg.params)) if(k in params) params[k]=cfg.params[k]
|
|
576
|
+
await writeCurrentProject(); await ensureDirs(); await saveSettings(); await saveAll()
|
|
577
|
+
return {ok:true,project:currentProject,problem:problemText?problemText.slice(0,60):'',params:Object.keys(params).map(k=>k+'='+params[k]).join(', ')}
|
|
578
|
+
}
|
|
553
579
|
async function initAbort(){ clearHeartbeat(); running=false; phase='idle'; autoDone=false; for(const [,r] of residents){ if(r.childId){ try{ subagents.interrupt(r.childId,{kind:'ancestor',agent:rootAgent}) }catch(e){} } r.childId=''; r.lastActiveAt=0; r.roundsSinceCompact=0 } await saveAll(); return {ok:true,message:'aborted'} }
|
|
554
580
|
function setPause(){ clearHeartbeat(); running=false; return {ok:true,message:'paused'} }
|
|
555
581
|
|
|
556
582
|
return {
|
|
557
583
|
sessionId, running:()=>running, autoDone:()=>autoDone, phase:()=>phase,
|
|
558
584
|
onResidentEnd, start, resume, status, report, addMember, removeMember, setParams,
|
|
559
|
-
setPause, initAbort, postMessage, startMeeting, saveAll, broadcast,
|
|
585
|
+
setPause, initAbort, postMessage, startMeeting, saveAll, broadcast, configure, loadSettings,
|
|
560
586
|
currentResident:()=>currentResident,
|
|
561
587
|
residentIdOf:(agent)=>{ const m=residentOfAgent(agent); return m||currentResident },
|
|
562
588
|
useResident:(id)=>{ currentResident=id },
|
|
@@ -580,7 +606,8 @@ export function apply(ctx) {
|
|
|
580
606
|
} })
|
|
581
607
|
}
|
|
582
608
|
// host/assistant-facing
|
|
583
|
-
registerTool('
|
|
609
|
+
registerTool('vibe_v4_configure','Create/configure a project: set project name, problem, and params WITHOUT starting a run. Use this FIRST, then vibe_v4_start to actually spawn residents.',objParams({project:{type:'string'},problem:{type:'string'},params:{type:'object'}}),(s,a)=>s.configure(a))
|
|
610
|
+
registerTool('vibe_v4_start','Start V4: spawn N resident subagents (brainstorm then self-organize).',objParams({problem:{type:'string'},residentCount:{type:'integer'},seedDirections:{type:'array',items:{type:'string'}}}),(s,a)=>s.start(a))
|
|
584
611
|
registerTool('vibe_v4_resume','Resume a persisted V4 run.',objParams({}),(s)=>s.resume())
|
|
585
612
|
registerTool('vibe_v4_pause','Pause V4.',objParams({}),(s)=>s.setPause())
|
|
586
613
|
registerTool('vibe_v4_abort','Abort V4 and interrupt residents.',objParams({}),(s)=>s.initAbort())
|
|
@@ -613,12 +640,13 @@ export function apply(ctx) {
|
|
|
613
640
|
|
|
614
641
|
commands.register({
|
|
615
642
|
name:'v4', description:'control the Vibe Math V4 framework',
|
|
616
|
-
input:{hint:'[start|resume|pause|abort|status|report|meeting|members|add|remove|set]'},
|
|
643
|
+
input:{hint:'[configure|start|resume|pause|abort|status|report|meeting|members|add|remove|set]'},
|
|
617
644
|
handler: async function(inv){
|
|
618
645
|
const s=getSession(inv&&inv.agent); if(!s) return {kind:'success',text:JSON.stringify({ok:false,error:'no session'})}
|
|
619
646
|
const line=String(inv&&inv.rawInput?inv.rawInput:'').trim(); const parts=line.split(/\s+/); const cmd=parts[0]||''; const rest=parts.slice(1)
|
|
620
647
|
let r
|
|
621
|
-
if(cmd==='
|
|
648
|
+
if(cmd==='configure') r=await s.configure({project:rest[0]||'', problem:parts.slice(2).join(' ')})
|
|
649
|
+
else if(cmd==='start') r=await s.start({})
|
|
622
650
|
else if(cmd==='resume') r=await s.resume()
|
|
623
651
|
else if(cmd==='pause') r=s.setPause()
|
|
624
652
|
else if(cmd==='abort') r=await s.initAbort()
|
|
@@ -628,7 +656,7 @@ export function apply(ctx) {
|
|
|
628
656
|
else if(cmd==='members') r={ok:true,residents:s.listResidents()}
|
|
629
657
|
else if(cmd==='add') r=await s.addMember(rest.join(' '))
|
|
630
658
|
else if(cmd==='remove') r=await s.removeMember(rest[0]||'')
|
|
631
|
-
else r={ok:false,usage:'start|resume|pause|abort|status|report|message|meeting|members|add|remove|set'}
|
|
659
|
+
else r={ok:false,usage:'configure|start|resume|pause|abort|status|report|message|meeting|members|add|remove|set'}
|
|
632
660
|
return {kind:'success',text:JSON.stringify(r,null,2)}
|
|
633
661
|
},
|
|
634
662
|
})
|
|
@@ -423,5 +423,44 @@ VibeMath/Projects/<project>/
|
|
|
423
423
|
### 4. 自组织优先,非固定模式约束
|
|
424
424
|
删除"typical actions"式枚举,改为"你自己决定做什么;优先级/分工由团队讨论决定"。仍保留 JSON 回复里 `propose_verify/propose_meeting/claim_task/voteSolved/solved` 作为框架可执行的**控制通道**,但讨论内容走 `input`/会议转发。
|
|
425
425
|
|
|
426
|
-
> 测试:`selfdrive-v4.mjs` 21/21;`e2e-v4-fixes.test.mjs`
|
|
426
|
+
> 测试:`selfdrive-v4.mjs` 21/21;`e2e-v4-fixes.test.mjs` 17/17(T5 提示词完整性、T6 群聊转发、T7 背景只讲一次)。
|
|
427
|
+
|
|
428
|
+
---
|
|
429
|
+
|
|
430
|
+
## 21. 基于真实测试的诊断修复(v1.3.8)
|
|
431
|
+
|
|
432
|
+
对一次真实 4 常驻 run(HRT 猜想)的会话记录做了全面诊断,修复以下违反哲学的问题:
|
|
433
|
+
|
|
434
|
+
### 1. 共识验证真正做到"全体一致"
|
|
435
|
+
此前 `finalizeVerify` 只看"投过票的人是否一致"——实测 `p-r1-04` 只有 r-1/r-3 两人投票(r-2/r-4 未投)却被判"全体一致为真"(2/4)。现改为:**只有当全体在册常驻都投了票(`verdicts` 覆盖全部 resident)才可能判"一致"**;否则进入辩论,或超轮后**保留为未定论(不回写 Verified)**。若某常驻一直忙/未投,则该对象**不会**被记为 Verified·真/假。
|
|
436
|
+
|
|
437
|
+
### 2. 会议必须全体发言
|
|
438
|
+
`continueMeetingRound` 改为按"是否已发言(`inputs` 覆盖全部 resident)"判定收口,而非按"是否被问过"。**只要还有常驻没发言,会议就继续等它**;`allSolved`(全票 solved→停止)也要求**全员发言且全票 true**。这样分工/停止表决不会被"缺席成员"带偏。
|
|
439
|
+
|
|
440
|
+
### 3. 背景只在第一轮讲一次(不再每轮重复,省上下文)
|
|
441
|
+
`contextBrief`(背景/使命/工作模式/文件与格式/工具/规则)现在**只在 `brainstormPrompt`(首轮)注入完整版一次**;之后的 normal/meeting/verify/CHECKPOINT 只用**极简的当前状态**(researcher id + 轮次 + 团队成员 + 通知 + JSON 回复),**不再重复那段长背景**,显著减少上下文占用。
|
|
442
|
+
|
|
443
|
+
### 4. 验证目标按"提出者"精确定位
|
|
444
|
+
`pendingVerify` 记录 `proposer`,`beginVerify` 存入 `targetOwner`;`findSourceRel` **优先在提出者的库里找**源卡(避免同名 id 跨常驻撞车,例如 r-3 的 `p-004` vs r-1 的 `p-r1-04`);验证提示里标注"(提出者 <owner>)"让常驻明确在验哪个对象。
|
|
445
|
+
|
|
446
|
+
### 5. 主代理放权(减少"主持人"指挥)
|
|
447
|
+
`agent.cordis.yml` persona 明确:**你的角色是让常驻自组织(hands-off)**。不要注入议程/优先级/分工/验证决定,不要指挥常驻;运行 `start` 后只读 `status/report`、在用户明确要求或团队明显僵死时才 `message`/`meeting`,且只做"促成",不做"决定"。
|
|
448
|
+
|
|
449
|
+
---
|
|
450
|
+
|
|
451
|
+
## 22. 进一步按哲学打磨(v1.3.9)
|
|
452
|
+
|
|
453
|
+
### 1. 会议议程来源确认(非 bug)
|
|
454
|
+
核查确认:之前担心的"主持人式"会议议程,其实是 **r-1 在它的汇报里 `propose_meeting` 字段给出的**,框架据此启动会议。属**常驻自组织发起会议**,符合哲学,无需改。(仅把 `finalizeMeeting` 的日志措辞从"not all spoke / not unanimous"改为准确的"no unanimous solved vote"。)
|
|
455
|
+
|
|
456
|
+
### 2. 压缩后重申核心规则(治"压缩遗忘规则")
|
|
457
|
+
常驻的背景/规则只在首轮讲一次;为避免真实 `/compact` 后常驻淡忘规则,现在**每次压缩触发时**(`needCompact`/达阈值)在提示开头**重申一段短的核心规则**(只有 Verified/ 算确立、验证须全组一致、只写自己/只读他人、任务分工团队决定、退出只输出 JSON),其余轮次仍保持极简。
|
|
458
|
+
|
|
459
|
+
### 3. 验证 `verdict` 明确为 0–1 正确概率
|
|
460
|
+
验证提示明确:`verdict` ∈ [0,1],**1=绝对为真(判真),0=绝对为假(判假),0.5=完全不确定**;"全体常驻一致判真(正确概率 verdict 为 1)或一致判假(正确概率 verdict 为 0)才算数"。框架把 `verdict` 解析为数值(>0.5→判真,<0.5→判假,=0.5→不确定),未全票时**留库附全组平均正确概率**;辩论录/源卡回写统一用该概率。向后兼容旧的 `"TRUE"/"FALSE"` 字符串。
|
|
461
|
+
|
|
462
|
+
### 4. 创建项目不再立即启动(先配置后启动)+ settings 文件 + 项目名
|
|
463
|
+
新增 **`vibe_v4_configure {project?, problem?, params?}`**:**只创建/配置项目(名称、问题、参数),不唤醒任何常驻**;参数持久化到 `State/settings.json`。之后 **`vibe_v4_start {problem?, residentCount?, seedDirections?}`** 才真正启动(若已配置问题可省略)。这样"先设好参数再启动",不再一创建就着急跑。`/v4 configure` 子命令 + 主代理 persona 的 `Main controls` 已同步(`vibe_v4_set` 也持久化到 settings 文件);支持设置**项目名**(`configure.project`)。
|
|
464
|
+
|
|
465
|
+
|
|
427
466
|
|