@zihanw/pi-forge 0.1.0 → 0.3.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/README.md +354 -185
- package/README.zh-CN.md +453 -0
- package/examples/default-prompt-stack.json +54 -51
- package/examples/reviewer-prompt-stack.json +115 -0
- package/examples/sillytavern-dm-writer-prompt-stack.json +190 -0
- package/package.json +4 -8
- package/src/compiler.ts +588 -87
- package/src/index.ts +509 -140
- package/src/loader.ts +179 -12
- package/src/payload-capture.ts +85 -0
- package/src/policy.ts +42 -0
- package/src/regex.ts +500 -0
- package/src/sillytavern-importer.ts +484 -50
- package/src/stack-migration.ts +159 -0
- package/src/storage.ts +28 -0
- package/src/types.ts +83 -2
- package/src/web-editor/index.ts +2 -0
- package/src/web-editor/page.ts +2844 -0
- package/src/web-editor/server.ts +289 -0
- package/src/web-editor/types.ts +84 -0
- package/src/web-host.ts +229 -0
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
# pi-forge
|
|
2
|
+
|
|
3
|
+
[English](README.md) | [简体中文](README.zh-CN.md)
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
**pi-forge** 让你自定义 Pi 的思考方式和行为。它提供 prompt stack(提示栈):这些 JSON 文件可以替换、追加到或插入到 Pi 的默认系统提示词之前,并控制 AI 的性格、可见工具、对话历史布局、模板变量和 prompt 转换。
|
|
8
|
+
|
|
9
|
+
可以把它理解为 AI agent 的角色卡。
|
|
10
|
+
|
|
11
|
+
## 能做什么
|
|
12
|
+
|
|
13
|
+
- **赋予 Pi 个性** — 把它变成创意写手、角色扮演搭档、严格的代码审查员,或任何你想要的风格。
|
|
14
|
+
- **一键切换模式** — 在"写代码"、"写小说"、"做翻译"之间用一条命令切换。
|
|
15
|
+
- **控制 AI 看到什么** — 选择每个 prompt 中出现哪些工具、技能和项目上下文。
|
|
16
|
+
- **按栈限制工具和技能** — 为专注模式启用工具策略,并过滤技能可见性。
|
|
17
|
+
- **使用模板变量** — 定义 `{{char}}` / `{{user}}` 这样的静态值,并在 prompt 文本里使用 ST 风格的轮次/会话变量宏。
|
|
18
|
+
- **转换发出和最终消息文本** — 对选中的历史、最终编译 prompt 或已结束的 assistant 消息执行确定性 regex 替换。
|
|
19
|
+
- **导入 SillyTavern 预设** — 一条命令把 ST 角色预设迁移到 Pi。
|
|
20
|
+
- **调试 prompt** — 拦截并查看实际发给模型的内容。
|
|
21
|
+
|
|
22
|
+
## 快速上手
|
|
23
|
+
|
|
24
|
+
### 安装
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pi install npm:@zihanw/pi-forge
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### 第一个 prompt stack
|
|
31
|
+
|
|
32
|
+
从 [examples/default-prompt-stack.json](examples/default-prompt-stack.json) 创建 `.pi/forge/prompt-stacks/default.json`。
|
|
33
|
+
|
|
34
|
+
默认示例参考了 `@earendil-works/pi-coding-agent/dist/core/system-prompt.js` 中 Pi 自己的 prompt builder,但把它拆成可移动的 pi-forge slot:角色、工具、guidelines、Pi 文档提示、append-system-prompt、项目上下文、技能、日期/cwd 和对话历史。
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
mkdir -p .pi/forge/prompt-stacks
|
|
38
|
+
$EDITOR .pi/forge/prompt-stacks/default.json
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
把示例 JSON 粘贴进去。如果你就在这个仓库里开发,也可以直接执行 `cp examples/default-prompt-stack.json .pi/forge/prompt-stacks/default.json`。
|
|
42
|
+
|
|
43
|
+
搞定。重启 Pi 或执行 `/preset reload`。如果当前没有选中其他栈,`default.json` 会自动启用;如果你之前执行过 `/preset use none` 或选择了别的栈,请执行 `/preset use default`。
|
|
44
|
+
|
|
45
|
+
### 可视化编辑器
|
|
46
|
+
|
|
47
|
+
不想手写 JSON?pi-forge 内置了 Web 编辑器:
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
/preset ui
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
拖拽、编辑、校验、查看完整预览和捕获的 payload、用 tabs 管理变量/context/regex 规则、切换深色模式、通过原始 stack JSON 修复高级字段、导入、导出、fork、删除栈 —— 全在浏览器里完成。Stack metadata 可以折叠,方便把当前编辑区留在屏幕内。
|
|
54
|
+
|
|
55
|
+
导入支持原生 pi-forge stack JSON,也支持 SillyTavern 预设 JSON。SillyTavern 预设会自动转换成 prompt stack;如果一个预设里有多个 `character_id` 配置,编辑器会询问要使用哪一个。
|
|
56
|
+
|
|
57
|
+
编辑器默认运行在一个可用的 `127.0.0.1` 端口,并带有会话 token,所以多个 Pi 实例可以同时打开各自的编辑器。如果 Pi 在 session navigation 或新会话后重新初始化扩展,同一项目中的 `/preset ui` 会复用已有编辑器 URL,不会遗留旧 server 后再开一个新端口。写入需要项目被信任,且只会写入 prompt-stack 存储目录。新建的栈会写入 `.pi/forge/prompt-stacks`;旧的 `.pi/prompt-stacks` 栈仍然可读取和编辑。保存、导入、fork、删除成功后会重新加载到当前 Pi 会话。需要时可以用 `/preset ui restart` 或 `/preset ui stop`。
|
|
58
|
+
|
|
59
|
+
要把旧栈复制到新位置,执行 `/preset migrate-stacks`。加 `--dry-run` 可先预览,加 `--overwrite` 可覆盖目标文件,加 `--delete-legacy` 会在复制成功后删除旧文件。
|
|
60
|
+
|
|
61
|
+
如果想优先使用某个端口,可以创建 `.pi/forge/config.json`。如果该端口被占用,pi-forge 会回退到其他可用端口,并显示实际 URL:
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"webEditor": {
|
|
66
|
+
"port": 41738
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## 使用场景
|
|
72
|
+
|
|
73
|
+
### 🎭 角色扮演 & 创意写作
|
|
74
|
+
|
|
75
|
+
让 Pi 扮演一个角色。在系统提示词中定义性格,用 user message 注入写作风格规则,用 `{{lastUserMessage}}` 在对话历史之后重新插入用户输入。
|
|
76
|
+
|
|
77
|
+
常用模式:
|
|
78
|
+
- 把长期角色规则放在 `system` block。
|
|
79
|
+
- 把 Pi 运行时上下文(工具、技能、项目)放在 `user` slot。
|
|
80
|
+
- 把 `chat-history` slot 设为跳过最新用户消息。
|
|
81
|
+
- 在最后加一个带 `{{lastUserMessage}}` 的 `user` block。
|
|
82
|
+
|
|
83
|
+
这样最新请求会更清晰,也不会重复出现。
|
|
84
|
+
|
|
85
|
+
如果想先从一个基线栈 fork 再改成角色,可以从 [examples/default-prompt-stack.json](examples/default-prompt-stack.json) 开始。
|
|
86
|
+
|
|
87
|
+
### 🧑💻 专注代码审查
|
|
88
|
+
|
|
89
|
+
创建一个 `reviewer.json` 栈,加入严格的审查规则,例如“优先检查正确性、回归风险、安全问题和缺失测试”。保留 `tools`、`project-context`、`variables` 和 `chat-history` slot,这样 Pi 仍然能检查仓库并看到你暴露的模板变量。
|
|
90
|
+
|
|
91
|
+
如果你想保留 Pi 原本的编程行为,只额外加上更严格的审查视角,可以使用 `mode: "append"`。
|
|
92
|
+
|
|
93
|
+
### 🌐 翻译模式
|
|
94
|
+
|
|
95
|
+
创建一个小型 `translator.json` 栈,用一个 system block 指定语气和目标语言,再保留 `chat-history` 和 `{{lastUserMessage}}` 的布局。这样可以在双语润色、直译、产品本地化审查之间快速切换,而不影响默认助手。
|
|
96
|
+
|
|
97
|
+
### 🔀 多模式切换
|
|
98
|
+
|
|
99
|
+
为不同任务创建独立的栈:
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
.pi/forge/prompt-stacks/
|
|
103
|
+
coder.json # 严格编程助手
|
|
104
|
+
writer.json # 创意写作搭档
|
|
105
|
+
translator.json # 双语翻译
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
用 `/preset use coder`、`/preset use writer` 等命令切换。
|
|
109
|
+
|
|
110
|
+
### 🧪 展示 pi-forge 特性的预设
|
|
111
|
+
|
|
112
|
+
- **Pi mirror** — 从 [examples/default-prompt-stack.json](examples/default-prompt-stack.json) 开始。它保留 Pi 的默认行为,同时把每个运行时区块变成可移动、可检查的 slot。
|
|
113
|
+
- **Focused reviewer** — 见 [examples/reviewer-prompt-stack.json](examples/reviewer-prompt-stack.json)。它禁用写文件工具,把旧聊天历史包裹成背景上下文,从 history 中移除最新用户消息,再用 `{{lastUserMessage}}` 作为明确的 review target 插入。
|
|
114
|
+
- **SillyTavern DM writer** — 见 [examples/sillytavern-dm-writer-prompt-stack.json](examples/sillytavern-dm-writer-prompt-stack.json)。它用 `{{char}}` / `{{user}}` 定义 Dungeon Master 角色,包裹旧冒险历史,把 `{{lastUserMessage}}` 作为当前玩家行动重新插入,并用 regex 清理 OOC 注释、暗骰标记、骰子写法和 `Player:` 前缀。
|
|
115
|
+
|
|
116
|
+
### 🔧 模板变量
|
|
117
|
+
|
|
118
|
+
定义稳定的 prompt 常量:
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
"variables": {
|
|
122
|
+
"char": "Konata",
|
|
123
|
+
"user": "User"
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
在 prompt 文本里用 ST 风格宏做局部变量读写:
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
{{setvar::mood::focused}}
|
|
131
|
+
{{getvar::mood}}
|
|
132
|
+
{{setsessionvar::topic::compiler cleanup}}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
需要长期保存的项目记忆请写入仓库文件,而不是 pi-forge prompt 变量。
|
|
136
|
+
|
|
137
|
+
### 📦 SillyTavern 迁移
|
|
138
|
+
|
|
139
|
+
把 ST 预设导入 Pi:
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
/preset import-silly ~/SillyTavern/presets/my-preset.json
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
pi-forge 会把预设转换为 prompt stack,并生成迁移报告,标明哪些已处理、哪些需要手动调整。
|
|
146
|
+
|
|
147
|
+
可安全表示的 SillyTavern `promptOnly` regex 脚本会作为 history 阶段规则转换成 pi-forge `regex.rules`,包括 full-match token 转换、trim strings、depth 字段和明确的 user/assistant placement。Display-only、prompt/display 混合、DOM/browser、CSS/HTML 美化、JavaScript、不支持的 placement 和无效 regex 脚本会保留为报告项,供手动检查。
|
|
148
|
+
|
|
149
|
+
### 🔍 Prompt 调试
|
|
150
|
+
|
|
151
|
+
查看实际发给模型的内容:
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
/payload next save=.pi/forge/payloads/last.json
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
或者打开 `/preset ui`,点击 **Arm payload**,发送下一条 Pi prompt,然后在浏览器里查看脱敏后的 provider payload。
|
|
158
|
+
|
|
159
|
+
或者不发送只预览编译结果:
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
/preset preview
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## 工作原理
|
|
166
|
+
|
|
167
|
+
一个 prompt stack 是一个 JSON 文件,包含两种条目:
|
|
168
|
+
|
|
169
|
+
| 类型 | 作用 |
|
|
170
|
+
|------|------|
|
|
171
|
+
| **Block** | 在指定位置插入的静态文本(系统提示词、用户消息、助手消息) |
|
|
172
|
+
| **Slot** | 来自 Pi 运行时的动态内容 —— 工具、技能、对话历史、日期、项目上下文等 |
|
|
173
|
+
|
|
174
|
+
条目按顺序排列。当栈激活时,pi-forge 会:
|
|
175
|
+
|
|
176
|
+
1. 用你的 `system` 角色 block 和 slot 生成系统提示词,然后按照栈的 `mode` 应用。
|
|
177
|
+
2. 在对话历史周围插入 `user`/`assistant` 角色的 block 和 slot。
|
|
178
|
+
3. 展开 `{{宏}}`,如 `{{lastUserMessage}}`、`{{date}}` 和自定义变量。
|
|
179
|
+
4. 将 stack 的工具策略应用到 Pi 当前 active tools,并过滤 pi-forge 渲染的 tool/skill slot。
|
|
180
|
+
5. 应用已启用的 `history` 和 `compiled` 阶段 outgoing regex 规则。
|
|
181
|
+
6. 可选地在 assistant 消息结束时应用破坏性的 `finalize` regex 规则。
|
|
182
|
+
|
|
183
|
+
### Slot 一览
|
|
184
|
+
|
|
185
|
+
| Slot | 插入的内容 |
|
|
186
|
+
|------|-----------|
|
|
187
|
+
| `chat-history` | 当前对话 |
|
|
188
|
+
| `tools` | 可用工具及其描述 |
|
|
189
|
+
| `tool-guidelines` | 工具使用指导 |
|
|
190
|
+
| `skills` | 已加载的 Pi 技能 |
|
|
191
|
+
| `project-context` | 项目指令和上下文文件 |
|
|
192
|
+
| `variables` | 静态/会话/轮次模板变量 |
|
|
193
|
+
| `date` / `cwd` / `date-cwd` | 当前日期和工作目录 |
|
|
194
|
+
| `active-model` | 当前使用的模型 |
|
|
195
|
+
| `append-system-prompt` | 用户追加的系统提示词 |
|
|
196
|
+
| `pi-docs` | Pi 文档指导 |
|
|
197
|
+
|
|
198
|
+
### 模式
|
|
199
|
+
|
|
200
|
+
- **replace**(默认)— 你的栈完全替换 Pi 的系统提示词。
|
|
201
|
+
- **append** — 你的栈追加在 Pi 默认系统提示词之后。
|
|
202
|
+
- **prepend** — 你的栈插入在 Pi 默认系统提示词之前。
|
|
203
|
+
|
|
204
|
+
## 常用命令
|
|
205
|
+
|
|
206
|
+
### 管理 prompt stack
|
|
207
|
+
|
|
208
|
+
| 命令 | 作用 |
|
|
209
|
+
|------|------|
|
|
210
|
+
| `/preset list` | 显示所有可用栈 |
|
|
211
|
+
| `/preset use <id>` | 激活一个栈 |
|
|
212
|
+
| `/preset use none` | 在当前会话中禁用 prompt stack |
|
|
213
|
+
| `/preset preview [id]` | 查看编译后的 prompt |
|
|
214
|
+
| `/preset validate [id]` | 检查栈是否有问题 |
|
|
215
|
+
| `/preset status` | 显示当前激活栈和诊断摘要 |
|
|
216
|
+
| `/preset diagnostics` | 显示运行时诊断 |
|
|
217
|
+
| `/preset reload` | 从磁盘重新加载栈 |
|
|
218
|
+
| `/preset migrate-stacks [--dry-run] [--overwrite] [--delete-legacy]` | 将旧 `.pi/prompt-stacks` 文件复制到 `.pi/forge/prompt-stacks` |
|
|
219
|
+
| `/preset ui [stop\|restart]` | 打开、停止或重启 Web 编辑器 |
|
|
220
|
+
|
|
221
|
+
### 导入 & 调试
|
|
222
|
+
|
|
223
|
+
| 命令 | 作用 |
|
|
224
|
+
|------|------|
|
|
225
|
+
| `/preset import-silly <path>` | 导入 SillyTavern 预设 |
|
|
226
|
+
| `/intercept` | 显示下一条 provider payload |
|
|
227
|
+
| `/payload next [save=<path>]` | 显示并可保存下一条 payload |
|
|
228
|
+
|
|
229
|
+
## 常用宏
|
|
230
|
+
|
|
231
|
+
在 block 内容中使用这些宏来插入动态值:
|
|
232
|
+
|
|
233
|
+
| 宏 | 展开为 |
|
|
234
|
+
|----|--------|
|
|
235
|
+
| `{{lastUserMessage}}` | 用户最新消息 |
|
|
236
|
+
| `{{date}}` | 当前日期 (YYYY-MM-DD) |
|
|
237
|
+
| `{{time}}` | 当前时间 (HH:MM:SS) |
|
|
238
|
+
| `{{cwd}}` | 当前工作目录 |
|
|
239
|
+
| `{{tools}}` | 逗号分隔的工具名 |
|
|
240
|
+
| `{{selectedTools}}` | 所选工具名的别名 |
|
|
241
|
+
| `{{activeModel}}` | 当前模型 (provider/id) |
|
|
242
|
+
| `{{char}}` / `{{user}}` | 栈中定义的自定义变量 |
|
|
243
|
+
|
|
244
|
+
### 变量宏
|
|
245
|
+
|
|
246
|
+
```
|
|
247
|
+
{{setvar::name::value}} 设置轮次变量(每条消息清空)
|
|
248
|
+
{{setsessionvar::name::value}} 设置会话变量(持久化)
|
|
249
|
+
{{setvar::session::name::value}} 也可设置会话变量
|
|
250
|
+
{{getvar::name}} 读取变量(轮次 → 会话 → 静态)
|
|
251
|
+
{{getturnvar::name}} 只读取轮次变量
|
|
252
|
+
{{getsessionvar::name}} 只读取会话变量
|
|
253
|
+
{{clearvar::name}} 清除变量
|
|
254
|
+
{{clearturnvar::name}} 清除轮次变量
|
|
255
|
+
{{clearsessionvar::name}} 清除会话变量
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Stack 参考
|
|
259
|
+
|
|
260
|
+
### 完整条目类型
|
|
261
|
+
|
|
262
|
+
**Block:**
|
|
263
|
+
|
|
264
|
+
```json
|
|
265
|
+
{
|
|
266
|
+
"kind": "block",
|
|
267
|
+
"id": "unique-id",
|
|
268
|
+
"name": "可读标签",
|
|
269
|
+
"enabled": true,
|
|
270
|
+
"role": "system",
|
|
271
|
+
"content": "你的文本。用 {{宏}} 插入动态内容。"
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
有效角色:`system`、`user`、`assistant`、`custom`。
|
|
276
|
+
|
|
277
|
+
**Slot:**
|
|
278
|
+
|
|
279
|
+
```json
|
|
280
|
+
{
|
|
281
|
+
"kind": "slot",
|
|
282
|
+
"id": "unique-id",
|
|
283
|
+
"name": "对话历史",
|
|
284
|
+
"enabled": true,
|
|
285
|
+
"role": "user",
|
|
286
|
+
"slot": "chat-history",
|
|
287
|
+
"options": {
|
|
288
|
+
"includeLastUserMessage": false
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Chat history 选项
|
|
294
|
+
|
|
295
|
+
```json
|
|
296
|
+
"options": {
|
|
297
|
+
"includeLastUserMessage": false,
|
|
298
|
+
"stripAssistantThinking": true,
|
|
299
|
+
"includeSummaries": true,
|
|
300
|
+
"toolMode": "keep",
|
|
301
|
+
"roles": ["user", "assistant"],
|
|
302
|
+
"maxMessages": 40,
|
|
303
|
+
"maxChars": 20000
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
当你在 history 之后使用 `{{lastUserMessage}}` 时设为 `false`,避免用户消息出现两次。
|
|
308
|
+
|
|
309
|
+
把 `stripAssistantThinking` 设为 `true` 可以从插入的历史中移除之前 assistant 的 thinking block。可见 assistant 文本、tool call 和 tool result 消息会保留。它只影响这个 slot 插入到模型输入里的 history,不会修改当前 agent loop 或已存储 transcript。
|
|
310
|
+
|
|
311
|
+
使用 `includeSummaries: false` 可以排除 Pi 的 branch/compaction summary 消息;`roles` 可以只保留指定消息角色;`toolMode: "drop"` 可以移除之前的 tool call/tool result history;`maxMessages` / `maxChars` 可以只保留最近 history。当过滤或截断可能拆散 tool-call pair 时,pi-forge 会移除悬空的 tool call/result,避免发送不一致的 tool history。
|
|
312
|
+
|
|
313
|
+
### 结构化 slot 格式选项
|
|
314
|
+
|
|
315
|
+
结构化运行时 slot 默认使用 XML 风格包装。给 `tools`、`tool-guidelines`、`skills`、`project-context` 或 `variables` slot 添加 `"format": "plain"`,可输出更紧凑的换行分隔文本。
|
|
316
|
+
|
|
317
|
+
```json
|
|
318
|
+
{
|
|
319
|
+
"kind": "slot",
|
|
320
|
+
"id": "tools",
|
|
321
|
+
"enabled": true,
|
|
322
|
+
"role": "system",
|
|
323
|
+
"slot": "tools",
|
|
324
|
+
"options": {
|
|
325
|
+
"format": "plain"
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
默认 Pi mirror 示例还会用到几个额外 slot 选项:
|
|
331
|
+
|
|
332
|
+
```json
|
|
333
|
+
{
|
|
334
|
+
"slot": "tools",
|
|
335
|
+
"options": {
|
|
336
|
+
"format": "plain",
|
|
337
|
+
"onlyWithSnippets": true
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
`tools.onlyWithSnippets` 会像 Pi 默认 prompt 一样,只显示带 prompt snippet 的工具。`tool-guidelines.heading`、`tool-guidelines.includePiDefaultGuidelines` 和 `tool-guidelines.piStyle` 用来匹配 Pi 默认的 guidelines 标题和条目。`skills.requireReadTool` 会在 read 工具未启用时隐藏 skills,和 Pi 默认行为一致。
|
|
343
|
+
|
|
344
|
+
### 工具和技能策略
|
|
345
|
+
|
|
346
|
+
Prompt stack 可以用栈级 `allow` 或 `deny` 列表限制工具和技能。模式默认精确匹配,也支持 `*` 通配符。
|
|
347
|
+
|
|
348
|
+
```json
|
|
349
|
+
{
|
|
350
|
+
"tools": {
|
|
351
|
+
"allow": ["read", "bash"]
|
|
352
|
+
},
|
|
353
|
+
"skills": {
|
|
354
|
+
"deny": ["browser-danger"]
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
使用 `allow` 时,只有匹配的工具或技能保持启用。使用 `deny` 时,除匹配项以外的工具或技能保持启用。同一个资源策略不能同时包含非空 `allow` 和 `deny` 列表;混用会产生 validation error。
|
|
360
|
+
|
|
361
|
+
工具策略会在栈激活期间通过 Pi 的 active tool list 强制执行。pi-forge 会记住之前的 active tools,并在禁用 prompt stack 或切换到没有工具策略的 stack 时恢复。
|
|
362
|
+
|
|
363
|
+
技能策略会过滤 pi-forge `skills` slot 渲染出的技能。如果 stack 使用 `mode: "append"` 或 `"prepend"`,Pi base prompt 里可能已经包含未过滤的技能;需要控制技能可见性时请使用 `mode: "replace"`。
|
|
364
|
+
|
|
365
|
+
### Regex 转换
|
|
366
|
+
|
|
367
|
+
Prompt stack 可以对发给模型的 prompt 文本执行确定性的 regex 替换,也可以选择清理已结束的 assistant 消息。Outgoing 规则支持 `history` 和 `compiled` 阶段。破坏性的最终消息清理使用 `stage: "compiled"`、`effect: "finalize"` 和 `messages` target。真正的 display-only streaming 转换和 provider-payload 重写还不会生效。
|
|
368
|
+
|
|
369
|
+
```json
|
|
370
|
+
"regex": {
|
|
371
|
+
"schemaVersion": 1,
|
|
372
|
+
"rules": [
|
|
373
|
+
{
|
|
374
|
+
"id": "trim-ooc",
|
|
375
|
+
"enabled": true,
|
|
376
|
+
"stage": "history",
|
|
377
|
+
"effect": "outgoing",
|
|
378
|
+
"pattern": "\\(OOC:[^)]+\\)",
|
|
379
|
+
"flags": "gi",
|
|
380
|
+
"replace": "",
|
|
381
|
+
"roles": ["assistant"],
|
|
382
|
+
"maxMessages": 20
|
|
383
|
+
}
|
|
384
|
+
]
|
|
385
|
+
}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
使用 `stage: "history"` 可以转换 `chat-history` slot 插入的消息。使用 `stage: "compiled"` 并可选配置 `targets: ["system"]`、`["messages"]` 或两者,可以转换最终编译后的 prompt。消息规则可以用 `roles`、`maxMessages`、`maxChars`、`minDepth` 和 `maxDepth` 限制范围,其中 depth `0` 是最新消息。Replacement 使用 JavaScript 语法(`$&` 表示完整匹配,`$1` 表示捕获组;`$0` 也作为完整匹配的别名,`$$` 转义字面 `$`)。`trimStrings` 会从展开后的 replacement match/capture 中移除字面量字符串,对应 SillyTavern 的 Trim Out 行为。支持的 regex flags 是 `g`、`i`、`m`、`s` 和 `u`。
|
|
389
|
+
|
|
390
|
+
要在 streaming 结束后清理一条 assistant 消息,使用 `effect: "finalize"`:
|
|
391
|
+
|
|
392
|
+
```json
|
|
393
|
+
{
|
|
394
|
+
"id": "finalize-ooc",
|
|
395
|
+
"enabled": true,
|
|
396
|
+
"stage": "compiled",
|
|
397
|
+
"effect": "finalize",
|
|
398
|
+
"targets": ["messages"],
|
|
399
|
+
"roles": ["assistant"],
|
|
400
|
+
"pattern": "\\s*\\(OOC:[^)]+\\)",
|
|
401
|
+
"flags": "gi",
|
|
402
|
+
"replace": ""
|
|
403
|
+
}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
警告:`finalize` 在 `message_end` 运行,TUI 可能已经显示过原始 streaming 输出。它会把清理后的 replacement message 交回 Pi,因此 transcript 中不会保留模型原始输出。
|
|
407
|
+
|
|
408
|
+
`effect: "outgoing"` 改变发给模型的输入。`effect: "finalize"` 改变已结束的 assistant transcript 内容。`effect: "display"` 和 `"both"` 会通过校验并产生 warning,但在真正的 display transforms 实现前运行时会忽略。
|
|
409
|
+
|
|
410
|
+
SillyTavern 导入会把确定性的 prompt-only `{{match}}` / `$0` full-match replacement 转成 JavaScript `$&`(`$0` 和 `$&` 在 pi-forge 中都可以用),在 `source.sillytavern` 中保留原始 regex 元数据,并作为 history 阶段规则运行以保持 depth 相对 chat。display-only、browser、unsupported-placement 脚本保留为 report-only。Web 编辑器提供结构化 Regex 对话框来编辑这些规则字段,并会保留需要通过 raw JSON 编辑的高级未知字段。
|
|
411
|
+
|
|
412
|
+
### Variables slot 选项
|
|
413
|
+
|
|
414
|
+
```json
|
|
415
|
+
{
|
|
416
|
+
"kind": "slot",
|
|
417
|
+
"id": "variables",
|
|
418
|
+
"enabled": true,
|
|
419
|
+
"role": "user",
|
|
420
|
+
"slot": "variables",
|
|
421
|
+
"options": {
|
|
422
|
+
"includeStatic": true,
|
|
423
|
+
"includeSession": true,
|
|
424
|
+
"includeTurn": false,
|
|
425
|
+
"format": "xml"
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
## 开发环境搭建
|
|
431
|
+
|
|
432
|
+
```bash
|
|
433
|
+
git clone <repo>
|
|
434
|
+
cd pi-forge
|
|
435
|
+
# .pi/settings.json 已指向包根目录
|
|
436
|
+
pi # 启动 Pi,信任项目,必要时 /reload
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
运行测试:
|
|
440
|
+
|
|
441
|
+
```bash
|
|
442
|
+
npm test
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
类型检查:
|
|
446
|
+
|
|
447
|
+
```bash
|
|
448
|
+
npm run typecheck
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
## License
|
|
452
|
+
|
|
453
|
+
MIT
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"type": "pi-forge.prompt-stack",
|
|
4
4
|
"id": "default",
|
|
5
|
-
"name": "Default
|
|
6
|
-
"description": "
|
|
5
|
+
"name": "Default Pi Prompt Mirror",
|
|
6
|
+
"description": "Recreates Pi's built-in prompt layout with pi-forge slots, exposing tools, guidelines, docs, append-system-prompt, project context, skills, date/cwd, and chat history as movable pieces.",
|
|
7
7
|
"autoActivate": true,
|
|
8
8
|
"mode": "replace",
|
|
9
9
|
"defaults": {
|
|
@@ -13,18 +13,24 @@
|
|
|
13
13
|
"context": {
|
|
14
14
|
"allowDuplicateChatHistory": false
|
|
15
15
|
},
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
|
|
16
|
+
"tools": {
|
|
17
|
+
"allow": ["*"]
|
|
18
|
+
},
|
|
19
|
+
"skills": {
|
|
20
|
+
"allow": ["*"]
|
|
19
21
|
},
|
|
20
22
|
"items": [
|
|
21
23
|
{
|
|
22
24
|
"kind": "block",
|
|
23
25
|
"id": "main-role",
|
|
24
|
-
"name": "
|
|
26
|
+
"name": "Pi Default Role",
|
|
25
27
|
"enabled": true,
|
|
26
28
|
"role": "system",
|
|
27
|
-
"
|
|
29
|
+
"source": {
|
|
30
|
+
"package": "@earendil-works/pi-coding-agent",
|
|
31
|
+
"file": "dist/core/system-prompt.js"
|
|
32
|
+
},
|
|
33
|
+
"content": "You are an expert coding assistant operating inside pi, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files."
|
|
28
34
|
},
|
|
29
35
|
{
|
|
30
36
|
"kind": "slot",
|
|
@@ -32,15 +38,49 @@
|
|
|
32
38
|
"name": "Available Tools",
|
|
33
39
|
"enabled": true,
|
|
34
40
|
"role": "system",
|
|
35
|
-
"slot": "tools"
|
|
41
|
+
"slot": "tools",
|
|
42
|
+
"options": {
|
|
43
|
+
"format": "plain",
|
|
44
|
+
"onlyWithSnippets": true
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"kind": "block",
|
|
49
|
+
"id": "custom-tools-note",
|
|
50
|
+
"name": "Custom Tools Note",
|
|
51
|
+
"enabled": true,
|
|
52
|
+
"role": "system",
|
|
53
|
+
"content": "In addition to the tools above, you may have access to other custom tools depending on the project."
|
|
36
54
|
},
|
|
37
55
|
{
|
|
38
56
|
"kind": "slot",
|
|
39
57
|
"id": "tool-guidelines",
|
|
40
|
-
"name": "
|
|
58
|
+
"name": "Guidelines",
|
|
41
59
|
"enabled": true,
|
|
42
60
|
"role": "system",
|
|
43
|
-
"slot": "tool-guidelines"
|
|
61
|
+
"slot": "tool-guidelines",
|
|
62
|
+
"options": {
|
|
63
|
+
"format": "plain",
|
|
64
|
+
"heading": "Guidelines:",
|
|
65
|
+
"includePiDefaultGuidelines": true,
|
|
66
|
+
"piStyle": true
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"kind": "slot",
|
|
71
|
+
"id": "pi-docs",
|
|
72
|
+
"name": "Pi Documentation Guidance",
|
|
73
|
+
"enabled": true,
|
|
74
|
+
"role": "system",
|
|
75
|
+
"slot": "pi-docs"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"kind": "slot",
|
|
79
|
+
"id": "append-system-prompt",
|
|
80
|
+
"name": "User Append System Prompt",
|
|
81
|
+
"enabled": true,
|
|
82
|
+
"role": "system",
|
|
83
|
+
"slot": "append-system-prompt"
|
|
44
84
|
},
|
|
45
85
|
{
|
|
46
86
|
"kind": "slot",
|
|
@@ -56,7 +96,10 @@
|
|
|
56
96
|
"name": "Available Skills",
|
|
57
97
|
"enabled": true,
|
|
58
98
|
"role": "system",
|
|
59
|
-
"slot": "skills"
|
|
99
|
+
"slot": "skills",
|
|
100
|
+
"options": {
|
|
101
|
+
"requireReadTool": true
|
|
102
|
+
}
|
|
60
103
|
},
|
|
61
104
|
{
|
|
62
105
|
"kind": "slot",
|
|
@@ -66,52 +109,12 @@
|
|
|
66
109
|
"role": "system",
|
|
67
110
|
"slot": "date-cwd"
|
|
68
111
|
},
|
|
69
|
-
{
|
|
70
|
-
"kind": "block",
|
|
71
|
-
"id": "history-open",
|
|
72
|
-
"name": "Open Conversation Context Wrapper",
|
|
73
|
-
"enabled": true,
|
|
74
|
-
"role": "user",
|
|
75
|
-
"content": "<conversation_context>\nThe following is the current Pi conversation context. Treat it as authoritative conversation state, including user requests, assistant replies, tool calls, and tool results."
|
|
76
|
-
},
|
|
77
112
|
{
|
|
78
113
|
"kind": "slot",
|
|
79
114
|
"id": "chat-history",
|
|
80
115
|
"name": "Chat History",
|
|
81
116
|
"enabled": true,
|
|
82
117
|
"slot": "chat-history"
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
"kind": "block",
|
|
86
|
-
"id": "history-close",
|
|
87
|
-
"name": "Close Conversation Context Wrapper",
|
|
88
|
-
"enabled": true,
|
|
89
|
-
"role": "user",
|
|
90
|
-
"content": "</conversation_context>"
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
"kind": "block",
|
|
94
|
-
"id": "post-history-focus",
|
|
95
|
-
"name": "Post-History Focus Instruction",
|
|
96
|
-
"enabled": true,
|
|
97
|
-
"role": "user",
|
|
98
|
-
"content": "<current_turn_instructions>\nFocus on the latest user request. Use the wrapped conversation context only as context; do not repeat it. If tools are needed, use the available Pi tools according to their schemas.\n</current_turn_instructions>"
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
"kind": "slot",
|
|
102
|
-
"id": "append-system-prompt",
|
|
103
|
-
"name": "User Append System Prompt",
|
|
104
|
-
"enabled": true,
|
|
105
|
-
"role": "user",
|
|
106
|
-
"slot": "append-system-prompt"
|
|
107
|
-
},
|
|
108
|
-
{
|
|
109
|
-
"kind": "slot",
|
|
110
|
-
"id": "pi-docs",
|
|
111
|
-
"name": "Pi Docs Guidance",
|
|
112
|
-
"enabled": false,
|
|
113
|
-
"role": "system",
|
|
114
|
-
"slot": "pi-docs"
|
|
115
118
|
}
|
|
116
119
|
]
|
|
117
120
|
}
|