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.
@@ -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] [--pure] \
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
- - variant 缺省/'default'/'max' → 'max'(默认档,专业用户才改)
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 = "max" if (not variant or variant == "default") else variant
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 用默认 max)
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, "max") for p, m in (args.models or {}).items()}
311
- # default 模型 创建时实时获取 Pi 默认模型填入:
312
- # pi-agent.json model 后,meeting_loop 才会传 --model;
313
- # 骨架期 models.md 仍写 default(--spec-gen 不获取),创建时(--spec)
314
- # 才解析。运行期固化不变(环境自包含)。
315
- if spec_dir:
316
- dm = _default_model()
317
- if dm:
318
- for p in participants:
319
- if p not in models or models[p][0] is None:
320
- models[p] = (dm, models.get(p, (None, "max"))[1])
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.pure, args.result_writer,
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.get(p, (None, "max"))
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] if mv[1] else "max",
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 '无'}, pure={args.pure}")
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("--pure", action="store_true", help="--pure 模式(禁外部插件)")
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.pure:
695
- cmd.append("--pure")
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:配额单一事实源;与 pure 处理一致)
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[, variant]`。model 默认 default(继承本机默认),
52
- variant 默认 max。只有不用默认/-max 时才需要改。
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/性能.md 全文——身份那句由脚本加,不在正文里):
80
+ 范例(agents/效率.md 全文——身份那句由脚本加,不在正文里;本例内容较长,
81
+ 要点是"把该视角盯住的东西逐项写明"):
82
+
83
+ 你的所有观点必须从运行效率角度出发:时间效率(一次分析从开始到收尾要
84
+ 多久、哪些环节在吃时间、哪些等待可消除)与运行效率(不必要的计算与
85
+ 等待、可并行而串行的部分、随规模增长的代价)。
86
+ 能用已有数据说出"省多少、占多少比例"就说;拿不到数据就写明需要什么
87
+ 数据,不要凭感觉下结论。
76
88
 
77
- 你的所有观点必须从性能角度出发:复杂度、热点、不必要的计算、扩展性。
78
- 如果其它视角的优化建议会显著损害性能,你应该明确反对并说明理由。
79
89
  其它视角由别的参与者负责,你不要越界展开。
80
90
  对其它视角的观点可以认同或反驳,但要用本视角的论据。
81
91