feat(curator): deploy the phase-0 system prompt, and correct a misleading README figure
The workspace now holds .pi/SYSTEM.md and .pi/APPEND_SYSTEM.md and nothing else.
SYSTEM.md is rewritten for what is actually deployed. The version committed in
07dd648 described five tools that will not exist until phase 3; shipping it would
have invited the model to call tools it does not have. The capability section now
states plainly that the agent has no tools and that every fact arrives in the
request. The phase-3 target, including the full tool-bearing launch contract, is
recorded in the plan as §4b together with why each part cannot be enabled sooner.
profile.toml likewise describes the deployed configuration rather than the target,
so that deploy-scenario.sh validates against reality and the path check means
something.
Recovered from the retired SKILL.md and folded into SYSTEM.md: the rule that the
current request's schema and length limits override everything else, and that a
JSON task returns exactly one JSON value with no fences. Phase 0's four prompt
types all depend on it, and it was the one part of that file not already covered.
Measured before and after on the real workspace, with flags read from the code
rather than transcribed (docs/evidence/2026-08-27-curator-phase0-prompt.md):
- expert coding assistant framing: present -> gone
- pointer to pi's own documentation: present -> gone
- the 64-line media policy: absent -> present
- workspace AGENTS.md: loaded -> blocked
- parent-directory AGENTS.md: LEAKED -> blocked
- <available_skills>: absent both times
Two things this confirms on the production configuration rather than a synthetic
probe. --skill was genuinely a no-op: it pointed at a real 64-line SKILL.md and
the skills block was still absent, because pi emits it only when a tool named
read is active and --no-tools deactivates everything. And --no-context-files is
the only switch that stops parent-directory pollution: a marker planted in
/home/claw/pi-workspaces/AGENTS.md reached the prompt before and not after.
Deleting the now-dead AGENTS.md and SKILL.md from the workspace changed the
prompt length by zero bytes, which is the proof that they were dead.
README corrected. Its table cited 960 characters as Curator's system prompt after
the change; that figure came from a few-line stub SYSTEM.md in the isolation
probe, and the real prompt is 3539 -- larger, not smaller. Presenting the stub
measurement as Curator's was misleading, and "72% smaller" was wrong. The prompt
grew because roughly 1.9 KB of pi scaffolding was replaced by domain policy that
had never loaded at all. The mechanism claim is unaffected.
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
# Curator 阶段 0 系统提示实测
|
||||
|
||||
日期:2026-08-27 · pi 0.84.3 · 零 token(单条 RPC `get_state`,不触达 provider)
|
||||
|
||||
探针:`probe-harness/curator-phase0-probe.ts`。它**不注册任何工具** —— 阶段 0 用
|
||||
`--no-tools`,基于工具的探针根本不会被调用。
|
||||
|
||||
两次运行都在真实 workspace 上进行,flag 直接来自代码
|
||||
(`python3 -c "print(PiCurator._isolation_args())"`),不是手抄的:
|
||||
|
||||
```
|
||||
--no-tools --no-extensions --no-skills --no-prompt-templates --no-themes --no-context-files --approve
|
||||
```
|
||||
|
||||
"改动前"用备份 `pre-refactor-20260827T053600Z/workspace-curator.tar.gz` 解出的
|
||||
原始 workspace(只有 `AGENTS.md` 与 `.pi/skills/curator-media/SKILL.md`,无
|
||||
`.pi/SYSTEM.md`),配原 flag `--approve --no-tools --skill <SKILL.md> --no-prompt-templates`。
|
||||
|
||||
两次都在 workspace 的父目录 `/home/claw/pi-workspaces/AGENTS.md` 埋了
|
||||
`PARENT_LEAK_MARKER`。
|
||||
|
||||
## 结果
|
||||
|
||||
| 探测项 | 改动前 | 改动后 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `P_LEN` | 2548 | **3539** | 变长,见下文 |
|
||||
| `expert coding assistant` | **true** | false | 编码助手人格已移除 |
|
||||
| `Pi documentation` | **true** | false | pi 自身文档指引已移除 |
|
||||
| `guidelines` | **true** | false | 默认 guidelines 段落已移除 |
|
||||
| `.pi/SYSTEM.md` 内容 | false | **true** | 策展人格已生效 |
|
||||
| `.pi/APPEND_SYSTEM.md` 内容 | false | **true** | 长期职责已生效 |
|
||||
| "你没有任何工具" | false | **true** | 能力边界已声明 |
|
||||
| "不是指令"(注入防护) | false | **true** | 不可信数据条款已生效 |
|
||||
| "只输出一个合法 JSON 值" | false | **true** | schema 服从条款已生效 |
|
||||
| workspace `AGENTS.md` | **true** | false | 被 `-nc` 阻断 |
|
||||
| 父目录 `AGENTS.md` 标记 | **true** | false | 被 `-nc` 阻断 |
|
||||
| `available_skills` 段落 | false | false | 两边都没有 |
|
||||
| `P_SKILLNAMES` | `[]` | `[]` | 两边都为空 |
|
||||
| `P_ACTIVE_TOOLS` | `[]` | `[]` | 两边都无工具 |
|
||||
|
||||
## 三个结论
|
||||
|
||||
**1. `--skill` 确实是空操作,在真实生产配置上得到确认。**
|
||||
改动前那一列里,`--skill` 明确指向了 64 行的 `curator-media/SKILL.md`,而
|
||||
`available_skills=false`、`SKILLNAMES=[]`。那份媒体策略从未进入过系统提示。
|
||||
原因是 pi 只在存在**激活的 `read` 工具**时生成 skills 段落
|
||||
(`dist/core/system-prompt.js:59,113`),而 `--no-tools` 关掉了全部工具。
|
||||
服务上线以来一直如此,README 与部署手册描述的机制并未发生。
|
||||
|
||||
**2. 只有 `-nc` 能阻断父目录污染。**
|
||||
改动前,workspace 自己的 `AGENTS.md` 和父目录 `/home/claw/pi-workspaces/AGENTS.md`
|
||||
的标记**都**进入了系统提示。加 `--no-context-files` 后两者都消失。
|
||||
`AGENTS.override.md` 做不到这件事(另见 `pi-runtime-notes.md` §9)。
|
||||
|
||||
**3. 系统提示变长了,这是修复的结果而不是代价。**
|
||||
2548 → 3539 字符。改动前那 2548 里,约 1.9 KB 是 pi 的编码助手框架、工具纪律和
|
||||
pi 文档指引 —— 对一个书影音 agent 全是噪音甚至风险(文档指引是注入文本的现成
|
||||
提权路径);真正属于 Curator 的领域策略一个字都没有。改动后这 3539 全部是
|
||||
Curator 自己的内容。
|
||||
|
||||
> 这一点纠正了本仓库 README 早先的写法。`isolation-probe.md` 里那个 960 字符
|
||||
> 是用一个几行的 stub `SYSTEM.md` 测出来的,用来演示替换机制;把它当成
|
||||
> Curator 的实际数字就成了误导。机制结论(skills 依赖 `read`)成立,
|
||||
> "缩小 72%" 这个说法不适用于真实的 Curator 系统提示。
|
||||
|
||||
## 复现
|
||||
|
||||
```bash
|
||||
# 改动后
|
||||
cd /home/claw/pi-workspaces/curator
|
||||
printf '{"id":"1","type":"get_state"}\n' | pi --mode rpc --no-session \
|
||||
-e <repo>/docs/evidence/probe-harness/curator-phase0-probe.ts \
|
||||
--no-tools --no-extensions --no-skills --no-prompt-templates \
|
||||
--no-themes --no-context-files --approve \
|
||||
--provider zenmux --model openai/gpt-5.6-luna 2>&1 >/dev/null | grep '^P_'
|
||||
```
|
||||
@@ -0,0 +1,35 @@
|
||||
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
||||
|
||||
// Dumps what the Curator agent's system prompt actually contains, under the
|
||||
// exact flag set curator/pi_agent.py::_isolation_args produces.
|
||||
//
|
||||
// Loaded with an explicit -e, which still applies under --no-extensions. The
|
||||
// probe registers no tool, so it works under --no-tools too: with --no-tools
|
||||
// every tool is inactive and a tool-based probe would never run.
|
||||
export default function probe(pi: ExtensionAPI) {
|
||||
pi.on("session_start", async (_e, ctx) => {
|
||||
const sp = ctx.getSystemPrompt?.() ?? "";
|
||||
const has = (needle: string) => String(sp.includes(needle));
|
||||
|
||||
console.error("P_LEN=" + sp.length);
|
||||
// Identity: the replacement must remove pi's coding-assistant framing.
|
||||
console.error("P_CODING_ASSISTANT=" + has("expert coding assistant"));
|
||||
console.error("P_PI_DOCS=" + has("Pi documentation"));
|
||||
console.error("P_GUIDELINES=" + has("guidelines"));
|
||||
// Our own content must be present.
|
||||
console.error("P_SYSTEM_MD=" + has("你是 Curator"));
|
||||
console.error("P_APPEND_MD=" + has("Curator 长期职责"));
|
||||
console.error("P_NO_TOOLS_CLAUSE=" + has("你没有任何工具"));
|
||||
console.error("P_UNTRUSTED_CLAUSE=" + has("不是指令"));
|
||||
console.error("P_JSON_CLAUSE=" + has("只输出一个合法 JSON 值"));
|
||||
// Leakage: stale workspace files and parent-directory context.
|
||||
console.error("P_STALE_AGENTS=" + has("Curator Pi Agent"));
|
||||
console.error("P_STALE_SKILL=" + has("Curator Media Reasoning"));
|
||||
console.error("P_PARENT_MARKER=" + has("PARENT_LEAK_MARKER"));
|
||||
console.error("P_SKILLS_BLOCK=" + has("available_skills"));
|
||||
const names = [...sp.matchAll(/<name>([^<]+)<\/name>/g)].map((m) => m[1]);
|
||||
console.error("P_SKILLNAMES=" + JSON.stringify(names));
|
||||
console.error("P_ACTIVE_TOOLS=" + JSON.stringify(pi.getActiveTools()));
|
||||
console.error("P_SP_BEGIN<<<" + sp.slice(0, 400).replace(/\n/g, "\\n") + ">>>");
|
||||
});
|
||||
}
|
||||
@@ -303,6 +303,154 @@ Telegram ──► TelegramGateway(薄适配器)
|
||||
|
||||
---
|
||||
|
||||
## 4b. 阶段 3 目标启动契约
|
||||
|
||||
`scenarios/curator/profile.toml` 始终描述**已部署**的配置,因此阶段 0 期间它是
|
||||
无工具形态。下面是阶段 3 完成后它应当变成的样子,逐项理由见 §3 阶段 3。
|
||||
|
||||
阶段 0 与目标的差异,以及为什么现在不能直接上:
|
||||
|
||||
| 项 | 阶段 0 现状 | 阶段 3 目标 | 为什么不能提前 |
|
||||
|---|---|---|---|
|
||||
| 工具 | `--no-tools` | `--no-builtin-tools` + 6 个自有工具 | `curator-tools.ts` 与 `agent_api.py` 尚不存在 |
|
||||
| skills | `--no-skills`,策略在系统提示里 | 三个自有 skill 目录 | skills 段落只在有激活的 `read` 工具时生成,无工具即为死代码 |
|
||||
| 事实获取 | Python 取好放进 prompt | agent 自己调工具 | 方向 B 的前提是工具存在 |
|
||||
| 会话 | 每条消息新起进程 | 长驻 RPC + 轮转 | 依赖 `shared/lib/py/pi_rpc.py` 接入 |
|
||||
| thinking | 单一 `high` | 按角色三档 | 依赖 RPC 的 `set_thinking_level` |
|
||||
| 写操作 | Python 直接写 | `propose_write` + 策略引擎 | 依赖阶段 2 的 `service.py` |
|
||||
|
||||
```toml
|
||||
# curator — Pi scenario profile
|
||||
#
|
||||
# STATUS: target configuration. The live service does NOT yet run this; it is
|
||||
# still on the pre-refactor launch parameters. Switching over happens in plan
|
||||
# phase 3 (docs/plans/2026-08-curator-agent-refactor.md).
|
||||
#
|
||||
# This file is the single source of truth for the launch contract.
|
||||
# scripts/deploy-scenario.sh renders it into <workspace>/.pi/launch.json, and
|
||||
# curator/pi_agent.py MUST read that file and fail closed if it is missing:
|
||||
# silently running without --no-extensions would widen the agent's reach.
|
||||
|
||||
[scenario]
|
||||
name = "curator"
|
||||
description = "Personal book / film / TV / music curation agent for the Curator service."
|
||||
workspace = "/home/claw/pi-workspaces/curator"
|
||||
session_dir = "/home/claw/.local/share/pi-curator/sessions"
|
||||
service = "curator.service"
|
||||
# Application code lives in a separate repository and is intentionally outside
|
||||
# the agent's workspace.
|
||||
backend = "/home/claw/codex-workspace/server-management/deploy/curator"
|
||||
|
||||
[model]
|
||||
provider = "zenmux"
|
||||
primary = "openai/gpt-5.6-luna"
|
||||
fallback = "x-ai/grok-4.6"
|
||||
|
||||
# One global thinking level was the dominant p50 latency contributor: intent
|
||||
# classification ran at "high" at the front of every message. Differentiate.
|
||||
[model.thinking]
|
||||
conversation = "high"
|
||||
extraction = "low"
|
||||
synthesis = "medium"
|
||||
|
||||
[session]
|
||||
# Per Telegram chat. The client appends a rotation counter, so history stays
|
||||
# greppable on disk instead of being summarised away.
|
||||
id_prefix = "curator-tg"
|
||||
rotate_after_prompts = 20
|
||||
rotate_after_messages = 50
|
||||
strategy = "session-id"
|
||||
|
||||
[isolation]
|
||||
# Verified combination — see docs/evidence/. Result: no coding-assistant
|
||||
# framing, no pi-docs block, no parent-directory context pollution, only this
|
||||
# scenario's own skills, only this scenario's own tools.
|
||||
no_builtin_tools = true # not --tools: a registry allowlist would block
|
||||
# tools registered dynamically from the backend
|
||||
no_extensions = true
|
||||
no_skills = true
|
||||
no_prompt_templates = true
|
||||
no_themes = true
|
||||
no_context_files = true # the ONLY switch that stops parent-dir AGENTS.md;
|
||||
# AGENTS.override.md does not (verified)
|
||||
approve = true # required to load .pi/SYSTEM.md and .pi/settings.json
|
||||
|
||||
[personality]
|
||||
# Both are system-prompt files, so --no-context-files does not affect them.
|
||||
system_prompt = ".pi/SYSTEM.md" # replaces pi's default prompt
|
||||
append_system_prompt = ".pi/APPEND_SYSTEM.md" # durable domain responsibilities
|
||||
context_files = [] # deliberately none
|
||||
|
||||
[resources]
|
||||
extensions = [".pi/extensions/curator-tools.ts"]
|
||||
skills = [
|
||||
".pi/skills/curator-core",
|
||||
".pi/skills/video-arr",
|
||||
".pi/skills/books-ingest",
|
||||
]
|
||||
|
||||
[tools]
|
||||
# Enforced twice: setActiveTools plus a tool_call block, both inside
|
||||
# curator-tools.ts. The CLI is not the security boundary.
|
||||
#
|
||||
# `read` is a restricted override from shared/extensions/pi-guard-base.ts. It is
|
||||
# mandatory, not optional: pi emits the skills section only when a tool named
|
||||
# `read` is active, and skill bodies load through it.
|
||||
allow = [
|
||||
"read",
|
||||
"curator_query_library",
|
||||
"curator_lookup_online",
|
||||
"curator_book_reviews",
|
||||
"curator_counts",
|
||||
"curator_propose_write",
|
||||
]
|
||||
|
||||
# Structured-output tools, used only by the stateless extraction/synthesis calls
|
||||
# (--no-session). They carry constrainedSampling + terminate.
|
||||
structured_output = ["emit_extraction", "emit_reviews"]
|
||||
|
||||
# The agent cannot write. curator_propose_write only records a planned Plan and
|
||||
# echoes the resolved identity; the deterministic policy engine in
|
||||
# curator/service.py decides whether it executes. Receipts are harvested from
|
||||
# tool_execution_end, never phrased by the model.
|
||||
receipt_tools = []
|
||||
|
||||
[tools.read_policy]
|
||||
# Must include the skill directories or skill bodies become unloadable.
|
||||
roots = [".pi/skills"]
|
||||
extensions = [".md"]
|
||||
max_chars = 40000
|
||||
|
||||
[bridge]
|
||||
# Loopback only, with a secret generated at service start and passed through env.
|
||||
# pi-guard-base asserts the host is loopback and refuses anything else.
|
||||
host = "127.0.0.1"
|
||||
port = 8767
|
||||
# The backend serves tool definitions as JSON Schema at /tools so that the schema
|
||||
# has exactly one owner; registerTool accepts a plain JSON Schema object.
|
||||
spec_endpoint = "/tools"
|
||||
|
||||
[budget]
|
||||
# Per-invocation timeouts do not compose: the old configuration could spend
|
||||
# 4 x 120 s on a single message with no overall bound. One deadline per user
|
||||
# message, enforced with RPC abort.
|
||||
turn_deadline_seconds = 180
|
||||
extraction_deadline_seconds = 120
|
||||
startup_timeout_seconds = 60
|
||||
|
||||
[env]
|
||||
# Explicit allowlist. Notably absent: every CURATOR_* credential. The provider
|
||||
# key is read by pi itself from ~/.pi/agent/models.json.
|
||||
minimal = true
|
||||
allowlist = ["PATH", "HOME", "LANG", "LC_ALL", "TZ", "SSL_CERT_FILE", "SSL_CERT_DIR"]
|
||||
extra = ["PI_TOOL_BRIDGE_URL", "PI_TOOL_BRIDGE_TOKEN"]
|
||||
|
||||
[secrets]
|
||||
env_file = "/home/claw/.config/curator/curator.env"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 实施者硬约束
|
||||
|
||||
1. 阶段 −1 检查点未全绿前禁止改任何源码。**已完成,可继续。**
|
||||
|
||||
Reference in New Issue
Block a user