pi-multi-viewers 0.3.0 → 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 +23 -1
- package/README.md +7 -5
- package/docs/design.md +168 -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 +52 -0
- package/meeting_fs.py +49 -5
- package/meeting_loop.py +46 -24
- 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/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
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# pi-probe.sh —— LLM 探针(把临时 pi 运行变成**可追溯、经同意的测试产物**)
|
|
4
|
+
#
|
|
5
|
+
# 它管三件事(都是吃过的教训):
|
|
6
|
+
#
|
|
7
|
+
# 1. **闸门:没有当次同意就不跑**(2026-09-13 教训)
|
|
8
|
+
# 我在未征得用户同意的情况下连跑 6 个真实 pi 进程(合计 ~9.5 分钟,其中一个
|
|
9
|
+
# 458s),理由是"在后台跑、不占用户终端"。判据本应是**预估时长**(用户规则:
|
|
10
|
+
# 秒级冒烟免批;分钟级/多轮必须当次确认),且**不因后台运行而豁免**。
|
|
11
|
+
# 现在:不带 `--approved "<凭据>"` 直接**拒绝执行**并提示先去问。
|
|
12
|
+
#
|
|
13
|
+
# 2. **登记:跑过的 LLM 运行留下账本**
|
|
14
|
+
# `~/.pi/pi-multi-viewers-llm-runs.log` 每行一次运行:起止时间、时长、退出码、
|
|
15
|
+
# 凭据、命令摘要。汇报时给账本,不靠记忆。
|
|
16
|
+
#
|
|
17
|
+
# 3. **收尾提醒:跑完先汇报,再决定下一步**
|
|
18
|
+
# 结束时打印一行显式提醒——2026-09-13 的第二个错误正是"跑完没汇报就接着跑
|
|
19
|
+
# 第二批实验"。
|
|
20
|
+
#
|
|
21
|
+
# 另外它把新建的 session 登记进 `~/.pi/pi-multi-viewers-test-sessions.log`
|
|
22
|
+
# (与 build_bootstrap 同一份),使 check-residue 能判定归属(否则白名单 cwd
|
|
23
|
+
# 下的探针 session 完全不可见)。
|
|
24
|
+
#
|
|
25
|
+
# 用法:
|
|
26
|
+
# ./scripts/pi-probe.sh --approved "用户 2026-09-13 15:20 同意跑 AFT 隔离实验" \
|
|
27
|
+
# --print "ok"
|
|
28
|
+
# ./scripts/pi-probe.sh --approved "..." --no-extensions --print "ok"
|
|
29
|
+
#
|
|
30
|
+
# 退出码 = pi 的退出码(闸门拒绝时为 2)。
|
|
31
|
+
set -u
|
|
32
|
+
|
|
33
|
+
SESS_DIR="$HOME/.pi/agent/sessions"
|
|
34
|
+
REGISTRY="$HOME/.pi/pi-multi-viewers-test-sessions.log"
|
|
35
|
+
LEDGER="$HOME/.pi/pi-multi-viewers-llm-runs.log"
|
|
36
|
+
|
|
37
|
+
usage() {
|
|
38
|
+
cat >&2 <<'EOS'
|
|
39
|
+
用法: pi-probe.sh --approved "<凭据>" [pi 参数...]
|
|
40
|
+
|
|
41
|
+
--approved "<凭据>" 必填:用户**当次**同意的凭据(原话/时间/授权范围)。
|
|
42
|
+
没有它就说明还没问——先去问,不要绕过这里直接调 pi。
|
|
43
|
+
|
|
44
|
+
判据(用户规则):预估**时长**——秒级冒烟免批;预计 ≥30s、多轮唤醒、
|
|
45
|
+
整场分析一律**当次**确认,且不因"后台跑、不占用户终端"豁免。
|
|
46
|
+
EOS
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
APPROVED=""
|
|
50
|
+
if [ "$#" -gt 0 ] && [ "$1" = "--approved" ]; then
|
|
51
|
+
APPROVED="${2:-}"
|
|
52
|
+
shift 2 2>/dev/null || true
|
|
53
|
+
fi
|
|
54
|
+
if [ -z "$APPROVED" ]; then
|
|
55
|
+
echo "拒绝执行:没有 --approved(= 未取得用户当次同意)。" >&2
|
|
56
|
+
usage
|
|
57
|
+
exit 2
|
|
58
|
+
fi
|
|
59
|
+
if [ "$#" -eq 0 ]; then
|
|
60
|
+
echo "拒绝执行:缺少 pi 参数。" >&2
|
|
61
|
+
usage
|
|
62
|
+
exit 2
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
cmd_brief="pi $*"
|
|
66
|
+
|
|
67
|
+
BEFORE="$(mktemp)"
|
|
68
|
+
AFTER="$(mktemp)"
|
|
69
|
+
trap 'rm -f "$BEFORE" "$AFTER"' EXIT
|
|
70
|
+
find "$SESS_DIR" -name '*.jsonl' -print 2>/dev/null | sort > "$BEFORE"
|
|
71
|
+
|
|
72
|
+
T0=$(date +%s)
|
|
73
|
+
pi "$@"
|
|
74
|
+
rc=$?
|
|
75
|
+
T1=$(date +%s)
|
|
76
|
+
|
|
77
|
+
# 账本(运行即登记:时长 / 退出码 / 凭据 / 命令摘要)
|
|
78
|
+
python3 - "$LEDGER" "$T0" "$T1" "$rc" "$APPROVED" "$cmd_brief" <<'PYEOF'
|
|
79
|
+
import json, sys
|
|
80
|
+
from datetime import datetime, timezone
|
|
81
|
+
ledger, t0, t1, rc, approved, cmd = sys.argv[1:7]
|
|
82
|
+
rec = {
|
|
83
|
+
"started": datetime.fromtimestamp(int(t0), timezone.utc).isoformat(),
|
|
84
|
+
"seconds": int(t1) - int(t0),
|
|
85
|
+
"rc": int(rc),
|
|
86
|
+
"approved": approved,
|
|
87
|
+
"cmd": cmd[:400],
|
|
88
|
+
}
|
|
89
|
+
with open(ledger, "a", encoding="utf-8") as f:
|
|
90
|
+
f.write(json.dumps(rec, ensure_ascii=False) + "\n")
|
|
91
|
+
print(f"[pi-probe] 账本已记:{rec['seconds']}s rc={rec['rc']} | 同意凭据:{approved[:60]}")
|
|
92
|
+
PYEOF
|
|
93
|
+
|
|
94
|
+
# session 登记(归属判定用)
|
|
95
|
+
find "$SESS_DIR" -name '*.jsonl' -print 2>/dev/null | sort > "$AFTER"
|
|
96
|
+
NEW=$(comm -13 "$BEFORE" "$AFTER")
|
|
97
|
+
if [ -n "$NEW" ]; then
|
|
98
|
+
echo "$NEW" | while IFS= read -r f; do
|
|
99
|
+
[ -n "$f" ] || continue
|
|
100
|
+
python3 - "$f" "$REGISTRY" <<'PYEOF'
|
|
101
|
+
import json, os, sys
|
|
102
|
+
from datetime import datetime, timezone
|
|
103
|
+
path, registry = sys.argv[1], sys.argv[2]
|
|
104
|
+
sid = cwd = ""
|
|
105
|
+
with open(path, encoding="utf-8") as f:
|
|
106
|
+
for line in f:
|
|
107
|
+
try:
|
|
108
|
+
ev = json.loads(line)
|
|
109
|
+
except ValueError:
|
|
110
|
+
continue
|
|
111
|
+
if ev.get("type") == "session":
|
|
112
|
+
sid = ev.get("id") or ""
|
|
113
|
+
cwd = ev.get("cwd") or ""
|
|
114
|
+
break
|
|
115
|
+
rec = {
|
|
116
|
+
"created": datetime.now(timezone.utc).isoformat(),
|
|
117
|
+
"session_id": sid,
|
|
118
|
+
"path": os.path.abspath(path),
|
|
119
|
+
"cwd": cwd,
|
|
120
|
+
"origin": "pi-probe",
|
|
121
|
+
}
|
|
122
|
+
with open(registry, "a", encoding="utf-8") as f:
|
|
123
|
+
f.write(json.dumps(rec, ensure_ascii=False) + "\n")
|
|
124
|
+
print(f"[pi-probe] session 已登记: {path}")
|
|
125
|
+
print(f"[pi-probe] session_id={sid} cwd={cwd}(用完删掉该文件)")
|
|
126
|
+
PYEOF
|
|
127
|
+
done
|
|
128
|
+
else
|
|
129
|
+
echo "[pi-probe] 未新建 session(用了 --session/--session-id 续接既有会话?)"
|
|
130
|
+
fi
|
|
131
|
+
|
|
132
|
+
# 收尾提醒(2026-09-13 教训:跑完先汇报,别接着跑下一批)
|
|
133
|
+
echo "[pi-probe] ⚠ 先把本次结果汇报给用户并停下等他指示——不要连续追加第二批实验。"
|
|
134
|
+
exit "$rc"
|
package/spec_gen.py
CHANGED
|
@@ -22,7 +22,7 @@ PI_AGENT_DIR = os.environ.get("PI_CODING_AGENT_DIR",
|
|
|
22
22
|
MAX_AGENT_NAME_LEN = 32
|
|
23
23
|
|
|
24
24
|
import meeting_fs
|
|
25
|
-
from meeting_fs import run_git, DEFAULT_STALL_TIMEOUT
|
|
25
|
+
from meeting_fs import run_git, DEFAULT_STALL_TIMEOUT, DEFAULT_THINKING
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
def _join_model_ref(provider, model_id):
|
|
@@ -276,24 +276,27 @@ def gen_spec_skeleton(spec_dir, participants, topic=None, background=None,
|
|
|
276
276
|
"本行是说明行,不会注入。\n\n")
|
|
277
277
|
if background:
|
|
278
278
|
f.write(background + "\n")
|
|
279
|
-
# models.md(用户 8024/9204/9271:预列各 agent,每行 agent名: model
|
|
280
|
-
# variant
|
|
281
|
-
#
|
|
279
|
+
# models.md(用户 8024/9204/9271:预列各 agent,每行 agent名: model,
|
|
280
|
+
# variant;model/thinking 预填主 pi 当前值,用户少改一个文件)
|
|
281
|
+
# **两个槽都永远显式写出**(含探测失败的路径):variant 槽留空会静默落到
|
|
282
|
+
# DEFAULT_THINKING,而 spec 文件表面完全正常(甚至更"干净")——意图与
|
|
283
|
+
# 生效值之间没有留痕(e2e17 评审 §7.3)。探测失败另打一行可见提示。
|
|
282
284
|
pm, pt = _detect_pi_model_thinking()
|
|
285
|
+
variant = pt or DEFAULT_THINKING
|
|
283
286
|
with open(os.path.join(spec_dir, "models.md"), "w") as f:
|
|
284
|
-
lines = ["# models.md——模型配置(可选)。每行:agent名: model
|
|
285
|
-
"model
|
|
287
|
+
lines = ["# models.md——模型配置(可选)。每行:agent名: model, variant。"
|
|
288
|
+
"model 写 default = 继承本机默认;variant 不写 = "
|
|
289
|
+
f"{DEFAULT_THINKING}(**两个槽都显式写出**,一眼可见)。"
|
|
286
290
|
"本行是说明行,不会注入。"]
|
|
287
291
|
for p in participants:
|
|
288
|
-
|
|
289
|
-
lines.append(f"{p}: {pm}, {pt}")
|
|
290
|
-
elif pm:
|
|
291
|
-
lines.append(f"{p}: {pm}")
|
|
292
|
-
elif pt:
|
|
293
|
-
lines.append(f"{p}: default, {pt}")
|
|
294
|
-
else:
|
|
295
|
-
lines.append(f"{p}: default")
|
|
292
|
+
lines.append(f"{p}: {pm or 'default'}, {variant}")
|
|
296
293
|
f.write("\n".join(lines) + "\n")
|
|
294
|
+
if not pt:
|
|
295
|
+
# 探测失败**可见**(不是静默取档):打印在使用者能看到的地方,
|
|
296
|
+
# 不阻断(终端直用时 PI_* 环境变量本就不存在,报错会断掉合法路径)。
|
|
297
|
+
print(f"[spec-gen] 未探测到主 pi 的 thinking 档位——models.md 用默认 "
|
|
298
|
+
f"{DEFAULT_THINKING}(如需其它档位请直接编辑该文件)",
|
|
299
|
+
file=sys.stderr)
|
|
297
300
|
# agents/X.md 占位 + .order(仅显式 --agents 时;快照路径的 .order
|
|
298
301
|
# 由 _snapshot_viewers 写入,此处不得重写)
|
|
299
302
|
if participants and not viewers_dir:
|
|
@@ -367,7 +370,7 @@ def gen_question(topic, stances, background, questions):
|
|
|
367
370
|
return "\n".join(lines)
|
|
368
371
|
|
|
369
372
|
|
|
370
|
-
def gen_protocol(topic, participants, max_meeting, max_rr,
|
|
373
|
+
def gen_protocol(topic, participants, max_meeting, max_rr, extensions=False,
|
|
371
374
|
result_writer=None,
|
|
372
375
|
stall_timeout=DEFAULT_STALL_TIMEOUT,
|
|
373
376
|
fork_source=None, fork_cwd=None,
|
|
@@ -385,8 +388,8 @@ def gen_protocol(topic, participants, max_meeting, max_rr, pure=False,
|
|
|
385
388
|
"stallTimeoutSeconds": stall_timeout,
|
|
386
389
|
"commitPolicy": "one-message-per-commit",
|
|
387
390
|
}
|
|
388
|
-
|
|
389
|
-
|
|
391
|
+
# 显式写出扩展策略(默认零扩展 = agents 不加载任何外部扩展)
|
|
392
|
+
proto["extensions"] = bool(extensions)
|
|
390
393
|
if fork_source:
|
|
391
394
|
# fork 模式(多视角):首唤挂载主 session + cwd=主项目
|
|
392
395
|
# forkMode 取值域与默认值的定义在 meeting_fs(FORK_MODES /
|
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
|
|