pi-multi-viewers 0.2.2 → 0.4.0
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/AGENTS.md +26 -3
- package/README.md +7 -5
- package/docs/design.md +182 -2
- package/docs/reviews/2026-09-12-e2e17-thinking-level-analysis.md +374 -0
- package/docs/reviews/2026-09-13-e2e19-scoped-config-review.md +126 -0
- package/docs/reviews/2026-09-13-e2e20-pure-run-review.md +159 -0
- package/docs/reviews/2026-09-13-e2e21-postfix-review.md +257 -0
- package/docs/reviews/2026-09-13-e2e23-time-breakdown-analysis.md +175 -0
- package/docs/reviews/README.md +7 -2
- package/docs/test-methodology.md +100 -0
- package/fake_agent.py +11 -3
- package/meeting_fs.py +49 -5
- package/meeting_loop.py +46 -24
- package/mv_cli.py +363 -0
- package/observability.py +351 -29
- package/package.json +1 -1
- package/prompts/multi-viewers.md +1 -1
- package/scripts/check-residue.sh +39 -17
- package/scripts/mv.sh +10 -357
- package/scripts/pi-probe.sh +134 -0
- package/spec_gen.py +20 -17
- package/start_discussion.py +37 -24
- package/templates/spec-readme.md.tpl +17 -7
package/start_discussion.py
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
用法:
|
|
5
5
|
python3 start_discussion.py --dir mymeet --topic "主题" --agents a,b \
|
|
6
|
-
[--stances '{"a": "立场1", "b": "立场2"}'] [--start] [--
|
|
6
|
+
[--stances '{"a": "立场1", "b": "立场2"}'] [--start] [--extensions] \
|
|
7
7
|
[--models '{"a": "provider/model"}'] [--max-meeting 10] [--max-rr 7]
|
|
8
8
|
|
|
9
9
|
复杂内容用 spec 规格目录(设计 16,与 CLI 内容参数互斥):
|
|
@@ -70,8 +70,11 @@ def _spec_models(spec_dir, participants):
|
|
|
70
70
|
"""解析 models.md(容错,用户 8024/9204 定):返回 {agent: (model, variant)}。
|
|
71
71
|
|
|
72
72
|
每行格式:`agent名: model, variant`(model 与 variant 逗号分隔)。
|
|
73
|
-
- model 缺省/'default' → None
|
|
74
|
-
|
|
73
|
+
- model 缺省/'default' → None(创建时填本机默认模型)——`default`
|
|
74
|
+
这个别名**只在 model 槽有意义**
|
|
75
|
+
- variant 缺省 → DEFAULT_THINKING;**没有 `default` 别名**(同词在相邻
|
|
76
|
+
两行反义会让读者必错;且空已是缺省,别名不增加表达力)——写了 `default`
|
|
77
|
+
就按原值透传给 pi(可见失败,而非静默重解释)
|
|
75
78
|
容错:空行/无 ':'/agent 不在 participants → 跳过;单字段行只有 model。
|
|
76
79
|
规则:第一行说明跳过(_spec_read)。
|
|
77
80
|
"""
|
|
@@ -93,8 +96,13 @@ def _spec_models(spec_dir, participants):
|
|
|
93
96
|
parts = [p.strip() for p in rest.split(",")]
|
|
94
97
|
model = parts[0] if parts and parts[0] else ""
|
|
95
98
|
variant = parts[1] if len(parts) > 1 else ""
|
|
99
|
+
# `default` **只在 model 槽有意义**(= 继承本机)。variant 槽不做
|
|
100
|
+
# 同名别名(e2e17 评审 §7.2:相邻两行同词反义——model 的 default
|
|
101
|
+
# = 继承,variant 的 default = max,按上一行直觉读下一行必错);
|
|
102
|
+
# 且别名并不增加表达力:空 = max 已是缺省。写 `default` 不再是
|
|
103
|
+
# 别名 → 原值传给 pi(可见的失败,而不是静默重解释成 max)。
|
|
96
104
|
m = None if (not model or model == "default") else model
|
|
97
|
-
v =
|
|
105
|
+
v = variant or meeting_fs.DEFAULT_THINKING
|
|
98
106
|
out[agent] = (m, v)
|
|
99
107
|
return out
|
|
100
108
|
|
|
@@ -303,21 +311,23 @@ def setup_environment(args, participants, base, spec_dir=None,
|
|
|
303
311
|
for p in participants}
|
|
304
312
|
agent_extra = {k: v for k, v in agent_extra.items() if v}
|
|
305
313
|
# models:spec 模式从 models.md 读(自包含,{agent: (model, variant)}),
|
|
306
|
-
# CLI --models 已互斥({agent: model} 旧格式——variant
|
|
314
|
+
# CLI --models 已互斥({agent: model} 旧格式——variant 用默认档)
|
|
307
315
|
if spec_dir:
|
|
308
316
|
models = _spec_models(spec_dir, participants)
|
|
309
317
|
else:
|
|
310
|
-
models = {p: (m,
|
|
311
|
-
|
|
312
|
-
#
|
|
313
|
-
#
|
|
314
|
-
#
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
318
|
+
models = {p: (m, meeting_fs.DEFAULT_THINKING)
|
|
319
|
+
for p, m in (args.models or {}).items()}
|
|
320
|
+
# 归一:每个 participant 都有 (model, variant) 条目,**此后只读**——
|
|
321
|
+
# 此前 :320 补默认模型与 :384 写 pi-agent.json 各自再写一遍
|
|
322
|
+
# `models.get(p, (None, "max"))`(同层同义重复,值两处声明,e2e17
|
|
323
|
+
# 评审 §7.10)。
|
|
324
|
+
# default 模型 → 创建时实时获取 Pi 默认模型填入:pi-agent.json 带
|
|
325
|
+
# model 后,meeting_loop 才会传 --model;骨架期 models.md 仍写 default
|
|
326
|
+
# (--spec-gen 不获取),创建时(--spec)才解析。运行期固化不变。
|
|
327
|
+
dm = _default_model() if spec_dir else None
|
|
328
|
+
for p in participants:
|
|
329
|
+
m, v = models.get(p, (None, meeting_fs.DEFAULT_THINKING))
|
|
330
|
+
models[p] = (m or dm, v)
|
|
321
331
|
# stance_ref(agent 定义"立场见 question.md"提示):spec 模式一律保留
|
|
322
332
|
# (设计 16.6:无法程序判断 question.md 有无立场节 → 一律提示;
|
|
323
333
|
# 互斥下 CLI stances 必为 None,传占位 dict 触发生成)
|
|
@@ -340,7 +350,7 @@ def setup_environment(args, participants, base, spec_dir=None,
|
|
|
340
350
|
# 共享配置(work-a 提交,setup commit 进 bare)
|
|
341
351
|
with open(os.path.join(wa, "protocol.json"), "w") as f:
|
|
342
352
|
json.dump(gen_protocol(spec_topic or args.topic, participants, args.max_meeting,
|
|
343
|
-
args.max_rr, args.
|
|
353
|
+
args.max_rr, args.extensions, args.result_writer,
|
|
344
354
|
args.stall_timeout,
|
|
345
355
|
fork_source=getattr(args, "fork_source", None),
|
|
346
356
|
fork_cwd=os.getcwd(),
|
|
@@ -381,14 +391,14 @@ def setup_environment(args, participants, base, spec_dir=None,
|
|
|
381
391
|
with open(os.path.join(workdir, "AGENTS.md"), "w") as f:
|
|
382
392
|
f.write(gen_agents_md(args, p, participants, spec_background,
|
|
383
393
|
main_pi_cwd=os.getcwd()))
|
|
384
|
-
mv = models
|
|
394
|
+
mv = models[p] # 归一后必有条目(见上方归一循环)
|
|
385
395
|
with open(os.path.join(workdir, ".pi/agent", f"{p}.md"), "w") as f:
|
|
386
396
|
f.write(gen_agent_def(p, participants, {p: mv[0]} if mv[0] else None,
|
|
387
397
|
stances_arg, agent_extra.get(p)))
|
|
388
398
|
with open(os.path.join(workdir, "pi-agent.json"), "w") as f:
|
|
389
399
|
json.dump({
|
|
390
400
|
"model": mv[0] or "",
|
|
391
|
-
"thinking": mv[1]
|
|
401
|
+
"thinking": mv[1] or meeting_fs.DEFAULT_THINKING,
|
|
392
402
|
"prompt_file": f".pi/agent/{p}.md",
|
|
393
403
|
}, f, indent=2, ensure_ascii=False)
|
|
394
404
|
|
|
@@ -409,7 +419,8 @@ def setup_environment(args, participants, base, spec_dir=None,
|
|
|
409
419
|
rw = args.result_writer or participants[-1]
|
|
410
420
|
print(f"[setup] 环境就绪: {base}({len(participants)} agents: {', '.join(participants)})")
|
|
411
421
|
print(f"[setup] resultWriter={rw}, maxMeeting={args.max_meeting}, maxRR={args.max_rr}, "
|
|
412
|
-
f"立场={'有' if (args.stances or spec_dir) else '无'},
|
|
422
|
+
f"立场={'有' if (args.stances or spec_dir) else '无'}, "
|
|
423
|
+
f"extensions={args.extensions}")
|
|
413
424
|
|
|
414
425
|
|
|
415
426
|
def _preserve_result_md(base):
|
|
@@ -539,7 +550,9 @@ def main():
|
|
|
539
550
|
"protocol.json,各 agent 首唤由本地生成 fork "
|
|
540
551
|
"源挂载主上下文;不传 = 从主 pi 环境自动解析"
|
|
541
552
|
"(PI_SESSION_ID;解析失败明确报错)")
|
|
542
|
-
parser.add_argument("--
|
|
553
|
+
parser.add_argument("--extensions", action="store_true",
|
|
554
|
+
help="让 agents 加载外部扩展(默认零扩展:不加载任何"
|
|
555
|
+
"外部扩展/技能/prompt-template/主题)")
|
|
543
556
|
parser.add_argument("--start", action="store_true", help="创建后启动讨论")
|
|
544
557
|
parser.add_argument("--skip-setup", action="store_true",
|
|
545
558
|
help="跳过环境生成,只启动已有环境(需 --dir)")
|
|
@@ -691,12 +704,12 @@ def main():
|
|
|
691
704
|
workdir = os.path.join(base, f"work-{p}")
|
|
692
705
|
cmd = [sys.executable, os.path.join(base, "meeting_loop.py"),
|
|
693
706
|
workdir, p]
|
|
694
|
-
if args.
|
|
695
|
-
cmd.append("--
|
|
707
|
+
if args.extensions:
|
|
708
|
+
cmd.append("--extensions")
|
|
696
709
|
# 配额(max-meeting/max-rr/stall-timeout)是环境属性:创建时
|
|
697
710
|
# 固化在 protocol.json,启动继承(loop 读 protocol 优先)。
|
|
698
711
|
# 不传 CLI —— 避免无条件覆盖 protocol.json 的固化值
|
|
699
|
-
# (审核 C1:配额单一事实源;与
|
|
712
|
+
# (审核 C1:配额单一事实源;与 extensions 处理一致)
|
|
700
713
|
with open(os.path.join(base, f"loop-{p}.log"), "w") as f:
|
|
701
714
|
procs.append(subprocess.Popen(cmd, stdout=f,
|
|
702
715
|
stderr=subprocess.STDOUT,
|
|
@@ -42,14 +42,19 @@ fork 机制已让每个 agent 携带发起分析时的对话上下文(默认 b
|
|
|
42
42
|
|
|
43
43
|
- 分析只聚焦某些方面("不讨论 API 设计")
|
|
44
44
|
- 已知的硬约束("必须保持向后兼容")
|
|
45
|
-
- 用户指定的优先级("
|
|
45
|
+
- 用户指定的优先级("效率问题优先级最高")
|
|
46
46
|
|
|
47
47
|
没有就留空。
|
|
48
48
|
|
|
49
49
|
## models.md —— 模型配置(可选)
|
|
50
50
|
|
|
51
|
-
每行:`agent名: model
|
|
52
|
-
variant
|
|
51
|
+
每行:`agent名: model, variant`(**两个槽都显式写出**,一眼可见本场跑在
|
|
52
|
+
什么模型/档位上)。model 写 `default` = 继承本机默认;variant 不写 =
|
|
53
|
+
`max`。想换档位(如 `high`)改这一行即可——**逐 agent 一行**,可以只改
|
|
54
|
+
某一个视角。
|
|
55
|
+
|
|
56
|
+
> 这里写的就是**声明值**;实际生效值由 pi 解析(它自己的优先级链)。
|
|
57
|
+
> `--report` 会把声明值与 session 里的生效值对照列出。
|
|
53
58
|
|
|
54
59
|
## agents/X.md —— 视角任务书(每个 agent 一个)
|
|
55
60
|
|
|
@@ -64,7 +69,7 @@ variant 默认 max。只有不用默认/-max 时才需要改。
|
|
|
64
69
|
|
|
65
70
|
写好视角任务书的要点(实测有效的措辞模式):
|
|
66
71
|
|
|
67
|
-
1. **单一视角**:明确写出这个 agent 用什么 lenses
|
|
72
|
+
1. **单一视角**:明确写出这个 agent 用什么 lenses 看(效率/简单化/
|
|
68
73
|
安全/成本/用户体验/……),并要求"所有观点必须从该视角出发"
|
|
69
74
|
2. **不越界**:写明"其它视角由别的参与者负责,你不要越界展开"——
|
|
70
75
|
实验证明这句能避免视角串味(不要列举具体是哪几个视角——
|
|
@@ -72,10 +77,15 @@ variant 默认 max。只有不用默认/-max 时才需要改。
|
|
|
72
77
|
3. **交锋义务**:写明"对其它视角的观点可以认同或反驳,但要用本视角
|
|
73
78
|
的论据"——防止附和式讨论
|
|
74
79
|
|
|
75
|
-
范例(agents
|
|
80
|
+
范例(agents/效率.md 全文——身份那句由脚本加,不在正文里;本例内容较长,
|
|
81
|
+
要点是"把该视角盯住的东西逐项写明"):
|
|
82
|
+
|
|
83
|
+
你的所有观点必须从运行效率角度出发:时间效率(一次分析从开始到收尾要
|
|
84
|
+
多久、哪些环节在吃时间、哪些等待可消除)与运行效率(不必要的计算与
|
|
85
|
+
等待、可并行而串行的部分、随规模增长的代价)。
|
|
86
|
+
能用已有数据说出"省多少、占多少比例"就说;拿不到数据就写明需要什么
|
|
87
|
+
数据,不要凭感觉下结论。
|
|
76
88
|
|
|
77
|
-
你的所有观点必须从性能角度出发:复杂度、热点、不必要的计算、扩展性。
|
|
78
|
-
如果其它视角的优化建议会显著损害性能,你应该明确反对并说明理由。
|
|
79
89
|
其它视角由别的参与者负责,你不要越界展开。
|
|
80
90
|
对其它视角的观点可以认同或反驳,但要用本视角的论据。
|
|
81
91
|
|