@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.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** lets you customize how Pi thinks and behaves. It gives you prompt stacks — JSON files that can replace, append to, or prepend Pi's default system prompt while controlling the AI's personality, visible tools, conversation history layout, template variables, and prompt transforms.
|
|
6
8
|
|
|
7
9
|
Think of it as a character sheet for your AI agent.
|
|
8
10
|
|
|
@@ -11,7 +13,9 @@ Think of it as a character sheet for your AI agent.
|
|
|
11
13
|
- **Give Pi a personality** — turn it into a creative writer, a roleplay partner, a strict code reviewer, or anything in between.
|
|
12
14
|
- **Switch contexts instantly** — one command to swap between "coding mode", "writing mode", and "translation mode".
|
|
13
15
|
- **Control what the AI sees** — choose which tools, skills, and project context appear in each prompt.
|
|
14
|
-
- **
|
|
16
|
+
- **Limit tools and skills per stack** — enforce active tool policy and filter skill visibility for focused modes.
|
|
17
|
+
- **Use template variables** — define static values such as `{{char}}` / `{{user}}`, and use ST-style turn/session variable macros inside prompt text.
|
|
18
|
+
- **Transform outgoing and finalized text** — run deterministic regex replacements on selected history, compiled prompt text, or finalized assistant messages.
|
|
15
19
|
- **Import SillyTavern presets** — bring your existing ST character presets into Pi with one command.
|
|
16
20
|
- **Debug your prompts** — intercept and inspect exactly what gets sent to the model.
|
|
17
21
|
|
|
@@ -25,43 +29,17 @@ pi install npm:@zihanw/pi-forge
|
|
|
25
29
|
|
|
26
30
|
### Your first prompt stack
|
|
27
31
|
|
|
28
|
-
Create `.pi/prompt-stacks/default.json
|
|
32
|
+
Create `.pi/forge/prompt-stacks/default.json` from [examples/default-prompt-stack.json](examples/default-prompt-stack.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": "Main Role",
|
|
42
|
-
"enabled": true,
|
|
43
|
-
"role": "system",
|
|
44
|
-
"content": "You are a friendly and concise coding assistant. Prefer short answers with code examples."
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
"kind": "slot",
|
|
48
|
-
"id": "tools",
|
|
49
|
-
"name": "Available Tools",
|
|
50
|
-
"enabled": true,
|
|
51
|
-
"role": "system",
|
|
52
|
-
"slot": "tools"
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
"kind": "slot",
|
|
56
|
-
"id": "chat-history",
|
|
57
|
-
"name": "Chat History",
|
|
58
|
-
"enabled": true,
|
|
59
|
-
"slot": "chat-history"
|
|
60
|
-
}
|
|
61
|
-
]
|
|
62
|
-
}
|
|
34
|
+
The default example mirrors Pi's own prompt builder from `@earendil-works/pi-coding-agent/dist/core/system-prompt.js`, but splits it into movable pi-forge slots: role, tools, guidelines, Pi docs guidance, appended system prompt text, project context, skills, date/cwd, and chat history.
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
mkdir -p .pi/forge/prompt-stacks
|
|
38
|
+
$EDITOR .pi/forge/prompt-stacks/default.json
|
|
63
39
|
```
|
|
64
40
|
|
|
41
|
+
Paste the example JSON into that file. If you are working inside this repository, you can copy it directly with `cp examples/default-prompt-stack.json .pi/forge/prompt-stacks/default.json`.
|
|
42
|
+
|
|
65
43
|
That's it. Restart Pi or run `/preset reload`. If no stack is already selected, `default.json` auto-activates. If you previously chose another stack or `/preset use none`, run `/preset use default`.
|
|
66
44
|
|
|
67
45
|
### Visual editor
|
|
@@ -72,13 +50,15 @@ Prefer clicking over typing JSON? pi-forge has a built-in web editor:
|
|
|
72
50
|
/preset ui
|
|
73
51
|
```
|
|
74
52
|
|
|
75
|
-
Drag, drop, edit, validate,
|
|
53
|
+
Drag, drop, create, edit, validate, inspect full previews and captured payloads, manage variables/context/regex rules in tabs, switch dark mode, recover through raw stack JSON, import, export, fork, and delete stacks — all in your browser. New stacks start from the default Pi prompt mirror layout. Stack metadata is collapsible so the active editor stays in view. The policy tab shows registered tools and loaded skills with selected-pattern chips and filtering, so allow/deny rules can be built from exact names while still supporting wildcards.
|
|
76
54
|
|
|
77
55
|
Import accepts native pi-forge stack JSON and SillyTavern preset JSON. SillyTavern presets are converted to prompt stacks automatically; if a preset contains multiple `character_id` configs, the editor asks which one to use.
|
|
78
56
|
|
|
79
|
-
The editor runs on `127.0.0.1
|
|
57
|
+
The editor runs on an available `127.0.0.1` port with a session token, so multiple Pi instances can run editors at the same time. If Pi reinitializes the extension after session navigation or a new session, `/preset ui` reuses the existing editor URL for the same project instead of orphaning the old server. Writes require a trusted project and stay inside prompt-stack storage. New stacks are written to `.pi/forge/prompt-stacks`; existing legacy stacks under `.pi/prompt-stacks` remain readable and editable. Successful save, import, fork, and delete actions reload into the current Pi session. Use `/preset ui restart` or `/preset ui stop` when needed.
|
|
58
|
+
|
|
59
|
+
To copy old stacks into the new location, run `/preset migrate-stacks`. Add `--dry-run` to preview, `--overwrite` to replace existing target files, and `--delete-legacy` to remove old files after successful copy.
|
|
80
60
|
|
|
81
|
-
To
|
|
61
|
+
To prefer a specific port, create `.pi/forge/config.json`. If that port is busy, pi-forge falls back to another available port and shows the actual URL:
|
|
82
62
|
|
|
83
63
|
```json
|
|
84
64
|
{
|
|
@@ -102,11 +82,11 @@ Useful pattern:
|
|
|
102
82
|
|
|
103
83
|
This keeps the latest request clear and avoids duplicating it.
|
|
104
84
|
|
|
105
|
-
For a
|
|
85
|
+
For a baseline stack to fork before turning Pi into a character, start from [examples/default-prompt-stack.json](examples/default-prompt-stack.json).
|
|
106
86
|
|
|
107
87
|
### 🧑💻 Focused code review
|
|
108
88
|
|
|
109
|
-
Create a `reviewer.json` stack with a strict review block: "prioritize correctness, regressions, security, and missing tests." Keep the `tools`, `project-context`, `variables`, and `chat-history` slots enabled so Pi can still inspect the repo and
|
|
89
|
+
Create a `reviewer.json` stack with a strict review block: "prioritize correctness, regressions, security, and missing tests." Keep the `tools`, `project-context`, `variables`, and `chat-history` slots enabled so Pi can still inspect the repo and see any template variables you expose.
|
|
110
90
|
|
|
111
91
|
Use `mode: "append"` if you want to keep Pi's normal coding behavior and only add the sharper review lens.
|
|
112
92
|
|
|
@@ -119,7 +99,7 @@ Create a small `translator.json` stack with one system block for tone and target
|
|
|
119
99
|
Create separate stacks for different tasks:
|
|
120
100
|
|
|
121
101
|
```
|
|
122
|
-
.pi/prompt-stacks/
|
|
102
|
+
.pi/forge/prompt-stacks/
|
|
123
103
|
coder.json # strict coding assistant
|
|
124
104
|
writer.json # creative writing partner
|
|
125
105
|
translator.json # bilingual translator
|
|
@@ -127,29 +107,35 @@ Create separate stacks for different tasks:
|
|
|
127
107
|
|
|
128
108
|
Switch with `/preset use coder`, `/preset use writer`, etc.
|
|
129
109
|
|
|
130
|
-
###
|
|
110
|
+
### 🧪 Presets that show off pi-forge
|
|
131
111
|
|
|
132
|
-
|
|
112
|
+
- **Pi mirror** — start from [examples/default-prompt-stack.json](examples/default-prompt-stack.json). It preserves normal Pi behavior while making every runtime section movable and inspectable.
|
|
113
|
+
- **Focused reviewer** — see [examples/reviewer-prompt-stack.json](examples/reviewer-prompt-stack.json). It denies file-writing tools, wraps prior chat history as background, removes the latest user message from history, then reinserts `{{lastUserMessage}}` as the explicit review target.
|
|
114
|
+
- **Read-only scout** — use `tools.allow` for `read`, `grep`, `find`, and `ls`; omit editing tools; cap `chat-history` with `maxChars`. Good for exploration turns where the model should report findings without changing files.
|
|
115
|
+
- **Surgical patcher** — keep the Pi mirror, require `read`, `edit`, and `bash`, strip assistant thinking from inserted history, and move `project-context` near the final user turn. Good for focused implementation passes.
|
|
116
|
+
- **SillyTavern DM writer** — see [examples/sillytavern-dm-writer-prompt-stack.json](examples/sillytavern-dm-writer-prompt-stack.json). It defines a Dungeon Master character with `{{char}}` / `{{user}}`, wraps prior adventure history, reinserts `{{lastUserMessage}}` as the current player action, and uses regex cleanup for OOC notes, secret-roll markers, dice notation, and `Player:` prefixes.
|
|
117
|
+
- **Payload lab** — include `active-model`, `date-cwd`, and variables slots, then add `compiled` regex rules for deterministic redaction or formatting. Pair it with `/payload next` or the web editor's capture view to audit exactly what changed.
|
|
118
|
+
- **Docs-only Pi expert** — allow only read/search tools, enable the `pi-docs` slot, and keep project context. Useful when you want answers grounded in the installed Pi docs instead of general memory.
|
|
119
|
+
|
|
120
|
+
### 🔧 Template variables
|
|
133
121
|
|
|
134
122
|
```json
|
|
135
|
-
"
|
|
136
|
-
"
|
|
137
|
-
|
|
138
|
-
"type": "string",
|
|
139
|
-
"scope": "session",
|
|
140
|
-
"description": "What we're working on",
|
|
141
|
-
"agentWritable": true
|
|
142
|
-
}
|
|
143
|
-
}
|
|
123
|
+
"variables": {
|
|
124
|
+
"char": "Konata",
|
|
125
|
+
"user": "User"
|
|
144
126
|
}
|
|
145
127
|
```
|
|
146
128
|
|
|
147
|
-
|
|
129
|
+
Use static variables for stable prompt constants, and ST-style macros for local prompt-time mutation:
|
|
148
130
|
|
|
149
131
|
```
|
|
150
|
-
|
|
132
|
+
{{setvar::mood::focused}}
|
|
133
|
+
{{getvar::mood}}
|
|
134
|
+
{{setsessionvar::topic::compiler cleanup}}
|
|
151
135
|
```
|
|
152
136
|
|
|
137
|
+
For durable project memory, use normal files in the repo rather than pi-forge prompt variables.
|
|
138
|
+
|
|
153
139
|
### 📦 SillyTavern migration
|
|
154
140
|
|
|
155
141
|
Bring your ST presets into Pi:
|
|
@@ -160,6 +146,8 @@ Bring your ST presets into Pi:
|
|
|
160
146
|
|
|
161
147
|
pi-forge converts the preset to a prompt stack and generates a migration report showing what was handled and what needs manual tweaking.
|
|
162
148
|
|
|
149
|
+
Deterministic SillyTavern `promptOnly` regex scripts are converted to pi-forge `regex.rules` as history-stage rules when they can be represented safely, including full-match token conversion, trim strings, depth fields, and clear user/assistant placements. Display-only, mixed prompt/display, DOM/browser, CSS/HTML decoration, JavaScript, unsupported placements, and invalid regex scripts stay report-only for manual review.
|
|
150
|
+
|
|
163
151
|
### 🔍 Prompt debugging
|
|
164
152
|
|
|
165
153
|
See exactly what gets sent to the model:
|
|
@@ -168,6 +156,8 @@ See exactly what gets sent to the model:
|
|
|
168
156
|
/payload next save=.pi/forge/payloads/last.json
|
|
169
157
|
```
|
|
170
158
|
|
|
159
|
+
Or open `/preset ui`, click **Arm payload**, send the next Pi prompt, and inspect the redacted provider payload in the browser.
|
|
160
|
+
|
|
171
161
|
Or preview your compiled prompt without sending anything:
|
|
172
162
|
|
|
173
163
|
```
|
|
@@ -188,6 +178,9 @@ Items are arranged in order. When the stack is active, pi-forge:
|
|
|
188
178
|
1. Builds a system prompt from your `system`-role blocks and slots, then applies it with the stack's `mode`.
|
|
189
179
|
2. Inserts `user`/`assistant` blocks and slots around the conversation history.
|
|
190
180
|
3. Expands `{{macros}}` like `{{lastUserMessage}}`, `{{date}}`, and custom variables.
|
|
181
|
+
4. Applies stack tool policy to Pi's active tool set and filters pi-forge-rendered tool/skill slots.
|
|
182
|
+
5. Applies enabled outgoing regex rules for the `history` and `compiled` stages.
|
|
183
|
+
6. Optionally applies destructive `finalize` regex rules when an assistant message finishes.
|
|
191
184
|
|
|
192
185
|
### Slots at a glance
|
|
193
186
|
|
|
@@ -198,8 +191,8 @@ Items are arranged in order. When the stack is active, pi-forge:
|
|
|
198
191
|
| `tool-guidelines` | Tool usage instructions |
|
|
199
192
|
| `skills` | Loaded Pi skills |
|
|
200
193
|
| `project-context` | Project instructions and context files |
|
|
201
|
-
| `variables` |
|
|
202
|
-
| `date` / `cwd` / `date-cwd` | Current date and working directory |
|
|
194
|
+
| `variables` | Static/session/turn template variables |
|
|
195
|
+
| `date` / `cwd` / `date-cwd` | Current date, optional current time, and working directory |
|
|
203
196
|
| `active-model` | Which model is being used |
|
|
204
197
|
| `append-system-prompt` | User's appended system prompt text |
|
|
205
198
|
| `pi-docs` | Pi documentation guidance |
|
|
@@ -224,26 +217,16 @@ Items are arranged in order. When the stack is active, pi-forge:
|
|
|
224
217
|
| `/preset status` | Show the active stack and diagnostics summary |
|
|
225
218
|
| `/preset diagnostics` | Show runtime diagnostics |
|
|
226
219
|
| `/preset reload` | Reload stacks from disk |
|
|
220
|
+
| `/preset migrate-stacks [--dry-run] [--overwrite] [--delete-legacy]` | Copy legacy `.pi/prompt-stacks` files into `.pi/forge/prompt-stacks` |
|
|
227
221
|
| `/preset ui [stop\|restart]` | Open, stop, or restart the web editor |
|
|
228
222
|
|
|
229
|
-
### State management
|
|
230
|
-
|
|
231
|
-
| Command | What it does |
|
|
232
|
-
|---------|-------------|
|
|
233
|
-
| `/state list` | Show all session state |
|
|
234
|
-
| `/state status` | Show state definitions and current values |
|
|
235
|
-
| `/state set <name> <value>` | Set a state variable |
|
|
236
|
-
| `/state get <name>` | Read a state variable |
|
|
237
|
-
| `/state clear [name]` | Clear state (all or by name) |
|
|
238
|
-
| `/preset vars ...` | Legacy variable commands kept for older stacks |
|
|
239
|
-
|
|
240
223
|
### Import & debug
|
|
241
224
|
|
|
242
225
|
| Command | What it does |
|
|
243
226
|
|---------|-------------|
|
|
244
227
|
| `/preset import-silly <path>` | Import a SillyTavern preset |
|
|
245
228
|
| `/intercept` | Show the next provider payload |
|
|
246
|
-
| `/payload next [save=<path>]` | Show and
|
|
229
|
+
| `/payload next [save=<path>]` | Show, save, and expose the next payload to the web editor |
|
|
247
230
|
|
|
248
231
|
## Common macros
|
|
249
232
|
|
|
@@ -274,6 +257,72 @@ Use these in block content to insert dynamic values:
|
|
|
274
257
|
{{clearsessionvar::name}} clear a session variable
|
|
275
258
|
```
|
|
276
259
|
|
|
260
|
+
### Filter and conditional macros
|
|
261
|
+
|
|
262
|
+
Nested macros are supported, and `::` separators are parsed only at the current macro depth.
|
|
263
|
+
|
|
264
|
+
| Macro | Expands to |
|
|
265
|
+
|-------|-----------|
|
|
266
|
+
| `{{trim::value}}` | `value` with leading/trailing whitespace removed |
|
|
267
|
+
| `{{upper::value}}` | Uppercase `value` |
|
|
268
|
+
| `{{lower::value}}` | Lowercase `value` |
|
|
269
|
+
| `{{json::value}}` | JSON string literal for `value` |
|
|
270
|
+
| `{{xml::value}}` | XML-escaped `value` |
|
|
271
|
+
| `{{ifvar::name::then::else}}` | `then` when a variable exists, otherwise `else` |
|
|
272
|
+
| `{{ifeq::name::expected::then::else}}` | `then` when a variable equals `expected`, otherwise `else` |
|
|
273
|
+
| `{{iftools::tool::then::else}}` | `then` when the selected tool list includes `tool`, otherwise `else` |
|
|
274
|
+
| `{{ifslot::slot::then::else}}` | `then` when the enabled stack items include `slot`, otherwise `else` |
|
|
275
|
+
|
|
276
|
+
Conditional branches are lazy: only the selected branch is expanded, so skipped branches cannot set or clear variables. The final `else` argument is optional and defaults to empty text.
|
|
277
|
+
|
|
278
|
+
### Trusted custom macros and slots
|
|
279
|
+
|
|
280
|
+
Custom macros and slots are registered by trusted extension code, not embedded in prompt-stack JSON. A stack can reference the registered name and pass declarative options; the executable `render` body lives in a Pi extension or another explicitly installed package.
|
|
281
|
+
|
|
282
|
+
```ts
|
|
283
|
+
import { registerMacro, registerSlot } from "@zihanw/pi-forge";
|
|
284
|
+
|
|
285
|
+
registerMacro({
|
|
286
|
+
name: "ticketId",
|
|
287
|
+
description: "Current ticket id from session variables.",
|
|
288
|
+
render: (ctx) => ctx.variables.toMacroText(ctx.variables.get("ticket.id")),
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
registerSlot({
|
|
292
|
+
name: "ticket-context",
|
|
293
|
+
description: "Render ticket context for the current task.",
|
|
294
|
+
options: {
|
|
295
|
+
heading: { type: "string", default: "Ticket context" },
|
|
296
|
+
},
|
|
297
|
+
render: (ctx) => [
|
|
298
|
+
String(ctx.options.heading ?? "Ticket context") + ":",
|
|
299
|
+
"- Ticket: " + ctx.variables.toMacroText(ctx.variables.get("ticket.id")),
|
|
300
|
+
"- Project: " + ctx.helpers.normalizePath(ctx.runtime.options.cwd),
|
|
301
|
+
].join("\n"),
|
|
302
|
+
});
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
The stack remains declarative:
|
|
306
|
+
|
|
307
|
+
```json
|
|
308
|
+
{
|
|
309
|
+
"kind": "slot",
|
|
310
|
+
"id": "ticket-context",
|
|
311
|
+
"enabled": true,
|
|
312
|
+
"role": "system",
|
|
313
|
+
"slot": "ticket-context",
|
|
314
|
+
"options": {
|
|
315
|
+
"heading": "Current ticket"
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Missing custom slots are validation warnings until the registering extension is installed and loaded. Built-in macros and slots use the same registry internally, so `getRegisteredMacros()` and `getRegisteredSlots()` can be used as implementation references.
|
|
321
|
+
|
|
322
|
+
For a complete copyable extension and stack, see [examples/custom-system-status-extension](examples/custom-system-status-extension). It registers a `{{cpuLoad}}` macro and a `machine-status` slot from a trusted Pi extension file.
|
|
323
|
+
|
|
324
|
+
When pi-forge is installed as a package, custom extensions can import `@zihanw/pi-forge`. When developing from a local checkout loaded through Pi settings, set an explicit local path as shown in the example README, such as `PI_FORGE_MODULE=/path/to/pi-forge/src/index.ts`. pi-forge keeps the macro/slot registry process-global so compatible local module copies share registrations.
|
|
325
|
+
|
|
277
326
|
## Stack reference
|
|
278
327
|
|
|
279
328
|
### Full item types
|
|
@@ -313,77 +362,150 @@ Valid roles: `system`, `user`, `assistant`, `custom`.
|
|
|
313
362
|
|
|
314
363
|
```json
|
|
315
364
|
"options": {
|
|
316
|
-
"includeLastUserMessage": false
|
|
365
|
+
"includeLastUserMessage": false,
|
|
366
|
+
"stripAssistantThinking": true,
|
|
367
|
+
"includeSummaries": true,
|
|
368
|
+
"toolMode": "keep",
|
|
369
|
+
"roles": ["user", "assistant"],
|
|
370
|
+
"maxMessages": 40,
|
|
371
|
+
"maxChars": 20000
|
|
317
372
|
}
|
|
318
373
|
```
|
|
319
374
|
|
|
320
375
|
Set to `false` when you use `{{lastUserMessage}}` after the history — prevents the user's message from appearing twice.
|
|
321
376
|
|
|
322
|
-
|
|
377
|
+
Set `stripAssistantThinking` to `true` to remove prior assistant thinking blocks from inserted chat history. Visible assistant text, tool calls, and tool result messages are preserved. This only affects history inserted by that slot and does not alter the current agent loop or stored transcript.
|
|
378
|
+
|
|
379
|
+
Use `includeSummaries: false` to omit Pi branch/compaction summary messages, `roles` to keep only specific message roles, `toolMode: "drop"` to remove prior tool-call/tool-result history, and `maxMessages` / `maxChars` to keep only recent history. When filters or limits can break tool-call pairs, pi-forge removes dangling tool calls/results instead of sending inconsistent tool history.
|
|
380
|
+
|
|
381
|
+
### Date slot options
|
|
382
|
+
|
|
383
|
+
Set `"includeTime": true` on a `date` or `date-cwd` slot to include the current time in `HH:MM:SS` after the current date.
|
|
384
|
+
|
|
385
|
+
### Structured slot format options
|
|
386
|
+
|
|
387
|
+
Structured runtime slots default to XML-style wrappers. Add `"format": "plain"` to `tools`, `tool-guidelines`, `skills`, `project-context`, or `variables` slots for compact newline-separated output.
|
|
323
388
|
|
|
324
389
|
```json
|
|
325
390
|
{
|
|
326
391
|
"kind": "slot",
|
|
327
|
-
"id": "
|
|
392
|
+
"id": "tools",
|
|
328
393
|
"enabled": true,
|
|
329
|
-
"role": "
|
|
330
|
-
"slot": "
|
|
394
|
+
"role": "system",
|
|
395
|
+
"slot": "tools",
|
|
396
|
+
"options": {
|
|
397
|
+
"format": "plain"
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
The default Pi mirror uses a few extra slot options:
|
|
403
|
+
|
|
404
|
+
```json
|
|
405
|
+
{
|
|
406
|
+
"slot": "tools",
|
|
331
407
|
"options": {
|
|
332
|
-
"
|
|
333
|
-
"
|
|
334
|
-
"includeMetadata": true,
|
|
335
|
-
"format": "xml",
|
|
336
|
-
"maxValueChars": 1200
|
|
408
|
+
"format": "plain",
|
|
409
|
+
"onlyWithSnippets": true
|
|
337
410
|
}
|
|
338
411
|
}
|
|
339
412
|
```
|
|
340
413
|
|
|
341
|
-
|
|
414
|
+
`tools.onlyWithSnippets` matches Pi's default "Available tools" section by hiding tools that do not provide prompt snippets. `tool-guidelines.heading`, `tool-guidelines.includePiDefaultGuidelines`, and `tool-guidelines.piStyle` make the guidelines slot match Pi's default heading and bullets. `skills.requireReadTool` hides skills unless the read tool is active, matching Pi's default behavior.
|
|
415
|
+
|
|
416
|
+
### Tool and skill policy
|
|
417
|
+
|
|
418
|
+
Prompt stacks can constrain tools and skills with stack-level `allow` or `deny` lists. Patterns are exact by default and support `*` wildcards.
|
|
419
|
+
|
|
420
|
+
```json
|
|
421
|
+
{
|
|
422
|
+
"tools": {
|
|
423
|
+
"allow": ["read", "bash"]
|
|
424
|
+
},
|
|
425
|
+
"skills": {
|
|
426
|
+
"deny": ["browser-danger"]
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
Use `allow` when only matching tools or skills should remain active. Use `deny` when everything except matching tools or skills should remain active. A single resource policy cannot contain both non-empty lists; mixed `allow` and `deny` entries are validation errors.
|
|
432
|
+
|
|
433
|
+
Tool policy is enforced through Pi's active tool list while the stack is active. pi-forge remembers the previous active tools and restores them when prompt stacks are disabled or switched to an unrestricted stack.
|
|
434
|
+
|
|
435
|
+
Skill policy filters skills rendered by pi-forge's `skills` slot. If a stack uses `mode: "append"` or `"prepend"`, Pi's base prompt may already contain unfiltered skills; use `mode: "replace"` when skill visibility must be controlled.
|
|
436
|
+
|
|
437
|
+
### Regex transforms
|
|
438
|
+
|
|
439
|
+
Prompt stacks can run deterministic regex replacements on model-bound prompt text and, optionally, finalized assistant messages. Outgoing rules support `history` and `compiled` stages. Destructive final-message cleanup uses `effect: "finalize"` at `stage: "compiled"` with the `messages` target. True display-only streaming transforms and provider-payload rewrites are not active yet.
|
|
342
440
|
|
|
343
441
|
```json
|
|
344
|
-
"
|
|
442
|
+
"regex": {
|
|
345
443
|
"schemaVersion": 1,
|
|
346
|
-
"
|
|
347
|
-
|
|
348
|
-
"
|
|
349
|
-
"
|
|
350
|
-
"
|
|
351
|
-
"
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
"
|
|
355
|
-
"
|
|
356
|
-
"
|
|
357
|
-
"userWritable": true
|
|
444
|
+
"rules": [
|
|
445
|
+
{
|
|
446
|
+
"id": "trim-ooc",
|
|
447
|
+
"enabled": true,
|
|
448
|
+
"stage": "history",
|
|
449
|
+
"effect": "outgoing",
|
|
450
|
+
"pattern": "\\(OOC:[^)]+\\)",
|
|
451
|
+
"flags": "gi",
|
|
452
|
+
"replace": "",
|
|
453
|
+
"roles": ["assistant"],
|
|
454
|
+
"maxMessages": 20
|
|
358
455
|
}
|
|
359
|
-
|
|
456
|
+
]
|
|
360
457
|
}
|
|
361
458
|
```
|
|
362
459
|
|
|
363
|
-
|
|
460
|
+
Use `stage: "history"` to transform messages inserted by the `chat-history` slot. Use `stage: "compiled"` with optional `targets: ["system"]`, `["messages"]`, or both to transform the final compiled prompt. Message rules can filter by `roles`, `maxMessages`, `maxChars`, `minDepth`, and `maxDepth`, where depth `0` is the latest message. Replacements use JavaScript syntax (`$&` for the full match, `$1` for captures; `$0` is also accepted as a full-match alias, and `$$` escapes a literal `$`). `trimStrings` removes literal strings from expanded replacement matches/captures, matching SillyTavern's Trim Out behavior. Supported regex flags are `g`, `i`, `m`, `s`, and `u`.
|
|
364
461
|
|
|
365
|
-
|
|
462
|
+
To clean a completed assistant message after streaming, use `effect: "finalize"`:
|
|
366
463
|
|
|
367
|
-
|
|
464
|
+
```json
|
|
465
|
+
{
|
|
466
|
+
"id": "finalize-ooc",
|
|
467
|
+
"enabled": true,
|
|
468
|
+
"stage": "compiled",
|
|
469
|
+
"effect": "finalize",
|
|
470
|
+
"targets": ["messages"],
|
|
471
|
+
"roles": ["assistant"],
|
|
472
|
+
"pattern": "\\s*\\(OOC:[^)]+\\)",
|
|
473
|
+
"flags": "gi",
|
|
474
|
+
"replace": ""
|
|
475
|
+
}
|
|
476
|
+
```
|
|
368
477
|
|
|
369
|
-
|
|
478
|
+
Warning: `finalize` runs at `message_end`, after raw output may already have streamed in the TUI. It returns a cleaned replacement message to Pi, so the original model output is not preserved in the stored transcript.
|
|
370
479
|
|
|
371
|
-
|
|
480
|
+
`effect: "outgoing"` changes model input. `effect: "finalize"` changes finalized assistant transcript content. `effect: "display"` and `"both"` validate with warnings but are ignored at runtime until true display transforms are implemented.
|
|
372
481
|
|
|
373
|
-
-
|
|
374
|
-
- Open questions (`agent.openQuestions`)
|
|
375
|
-
- Story state (`agent.storyState`)
|
|
376
|
-
- User-requested notes (`agent.notes`)
|
|
482
|
+
SillyTavern imports convert deterministic prompt-only `{{match}}` / `$0` full-match replacements to JavaScript `$&` (both `$0` and `$&` work in pi-forge), preserve original regex metadata in `source.sillytavern`, and run as history-stage rules so depth stays chat-relative. Display-only/browser/unsupported-placement scripts stay report-only. The web editor has a structured Regex dialog for these rule fields and preserves advanced unknown fields for raw JSON editing.
|
|
377
483
|
|
|
378
|
-
###
|
|
484
|
+
### Variables slot options
|
|
379
485
|
|
|
380
|
-
|
|
486
|
+
```json
|
|
487
|
+
{
|
|
488
|
+
"kind": "slot",
|
|
489
|
+
"id": "variables",
|
|
490
|
+
"enabled": true,
|
|
491
|
+
"role": "user",
|
|
492
|
+
"slot": "variables",
|
|
493
|
+
"options": {
|
|
494
|
+
"includeStatic": true,
|
|
495
|
+
"includeSession": true,
|
|
496
|
+
"includeTurn": false,
|
|
497
|
+
"format": "xml"
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
```
|
|
381
501
|
|
|
382
502
|
## Package setup for development
|
|
383
503
|
|
|
384
504
|
```bash
|
|
385
505
|
git clone <repo>
|
|
386
506
|
cd pi-forge
|
|
507
|
+
npm install
|
|
508
|
+
npm run build
|
|
387
509
|
# .pi/settings.json already points at the package root
|
|
388
510
|
pi # start Pi, trust the project, /reload if needed
|
|
389
511
|
```
|
|
@@ -400,6 +522,12 @@ Typecheck:
|
|
|
400
522
|
npm run typecheck
|
|
401
523
|
```
|
|
402
524
|
|
|
525
|
+
Build package output:
|
|
526
|
+
|
|
527
|
+
```bash
|
|
528
|
+
npm run build
|
|
529
|
+
```
|
|
530
|
+
|
|
403
531
|
## License
|
|
404
532
|
|
|
405
533
|
MIT
|