@zihanw/pi-forge 0.2.0 → 0.3.1
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 +233 -105
- package/README.zh-CN.md +215 -104
- package/dist/compiler.d.ts +10 -0
- package/dist/compiler.d.ts.map +1 -0
- package/dist/compiler.js +490 -0
- package/dist/compiler.js.map +1 -0
- package/dist/extension-registry.d.ts +25 -0
- package/dist/extension-registry.d.ts.map +1 -0
- package/dist/extension-registry.js +6 -0
- package/dist/extension-registry.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +364 -0
- package/dist/index.js.map +1 -0
- package/dist/lifecycle.d.ts +14 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +139 -0
- package/dist/lifecycle.js.map +1 -0
- package/dist/loader.d.ts +8 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +345 -0
- package/dist/loader.js.map +1 -0
- package/dist/macro-engine.d.ts +23 -0
- package/dist/macro-engine.d.ts.map +1 -0
- package/dist/macro-engine.js +262 -0
- package/dist/macro-engine.js.map +1 -0
- package/dist/payload-capture.d.ts +15 -0
- package/dist/payload-capture.d.ts.map +1 -0
- package/dist/payload-capture.js +86 -0
- package/dist/payload-capture.js.map +1 -0
- package/dist/payload-command.d.ts +10 -0
- package/dist/payload-command.d.ts.map +1 -0
- package/dist/payload-command.js +112 -0
- package/dist/payload-command.js.map +1 -0
- package/dist/policy.d.ts +6 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +38 -0
- package/dist/policy.js.map +1 -0
- package/dist/preset-command.d.ts +14 -0
- package/dist/preset-command.d.ts.map +1 -0
- package/dist/preset-command.js +223 -0
- package/dist/preset-command.js.map +1 -0
- package/dist/preview.d.ts +12 -0
- package/dist/preview.d.ts.map +1 -0
- package/dist/preview.js +179 -0
- package/dist/preview.js.map +1 -0
- package/dist/regex.d.ts +7 -0
- package/dist/regex.d.ts.map +1 -0
- package/dist/regex.js +432 -0
- package/dist/regex.js.map +1 -0
- package/dist/render-helpers.d.ts +44 -0
- package/dist/render-helpers.d.ts.map +1 -0
- package/dist/render-helpers.js +128 -0
- package/dist/render-helpers.js.map +1 -0
- package/dist/runtime-state.d.ts +24 -0
- package/dist/runtime-state.d.ts.map +1 -0
- package/dist/runtime-state.js +13 -0
- package/dist/runtime-state.js.map +1 -0
- package/dist/sillytavern-importer/items.d.ts +3 -0
- package/dist/sillytavern-importer/items.d.ts.map +1 -0
- package/dist/sillytavern-importer/items.js +88 -0
- package/dist/sillytavern-importer/items.js.map +1 -0
- package/dist/sillytavern-importer/macros.d.ts +15 -0
- package/dist/sillytavern-importer/macros.d.ts.map +1 -0
- package/dist/sillytavern-importer/macros.js +141 -0
- package/dist/sillytavern-importer/macros.js.map +1 -0
- package/dist/sillytavern-importer/prompt-order.d.ts +6 -0
- package/dist/sillytavern-importer/prompt-order.d.ts.map +1 -0
- package/dist/sillytavern-importer/prompt-order.js +38 -0
- package/dist/sillytavern-importer/prompt-order.js.map +1 -0
- package/dist/sillytavern-importer/regex.d.ts +3 -0
- package/dist/sillytavern-importer/regex.d.ts.map +1 -0
- package/dist/sillytavern-importer/regex.js +275 -0
- package/dist/sillytavern-importer/regex.js.map +1 -0
- package/dist/sillytavern-importer/report.d.ts +21 -0
- package/dist/sillytavern-importer/report.d.ts.map +1 -0
- package/dist/sillytavern-importer/report.js +166 -0
- package/dist/sillytavern-importer/report.js.map +1 -0
- package/dist/sillytavern-importer/types.d.ts +106 -0
- package/dist/sillytavern-importer/types.d.ts.map +1 -0
- package/dist/sillytavern-importer/types.js +2 -0
- package/dist/sillytavern-importer/types.js.map +1 -0
- package/dist/sillytavern-importer.d.ts +5 -0
- package/dist/sillytavern-importer.d.ts.map +1 -0
- package/dist/sillytavern-importer.js +117 -0
- package/dist/sillytavern-importer.js.map +1 -0
- package/dist/slot-renderers.d.ts +25 -0
- package/dist/slot-renderers.d.ts.map +1 -0
- package/dist/slot-renderers.js +334 -0
- package/dist/slot-renderers.js.map +1 -0
- package/dist/stack-migration.d.ts +29 -0
- package/dist/stack-migration.d.ts.map +1 -0
- package/dist/stack-migration.js +126 -0
- package/dist/stack-migration.js.map +1 -0
- package/dist/storage.d.ts +6 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +23 -0
- package/dist/storage.js.map +1 -0
- package/dist/types.d.ts +173 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/web-editor/index.d.ts +3 -0
- package/dist/web-editor/index.d.ts.map +1 -0
- package/dist/web-editor/index.js +2 -0
- package/dist/web-editor/index.js.map +1 -0
- package/dist/web-editor/page.d.ts +2 -0
- package/dist/web-editor/page.d.ts.map +1 -0
- package/dist/web-editor/page.js +3331 -0
- package/dist/web-editor/page.js.map +1 -0
- package/dist/web-editor/server.d.ts +4 -0
- package/dist/web-editor/server.d.ts.map +1 -0
- package/dist/web-editor/server.js +263 -0
- package/dist/web-editor/server.js.map +1 -0
- package/dist/web-editor/types.d.ts +125 -0
- package/dist/web-editor/types.d.ts.map +1 -0
- package/dist/web-editor/types.js +2 -0
- package/dist/web-editor/types.js.map +1 -0
- package/dist/web-host.d.ts +29 -0
- package/dist/web-host.d.ts.map +1 -0
- package/dist/web-host.js +174 -0
- package/dist/web-host.js.map +1 -0
- package/examples/custom-system-status-extension/README.md +78 -0
- package/examples/custom-system-status-extension/index.ts +176 -0
- package/examples/custom-system-status-extension/prompt-stack.json +39 -0
- package/examples/default-prompt-stack.json +52 -93
- package/examples/image-reader-prompt-stack.json +124 -0
- package/examples/reviewer-prompt-stack.json +115 -0
- package/examples/sillytavern-dm-writer-prompt-stack.json +190 -0
- package/package.json +30 -9
- package/src/compiler.ts +321 -420
- package/src/extension-registry.ts +33 -0
- package/src/index.ts +310 -1110
- package/src/lifecycle.ts +171 -0
- package/src/loader.ts +141 -56
- package/src/macro-engine.ts +358 -0
- package/src/payload-capture.ts +85 -0
- package/src/payload-command.ts +138 -0
- package/src/policy.ts +42 -0
- package/src/preset-command.ts +271 -0
- package/src/preview.ts +226 -0
- package/src/regex.ts +500 -0
- package/src/render-helpers.ts +169 -0
- package/src/runtime-state.ts +36 -0
- package/src/sillytavern-importer/items.ts +98 -0
- package/src/sillytavern-importer/macros.ts +159 -0
- package/src/sillytavern-importer/prompt-order.ts +54 -0
- package/src/sillytavern-importer/regex.ts +270 -0
- package/src/sillytavern-importer/report.ts +202 -0
- package/src/sillytavern-importer/types.ts +120 -0
- package/src/sillytavern-importer.ts +57 -482
- package/src/slot-renderers.ts +414 -0
- package/src/stack-migration.ts +159 -0
- package/src/storage.ts +28 -0
- package/src/types.ts +83 -52
- package/src/web-editor/index.ts +2 -0
- package/src/web-editor/page.ts +3330 -0
- package/src/web-editor/server.ts +294 -0
- package/src/web-editor/types.ts +98 -0
- package/src/web-host.ts +232 -0
- package/src/web-editor.ts +0 -1491
package/README.zh-CN.md
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
[English](README.md) | [简体中文](README.zh-CN.md)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
**pi-forge** 让你自定义 Pi 的思考方式和行为。它提供 prompt stack(提示栈):这些 JSON 文件可以替换、追加到或插入到 Pi 的默认系统提示词之前,并控制 AI 的性格、可见工具、对话历史布局、模板变量和 prompt 转换。
|
|
6
8
|
|
|
7
9
|
可以把它理解为 AI agent 的角色卡。
|
|
8
10
|
|
|
@@ -11,7 +13,9 @@
|
|
|
11
13
|
- **赋予 Pi 个性** — 把它变成创意写手、角色扮演搭档、严格的代码审查员,或任何你想要的风格。
|
|
12
14
|
- **一键切换模式** — 在"写代码"、"写小说"、"做翻译"之间用一条命令切换。
|
|
13
15
|
- **控制 AI 看到什么** — 选择每个 prompt 中出现哪些工具、技能和项目上下文。
|
|
14
|
-
-
|
|
16
|
+
- **按栈限制工具和技能** — 为专注模式启用工具策略,并过滤技能可见性。
|
|
17
|
+
- **使用模板变量** — 定义 `{{char}}` / `{{user}}` 这样的静态值,并在 prompt 文本里使用 ST 风格的轮次/会话变量宏。
|
|
18
|
+
- **转换发出和最终消息文本** — 对选中的历史、最终编译 prompt 或已结束的 assistant 消息执行确定性 regex 替换。
|
|
15
19
|
- **导入 SillyTavern 预设** — 一条命令把 ST 角色预设迁移到 Pi。
|
|
16
20
|
- **调试 prompt** — 拦截并查看实际发给模型的内容。
|
|
17
21
|
|
|
@@ -25,43 +29,17 @@ pi install npm:@zihanw/pi-forge
|
|
|
25
29
|
|
|
26
30
|
### 第一个 prompt stack
|
|
27
31
|
|
|
28
|
-
创建 `.pi/prompt-stacks/default.json
|
|
32
|
+
从 [examples/default-prompt-stack.json](examples/default-prompt-stack.json) 创建 `.pi/forge/prompt-stacks/default.json`。
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"autoActivate": true,
|
|
36
|
-
"mode": "replace",
|
|
37
|
-
"items": [
|
|
38
|
-
{
|
|
39
|
-
"kind": "block",
|
|
40
|
-
"id": "role",
|
|
41
|
-
"name": "主要角色",
|
|
42
|
-
"enabled": true,
|
|
43
|
-
"role": "system",
|
|
44
|
-
"content": "你是一个友好简洁的编程助手,回答时优先给出简短说明和代码示例。"
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
"kind": "slot",
|
|
48
|
-
"id": "tools",
|
|
49
|
-
"name": "可用工具",
|
|
50
|
-
"enabled": true,
|
|
51
|
-
"role": "system",
|
|
52
|
-
"slot": "tools"
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
"kind": "slot",
|
|
56
|
-
"id": "chat-history",
|
|
57
|
-
"name": "对话历史",
|
|
58
|
-
"enabled": true,
|
|
59
|
-
"slot": "chat-history"
|
|
60
|
-
}
|
|
61
|
-
]
|
|
62
|
-
}
|
|
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
|
|
63
39
|
```
|
|
64
40
|
|
|
41
|
+
把示例 JSON 粘贴进去。如果你就在这个仓库里开发,也可以直接执行 `cp examples/default-prompt-stack.json .pi/forge/prompt-stacks/default.json`。
|
|
42
|
+
|
|
65
43
|
搞定。重启 Pi 或执行 `/preset reload`。如果当前没有选中其他栈,`default.json` 会自动启用;如果你之前执行过 `/preset use none` 或选择了别的栈,请执行 `/preset use default`。
|
|
66
44
|
|
|
67
45
|
### 可视化编辑器
|
|
@@ -72,13 +50,15 @@ pi install npm:@zihanw/pi-forge
|
|
|
72
50
|
/preset ui
|
|
73
51
|
```
|
|
74
52
|
|
|
75
|
-
|
|
53
|
+
拖拽、新建、编辑、校验、查看完整预览和捕获的 payload、用 tabs 管理变量/context/regex 规则、切换深色模式、通过原始 stack JSON 修复高级字段、导入、导出、fork、删除栈 —— 全在浏览器里完成。新栈会从默认 Pi prompt mirror 布局开始。Stack metadata 可以折叠,方便把当前编辑区留在屏幕内。Policy tab 会显示已注册工具和已加载 skills,并提供已选 pattern chips 和过滤输入,方便用精确名称编写 allow/deny 规则,同时保留通配符写法。
|
|
76
54
|
|
|
77
55
|
导入支持原生 pi-forge stack JSON,也支持 SillyTavern 预设 JSON。SillyTavern 预设会自动转换成 prompt stack;如果一个预设里有多个 `character_id` 配置,编辑器会询问要使用哪一个。
|
|
78
56
|
|
|
79
|
-
|
|
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` 会在复制成功后删除旧文件。
|
|
80
60
|
|
|
81
|
-
|
|
61
|
+
如果想优先使用某个端口,可以创建 `.pi/forge/config.json`。如果该端口被占用,pi-forge 会回退到其他可用端口,并显示实际 URL:
|
|
82
62
|
|
|
83
63
|
```json
|
|
84
64
|
{
|
|
@@ -102,11 +82,11 @@ pi install npm:@zihanw/pi-forge
|
|
|
102
82
|
|
|
103
83
|
这样最新请求会更清晰,也不会重复出现。
|
|
104
84
|
|
|
105
|
-
|
|
85
|
+
如果想先从一个基线栈 fork 再改成角色,可以从 [examples/default-prompt-stack.json](examples/default-prompt-stack.json) 开始。
|
|
106
86
|
|
|
107
87
|
### 🧑💻 专注代码审查
|
|
108
88
|
|
|
109
|
-
创建一个 `reviewer.json` 栈,加入严格的审查规则,例如“优先检查正确性、回归风险、安全问题和缺失测试”。保留 `tools`、`project-context`、`variables` 和 `chat-history` slot,这样 Pi
|
|
89
|
+
创建一个 `reviewer.json` 栈,加入严格的审查规则,例如“优先检查正确性、回归风险、安全问题和缺失测试”。保留 `tools`、`project-context`、`variables` 和 `chat-history` slot,这样 Pi 仍然能检查仓库并看到你暴露的模板变量。
|
|
110
90
|
|
|
111
91
|
如果你想保留 Pi 原本的编程行为,只额外加上更严格的审查视角,可以使用 `mode: "append"`。
|
|
112
92
|
|
|
@@ -119,7 +99,7 @@ pi install npm:@zihanw/pi-forge
|
|
|
119
99
|
为不同任务创建独立的栈:
|
|
120
100
|
|
|
121
101
|
```
|
|
122
|
-
.pi/prompt-stacks/
|
|
102
|
+
.pi/forge/prompt-stacks/
|
|
123
103
|
coder.json # 严格编程助手
|
|
124
104
|
writer.json # 创意写作搭档
|
|
125
105
|
translator.json # 双语翻译
|
|
@@ -127,29 +107,33 @@ pi install npm:@zihanw/pi-forge
|
|
|
127
107
|
|
|
128
108
|
用 `/preset use coder`、`/preset use writer` 等命令切换。
|
|
129
109
|
|
|
130
|
-
###
|
|
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:` 前缀。
|
|
131
115
|
|
|
132
|
-
|
|
116
|
+
### 🔧 模板变量
|
|
117
|
+
|
|
118
|
+
定义稳定的 prompt 常量:
|
|
133
119
|
|
|
134
120
|
```json
|
|
135
|
-
"
|
|
136
|
-
"
|
|
137
|
-
|
|
138
|
-
"type": "string",
|
|
139
|
-
"scope": "session",
|
|
140
|
-
"description": "当前任务进度",
|
|
141
|
-
"agentWritable": true
|
|
142
|
-
}
|
|
143
|
-
}
|
|
121
|
+
"variables": {
|
|
122
|
+
"char": "Konata",
|
|
123
|
+
"user": "User"
|
|
144
124
|
}
|
|
145
125
|
```
|
|
146
126
|
|
|
147
|
-
|
|
127
|
+
在 prompt 文本里用 ST 风格宏做局部变量读写:
|
|
148
128
|
|
|
149
129
|
```
|
|
150
|
-
|
|
130
|
+
{{setvar::mood::focused}}
|
|
131
|
+
{{getvar::mood}}
|
|
132
|
+
{{setsessionvar::topic::compiler cleanup}}
|
|
151
133
|
```
|
|
152
134
|
|
|
135
|
+
需要长期保存的项目记忆请写入仓库文件,而不是 pi-forge prompt 变量。
|
|
136
|
+
|
|
153
137
|
### 📦 SillyTavern 迁移
|
|
154
138
|
|
|
155
139
|
把 ST 预设导入 Pi:
|
|
@@ -160,6 +144,8 @@ Agent 用 `forge_state_set` 更新状态。你也可以手动设置:
|
|
|
160
144
|
|
|
161
145
|
pi-forge 会把预设转换为 prompt stack,并生成迁移报告,标明哪些已处理、哪些需要手动调整。
|
|
162
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
|
+
|
|
163
149
|
### 🔍 Prompt 调试
|
|
164
150
|
|
|
165
151
|
查看实际发给模型的内容:
|
|
@@ -168,6 +154,8 @@ pi-forge 会把预设转换为 prompt stack,并生成迁移报告,标明哪
|
|
|
168
154
|
/payload next save=.pi/forge/payloads/last.json
|
|
169
155
|
```
|
|
170
156
|
|
|
157
|
+
或者打开 `/preset ui`,点击 **Arm payload**,发送下一条 Pi prompt,然后在浏览器里查看脱敏后的 provider payload。
|
|
158
|
+
|
|
171
159
|
或者不发送只预览编译结果:
|
|
172
160
|
|
|
173
161
|
```
|
|
@@ -188,6 +176,9 @@ pi-forge 会把预设转换为 prompt stack,并生成迁移报告,标明哪
|
|
|
188
176
|
1. 用你的 `system` 角色 block 和 slot 生成系统提示词,然后按照栈的 `mode` 应用。
|
|
189
177
|
2. 在对话历史周围插入 `user`/`assistant` 角色的 block 和 slot。
|
|
190
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 规则。
|
|
191
182
|
|
|
192
183
|
### Slot 一览
|
|
193
184
|
|
|
@@ -198,8 +189,8 @@ pi-forge 会把预设转换为 prompt stack,并生成迁移报告,标明哪
|
|
|
198
189
|
| `tool-guidelines` | 工具使用指导 |
|
|
199
190
|
| `skills` | 已加载的 Pi 技能 |
|
|
200
191
|
| `project-context` | 项目指令和上下文文件 |
|
|
201
|
-
| `variables` |
|
|
202
|
-
| `date` / `cwd` / `date-cwd` |
|
|
192
|
+
| `variables` | 静态/会话/轮次模板变量 |
|
|
193
|
+
| `date` / `cwd` / `date-cwd` | 当前日期、可选当前时间和工作目录 |
|
|
203
194
|
| `active-model` | 当前使用的模型 |
|
|
204
195
|
| `append-system-prompt` | 用户追加的系统提示词 |
|
|
205
196
|
| `pi-docs` | Pi 文档指导 |
|
|
@@ -224,19 +215,9 @@ pi-forge 会把预设转换为 prompt stack,并生成迁移报告,标明哪
|
|
|
224
215
|
| `/preset status` | 显示当前激活栈和诊断摘要 |
|
|
225
216
|
| `/preset diagnostics` | 显示运行时诊断 |
|
|
226
217
|
| `/preset reload` | 从磁盘重新加载栈 |
|
|
218
|
+
| `/preset migrate-stacks [--dry-run] [--overwrite] [--delete-legacy]` | 将旧 `.pi/prompt-stacks` 文件复制到 `.pi/forge/prompt-stacks` |
|
|
227
219
|
| `/preset ui [stop\|restart]` | 打开、停止或重启 Web 编辑器 |
|
|
228
220
|
|
|
229
|
-
### 状态管理
|
|
230
|
-
|
|
231
|
-
| 命令 | 作用 |
|
|
232
|
-
|------|------|
|
|
233
|
-
| `/state list` | 显示所有会话状态 |
|
|
234
|
-
| `/state status` | 显示状态定义和当前值 |
|
|
235
|
-
| `/state set <name> <value>` | 设置状态变量 |
|
|
236
|
-
| `/state get <name>` | 读取状态变量 |
|
|
237
|
-
| `/state clear [name]` | 清除状态(全部或按名称) |
|
|
238
|
-
| `/preset vars ...` | 为旧栈保留的兼容变量命令 |
|
|
239
|
-
|
|
240
221
|
### 导入 & 调试
|
|
241
222
|
|
|
242
223
|
| 命令 | 作用 |
|
|
@@ -274,6 +255,57 @@ pi-forge 会把预设转换为 prompt stack,并生成迁移报告,标明哪
|
|
|
274
255
|
{{clearsessionvar::name}} 清除会话变量
|
|
275
256
|
```
|
|
276
257
|
|
|
258
|
+
### 过滤和条件宏
|
|
259
|
+
|
|
260
|
+
宏支持嵌套,`::` 分隔符只会在当前宏深度拆分。
|
|
261
|
+
|
|
262
|
+
| 宏 | 展开为 |
|
|
263
|
+
|----|--------|
|
|
264
|
+
| `{{trim::value}}` | 去掉首尾空白后的 `value` |
|
|
265
|
+
| `{{upper::value}}` | 大写 `value` |
|
|
266
|
+
| `{{lower::value}}` | 小写 `value` |
|
|
267
|
+
| `{{json::value}}` | `value` 的 JSON 字符串字面量 |
|
|
268
|
+
| `{{xml::value}}` | XML 转义后的 `value` |
|
|
269
|
+
| `{{ifvar::name::then::else}}` | 变量存在时输出 `then`,否则输出 `else` |
|
|
270
|
+
| `{{ifeq::name::expected::then::else}}` | 变量等于 `expected` 时输出 `then`,否则输出 `else` |
|
|
271
|
+
| `{{iftools::tool::then::else}}` | 当前工具列表包含 `tool` 时输出 `then`,否则输出 `else` |
|
|
272
|
+
| `{{ifslot::slot::then::else}}` | 启用的 stack 条目包含 `slot` 时输出 `then`,否则输出 `else` |
|
|
273
|
+
|
|
274
|
+
条件宏是 lazy 的:只有选中的分支会展开,所以被跳过的分支不会设置或清除变量。最后的 `else` 参数可省略,默认输出空文本。
|
|
275
|
+
|
|
276
|
+
### 可信自定义宏和 slot
|
|
277
|
+
|
|
278
|
+
自定义宏和 slot 由可信扩展代码注册,不把可执行代码写进 prompt-stack JSON。Stack 只引用已注册名称并传入声明式 options;真正的 `render` 逻辑放在 Pi 扩展或明确安装的包里。
|
|
279
|
+
|
|
280
|
+
```ts
|
|
281
|
+
import { registerMacro, registerSlot } from "@zihanw/pi-forge";
|
|
282
|
+
|
|
283
|
+
registerMacro({
|
|
284
|
+
name: "ticketId",
|
|
285
|
+
description: "从会话变量读取当前 ticket id。",
|
|
286
|
+
render: (ctx) => ctx.variables.toMacroText(ctx.variables.get("ticket.id")),
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
registerSlot({
|
|
290
|
+
name: "ticket-context",
|
|
291
|
+
description: "渲染当前任务的 ticket 上下文。",
|
|
292
|
+
options: {
|
|
293
|
+
heading: { type: "string", default: "Ticket context" },
|
|
294
|
+
},
|
|
295
|
+
render: (ctx) => [
|
|
296
|
+
String(ctx.options.heading ?? "Ticket context") + ":",
|
|
297
|
+
"- Ticket: " + ctx.variables.toMacroText(ctx.variables.get("ticket.id")),
|
|
298
|
+
"- Project: " + ctx.helpers.normalizePath(ctx.runtime.options.cwd),
|
|
299
|
+
].join("\n"),
|
|
300
|
+
});
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
缺失的自定义 slot 会产生校验 warning,直到对应注册扩展安装并加载。内置宏和 slot 也使用同一个 registry,可用 `getRegisteredMacros()` 和 `getRegisteredSlots()` 作为实现参考。
|
|
304
|
+
|
|
305
|
+
完整可复制的扩展和 stack 示例见 [examples/custom-system-status-extension](examples/custom-system-status-extension)。它在可信 Pi 扩展文件中注册 `{{cpuLoad}}` 宏和 `machine-status` slot。
|
|
306
|
+
|
|
307
|
+
如果 pi-forge 是作为 package 安装的,自定义扩展可以 import `@zihanw/pi-forge`。如果你是通过 Pi settings 加载本地 checkout,请按示例 README 设置显式路径,例如 `PI_FORGE_MODULE=/path/to/pi-forge/src/index.ts`。pi-forge 会把 macro/slot registry 放在当前进程的 global registry 中,因此兼容的本地模块副本可以共享注册结果。
|
|
308
|
+
|
|
277
309
|
## Stack 参考
|
|
278
310
|
|
|
279
311
|
### 完整条目类型
|
|
@@ -313,77 +345,150 @@ pi-forge 会把预设转换为 prompt stack,并生成迁移报告,标明哪
|
|
|
313
345
|
|
|
314
346
|
```json
|
|
315
347
|
"options": {
|
|
316
|
-
"includeLastUserMessage": false
|
|
348
|
+
"includeLastUserMessage": false,
|
|
349
|
+
"stripAssistantThinking": true,
|
|
350
|
+
"includeSummaries": true,
|
|
351
|
+
"toolMode": "keep",
|
|
352
|
+
"roles": ["user", "assistant"],
|
|
353
|
+
"maxMessages": 40,
|
|
354
|
+
"maxChars": 20000
|
|
317
355
|
}
|
|
318
356
|
```
|
|
319
357
|
|
|
320
358
|
当你在 history 之后使用 `{{lastUserMessage}}` 时设为 `false`,避免用户消息出现两次。
|
|
321
359
|
|
|
322
|
-
|
|
360
|
+
把 `stripAssistantThinking` 设为 `true` 可以从插入的历史中移除之前 assistant 的 thinking block。可见 assistant 文本、tool call 和 tool result 消息会保留。它只影响这个 slot 插入到模型输入里的 history,不会修改当前 agent loop 或已存储 transcript。
|
|
361
|
+
|
|
362
|
+
使用 `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。
|
|
363
|
+
|
|
364
|
+
### Date slot 选项
|
|
365
|
+
|
|
366
|
+
在 `date` 或 `date-cwd` slot 上设置 `"includeTime": true`,会在当前日期后加入 `HH:MM:SS` 格式的当前时间。
|
|
367
|
+
|
|
368
|
+
### 结构化 slot 格式选项
|
|
369
|
+
|
|
370
|
+
结构化运行时 slot 默认使用 XML 风格包装。给 `tools`、`tool-guidelines`、`skills`、`project-context` 或 `variables` slot 添加 `"format": "plain"`,可输出更紧凑的换行分隔文本。
|
|
323
371
|
|
|
324
372
|
```json
|
|
325
373
|
{
|
|
326
374
|
"kind": "slot",
|
|
327
|
-
"id": "
|
|
375
|
+
"id": "tools",
|
|
328
376
|
"enabled": true,
|
|
329
|
-
"role": "
|
|
330
|
-
"slot": "
|
|
377
|
+
"role": "system",
|
|
378
|
+
"slot": "tools",
|
|
331
379
|
"options": {
|
|
332
|
-
"
|
|
333
|
-
"includeNamespaces": ["user.*", "agent.*"],
|
|
334
|
-
"includeMetadata": true,
|
|
335
|
-
"format": "xml",
|
|
336
|
-
"maxValueChars": 1200
|
|
380
|
+
"format": "plain"
|
|
337
381
|
}
|
|
338
382
|
}
|
|
339
383
|
```
|
|
340
384
|
|
|
341
|
-
|
|
385
|
+
默认 Pi mirror 示例还会用到几个额外 slot 选项:
|
|
342
386
|
|
|
343
387
|
```json
|
|
344
|
-
|
|
388
|
+
{
|
|
389
|
+
"slot": "tools",
|
|
390
|
+
"options": {
|
|
391
|
+
"format": "plain",
|
|
392
|
+
"onlyWithSnippets": true
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
`tools.onlyWithSnippets` 会像 Pi 默认 prompt 一样,只显示带 prompt snippet 的工具。`tool-guidelines.heading`、`tool-guidelines.includePiDefaultGuidelines` 和 `tool-guidelines.piStyle` 用来匹配 Pi 默认的 guidelines 标题和条目。`skills.requireReadTool` 会在 read 工具未启用时隐藏 skills,和 Pi 默认行为一致。
|
|
398
|
+
|
|
399
|
+
### 工具和技能策略
|
|
400
|
+
|
|
401
|
+
Prompt stack 可以用栈级 `allow` 或 `deny` 列表限制工具和技能。模式默认精确匹配,也支持 `*` 通配符。
|
|
402
|
+
|
|
403
|
+
```json
|
|
404
|
+
{
|
|
405
|
+
"tools": {
|
|
406
|
+
"allow": ["read", "bash"]
|
|
407
|
+
},
|
|
408
|
+
"skills": {
|
|
409
|
+
"deny": ["browser-danger"]
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
使用 `allow` 时,只有匹配的工具或技能保持启用。使用 `deny` 时,除匹配项以外的工具或技能保持启用。同一个资源策略不能同时包含非空 `allow` 和 `deny` 列表;混用会产生 validation error。
|
|
415
|
+
|
|
416
|
+
工具策略会在栈激活期间通过 Pi 的 active tool list 强制执行。pi-forge 会记住之前的 active tools,并在禁用 prompt stack 或切换到没有工具策略的 stack 时恢复。
|
|
417
|
+
|
|
418
|
+
技能策略会过滤 pi-forge `skills` slot 渲染出的技能。如果 stack 使用 `mode: "append"` 或 `"prepend"`,Pi base prompt 里可能已经包含未过滤的技能;需要控制技能可见性时请使用 `mode: "replace"`。
|
|
419
|
+
|
|
420
|
+
### Regex 转换
|
|
421
|
+
|
|
422
|
+
Prompt stack 可以对发给模型的 prompt 文本执行确定性的 regex 替换,也可以选择清理已结束的 assistant 消息。Outgoing 规则支持 `history` 和 `compiled` 阶段。破坏性的最终消息清理使用 `stage: "compiled"`、`effect: "finalize"` 和 `messages` target。真正的 display-only streaming 转换和 provider-payload 重写还不会生效。
|
|
423
|
+
|
|
424
|
+
```json
|
|
425
|
+
"regex": {
|
|
345
426
|
"schemaVersion": 1,
|
|
346
|
-
"
|
|
347
|
-
|
|
348
|
-
"
|
|
349
|
-
"
|
|
350
|
-
"
|
|
351
|
-
"
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
"
|
|
355
|
-
"
|
|
356
|
-
"
|
|
357
|
-
"userWritable": true
|
|
427
|
+
"rules": [
|
|
428
|
+
{
|
|
429
|
+
"id": "trim-ooc",
|
|
430
|
+
"enabled": true,
|
|
431
|
+
"stage": "history",
|
|
432
|
+
"effect": "outgoing",
|
|
433
|
+
"pattern": "\\(OOC:[^)]+\\)",
|
|
434
|
+
"flags": "gi",
|
|
435
|
+
"replace": "",
|
|
436
|
+
"roles": ["assistant"],
|
|
437
|
+
"maxMessages": 20
|
|
358
438
|
}
|
|
359
|
-
|
|
439
|
+
]
|
|
360
440
|
}
|
|
361
441
|
```
|
|
362
442
|
|
|
363
|
-
|
|
443
|
+
使用 `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`。
|
|
364
444
|
|
|
365
|
-
|
|
445
|
+
要在 streaming 结束后清理一条 assistant 消息,使用 `effect: "finalize"`:
|
|
366
446
|
|
|
367
|
-
|
|
447
|
+
```json
|
|
448
|
+
{
|
|
449
|
+
"id": "finalize-ooc",
|
|
450
|
+
"enabled": true,
|
|
451
|
+
"stage": "compiled",
|
|
452
|
+
"effect": "finalize",
|
|
453
|
+
"targets": ["messages"],
|
|
454
|
+
"roles": ["assistant"],
|
|
455
|
+
"pattern": "\\s*\\(OOC:[^)]+\\)",
|
|
456
|
+
"flags": "gi",
|
|
457
|
+
"replace": ""
|
|
458
|
+
}
|
|
459
|
+
```
|
|
368
460
|
|
|
369
|
-
|
|
461
|
+
警告:`finalize` 在 `message_end` 运行,TUI 可能已经显示过原始 streaming 输出。它会把清理后的 replacement message 交回 Pi,因此 transcript 中不会保留模型原始输出。
|
|
370
462
|
|
|
371
|
-
|
|
463
|
+
`effect: "outgoing"` 改变发给模型的输入。`effect: "finalize"` 改变已结束的 assistant transcript 内容。`effect: "display"` 和 `"both"` 会通过校验并产生 warning,但在真正的 display transforms 实现前运行时会忽略。
|
|
372
464
|
|
|
373
|
-
-
|
|
374
|
-
- 待解决问题 (`agent.openQuestions`)
|
|
375
|
-
- 故事状态 (`agent.storyState`)
|
|
376
|
-
- 用户要求的笔记 (`agent.notes`)
|
|
465
|
+
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 编辑的高级未知字段。
|
|
377
466
|
|
|
378
|
-
###
|
|
467
|
+
### Variables slot 选项
|
|
379
468
|
|
|
380
|
-
|
|
469
|
+
```json
|
|
470
|
+
{
|
|
471
|
+
"kind": "slot",
|
|
472
|
+
"id": "variables",
|
|
473
|
+
"enabled": true,
|
|
474
|
+
"role": "user",
|
|
475
|
+
"slot": "variables",
|
|
476
|
+
"options": {
|
|
477
|
+
"includeStatic": true,
|
|
478
|
+
"includeSession": true,
|
|
479
|
+
"includeTurn": false,
|
|
480
|
+
"format": "xml"
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
```
|
|
381
484
|
|
|
382
485
|
## 开发环境搭建
|
|
383
486
|
|
|
384
487
|
```bash
|
|
385
488
|
git clone <repo>
|
|
386
489
|
cd pi-forge
|
|
490
|
+
npm install
|
|
491
|
+
npm run build
|
|
387
492
|
# .pi/settings.json 已指向包根目录
|
|
388
493
|
pi # 启动 Pi,信任项目,必要时 /reload
|
|
389
494
|
```
|
|
@@ -400,6 +505,12 @@ npm test
|
|
|
400
505
|
npm run typecheck
|
|
401
506
|
```
|
|
402
507
|
|
|
508
|
+
构建 package 输出:
|
|
509
|
+
|
|
510
|
+
```bash
|
|
511
|
+
npm run build
|
|
512
|
+
```
|
|
513
|
+
|
|
403
514
|
## License
|
|
404
515
|
|
|
405
516
|
MIT
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AgentMessage } from "@earendil-works/pi-agent-core";
|
|
2
|
+
import type { CompileMessagesResult, CompileSystemPromptResult, PromptRuntime, PromptStack, PromptVariableValue, PromptVariableStore } from "./types.ts";
|
|
3
|
+
export declare function createPromptVariableStore(sessionVariables?: Record<string, PromptVariableValue>): PromptVariableStore;
|
|
4
|
+
export declare function resetTurnVariables(store: PromptVariableStore): void;
|
|
5
|
+
export declare function markSessionVariablesClean(store: PromptVariableStore): void;
|
|
6
|
+
export declare function compileSystemPrompt(stack: PromptStack, runtime: PromptRuntime, baseSystemPrompt: string): CompileSystemPromptResult;
|
|
7
|
+
export declare function compileMessages(stack: PromptStack, runtime: PromptRuntime, originalMessages: AgentMessage[]): CompileMessagesResult;
|
|
8
|
+
export declare function getLatestUserMessage(messages: AgentMessage[]): string | undefined;
|
|
9
|
+
export declare function agentMessageToPreviewText(message: AgentMessage): string;
|
|
10
|
+
//# sourceMappingURL=compiler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../src/compiler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EAEX,qBAAqB,EACrB,yBAAyB,EACzB,aAAa,EACb,WAAW,EAKX,mBAAmB,EACnB,mBAAmB,EACnB,MAAM,YAAY,CAAC;AAgBpB,wBAAgB,yBAAyB,CAAC,gBAAgB,GAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAM,GAAG,mBAAmB,CAEzH;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI,CAGnE;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI,CAE1E;AAED,wBAAgB,mBAAmB,CAClC,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,aAAa,EACtB,gBAAgB,EAAE,MAAM,GACtB,yBAAyB,CAuC3B;AAED,wBAAgB,eAAe,CAC9B,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,aAAa,EACtB,gBAAgB,EAAE,YAAY,EAAE,GAC9B,qBAAqB,CA2CvB;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,MAAM,GAAG,SAAS,CASjF;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAWvE"}
|