@zihanw/pi-forge 0.5.1 → 0.5.3
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/CHANGELOG.md +26 -0
- package/README.md +24 -20
- package/README.zh-CN.md +24 -20
- package/dist/agent-profile.js +5 -5
- package/dist/agent-profile.js.map +1 -1
- package/dist/codecs/agent-profile.js +4 -4
- package/dist/codecs/agent-profile.js.map +1 -1
- package/dist/codecs/prompt-stack.d.ts +2 -2
- package/dist/codecs/prompt-stack.d.ts.map +1 -1
- package/dist/codecs/prompt-stack.js +37 -20
- package/dist/codecs/prompt-stack.js.map +1 -1
- package/dist/compiler.d.ts.map +1 -1
- package/dist/compiler.js +81 -0
- package/dist/compiler.js.map +1 -1
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/lifecycle.js +17 -2
- package/dist/lifecycle.js.map +1 -1
- package/dist/preset-command.js +13 -13
- package/dist/preset-command.js.map +1 -1
- package/dist/preview.d.ts.map +1 -1
- package/dist/preview.js +27 -7
- package/dist/preview.js.map +1 -1
- package/dist/profile-command.js +6 -6
- package/dist/profile-command.js.map +1 -1
- package/dist/profile-service.js +4 -4
- package/dist/profile-service.js.map +1 -1
- package/dist/regex.d.ts +12 -0
- package/dist/regex.d.ts.map +1 -1
- package/dist/regex.js +81 -5
- package/dist/regex.js.map +1 -1
- package/dist/repositories/prompt-stack.js +8 -8
- package/dist/repositories/prompt-stack.js.map +1 -1
- package/dist/runtime/profile-runtime.js +3 -3
- package/dist/runtime/profile-runtime.js.map +1 -1
- package/dist/runtime/prompt-stack-runtime.js +1 -1
- package/dist/runtime/prompt-stack-runtime.js.map +1 -1
- package/dist/runtime/tool-policy-runtime.d.ts.map +1 -1
- package/dist/runtime/tool-policy-runtime.js +16 -4
- package/dist/runtime/tool-policy-runtime.js.map +1 -1
- package/dist/runtime/web-editor-runtime.js +7 -7
- package/dist/runtime/web-editor-runtime.js.map +1 -1
- package/dist/subagent-host.js +4 -4
- package/dist/subagent-host.js.map +1 -1
- package/dist/types.d.ts +17 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/web-editor/client-script.generated.d.ts.map +1 -1
- package/dist/web-editor/client-script.generated.js +1 -1
- package/dist/web-editor/client-script.generated.js.map +1 -1
- package/dist/web-editor/client-styles.generated.d.ts.map +1 -1
- package/dist/web-editor/client-styles.generated.js +1 -1
- package/dist/web-editor/client-styles.generated.js.map +1 -1
- package/dist/web-editor/page.d.ts +1 -1
- package/dist/web-editor/page.d.ts.map +1 -1
- package/dist/web-editor/page.js +2 -2
- package/dist/web-editor/page.js.map +1 -1
- package/dist/web-editor/server.js +58 -5
- package/dist/web-editor/server.js.map +1 -1
- package/dist/web-editor/styles.d.ts.map +1 -1
- package/dist/web-editor/styles.js +26 -1
- package/dist/web-editor/styles.js.map +1 -1
- package/dist/web-editor/types.d.ts +18 -1
- package/dist/web-editor/types.d.ts.map +1 -1
- package/dist/web-host.d.ts +5 -3
- package/dist/web-host.d.ts.map +1 -1
- package/dist/web-host.js +114 -26
- package/dist/web-host.js.map +1 -1
- package/docs/README.md +5 -5
- package/docs/concepts/prompt-stacks.md +19 -15
- package/docs/design/architecture-0.5.md +10 -0
- package/docs/development/roadmap.md +16 -0
- package/docs/getting-started.md +1 -1
- package/docs/guides/use-cases.md +4 -2
- package/docs/guides/web-editor.md +13 -8
- package/docs/reference/configuration.md +4 -1
- package/docs/reference/features.md +5 -0
- package/docs/reference/stack-schema.md +58 -1
- package/docs/zh-CN/README.md +4 -4
- package/docs/zh-CN/concepts/prompt-stacks.md +16 -10
- package/docs/zh-CN/guides/web-editor.md +11 -6
- package/examples/custom-system-status-extension/README.md +6 -6
- package/examples/custom-system-status-extension/index.ts +15 -8
- package/examples/fake-assistant-direct-output-prompt-stack.json +48 -0
- package/examples/hack-prompt-stack.json +118 -0
- package/examples/minimal-prompt-stack.json +40 -0
- package/package.json +2 -2
- package/examples/image-reader-prompt-stack.json +0 -114
- package/examples/reviewer-prompt-stack.json +0 -104
|
@@ -14,7 +14,7 @@ Use `/preset ui restart` to replace its server or `/preset ui stop` to close it.
|
|
|
14
14
|
|
|
15
15
|
The editor binds to an available `127.0.0.1` port and uses a session token. Multiple Pi projects can run editors simultaneously. Lifecycle reinitialization reuses the existing editor URL for the same project when possible.
|
|
16
16
|
|
|
17
|
-
Reads, preview, resources, and payload inspection remain available as appropriate, but writes require Pi to trust the project. Files are constrained to
|
|
17
|
+
Reads, preview, resources, and payload inspection remain available as appropriate, but writes require Pi to trust the project. Files are constrained to Pi Forge's Preset/Profile storage. Never expose or proxy the editor URL to an untrusted network.
|
|
18
18
|
|
|
19
19
|
Choose a preferred port in `.pi/forge/config.json`:
|
|
20
20
|
|
|
@@ -28,12 +28,17 @@ Choose a preferred port in `.pi/forge/config.json`:
|
|
|
28
28
|
|
|
29
29
|
If that port is unavailable, pi-forge selects another and shows the actual URL.
|
|
30
30
|
|
|
31
|
-
##
|
|
31
|
+
## Interface language
|
|
32
32
|
|
|
33
|
-
The
|
|
33
|
+
The editor interface is available in English and Chinese. Use the language selector in the top bar (Auto / English / 中文); the choice is written to `webEditor.locale` in the project config. `Auto` (the default) follows the browser language, and the initial page render also honors the browser's `Accept-Language` header. Interface chrome, built-in Preset/Profile surfaces, and the preview/diff dock are localized; compiler diagnostics, provider-contributed settings pages, and authored Preset content stay in their authored language.
|
|
34
|
+
|
|
35
|
+
## Preset workspace
|
|
36
|
+
|
|
37
|
+
The Preset workspace provides:
|
|
34
38
|
|
|
35
39
|
- creation from the default Pi-mirror layout;
|
|
36
|
-
-
|
|
40
|
+
- an ordered **Stack** tab for Block/Slot composition;
|
|
41
|
+
- structured metadata, policy, parameters, context, and Regex editing;
|
|
37
42
|
- drag-and-drop item order and enable/disable controls;
|
|
38
43
|
- validation and a full compiled preview;
|
|
39
44
|
- registered-tool and loaded-skill search with exact-name chips and wildcard patterns;
|
|
@@ -43,15 +48,15 @@ The stack workspace provides:
|
|
|
43
48
|
- payload arming and redacted captured-payload inspection;
|
|
44
49
|
- light and dark themes.
|
|
45
50
|
|
|
46
|
-
Existing IDs are immutable during edit. Use **More → Fork** to create a different ID without breaking
|
|
51
|
+
Existing IDs are immutable during edit. Use **More → Fork** to create a different ID without breaking Profile references or the active selection. The compact selector attached to **New preset** (default `Project`) chooses where new Presets, imports, and forks are written: `Global` targets the user-global `~/.pi/forge/prompt-stacks`, `Project` targets `.pi/forge/prompt-stacks`. Those paths keep their pre-0.5.3 names for compatibility. Less-used capture, fork, import, export, and delete actions live under **More** so the Stack and Preview/Diff panes keep the available viewport. Preset rows show a `global` badge, and save/delete routes use `global:<id>` for exact global mutations. Legacy resources remain editable in place.
|
|
47
52
|
|
|
48
|
-
Saves, imports, forks, and deletes reload
|
|
53
|
+
Saves, imports, forks, and deletes reload Preset state into the current Pi session. When another surface changes a referenced Preset, returning to Profiles refreshes Profile resolution.
|
|
49
54
|
|
|
50
55
|
## Agent-profile workspace
|
|
51
56
|
|
|
52
|
-
The
|
|
57
|
+
The Profile list shows each Profile's ID, display metadata, model, thinking level, Preset, resolution state, auto-activation, last-applied provenance, and a `project`/`global` scope badge. Same-ID shadow pairs are marked `shadows global:<id>` or `shadowed by project:<id>`.
|
|
53
58
|
|
|
54
|
-
Trusted projects can create
|
|
59
|
+
Trusted projects can create Profiles in either scope: the scope selector beside **New profile** (default `project`) chooses whether to write the user-global `~/.pi/forge/agent-profiles` or the project `.pi/forge/agent-profiles`. Global Profiles can be edited, validated, saved, applied once, and deleted through explicit `global:<id>` routes; unqualified routes stay project-only. When editing a global Profile, the Preset dropdown offers only global Presets. Model choices come from Pi's model registry, thinking choices reflect model support, and Preset choices come from the shared repository. The editor rejects a second auto-activation Profile within the same scope.
|
|
55
60
|
|
|
56
61
|
The runtime/provenance card separates current runtime state, last-applied snapshot, source-definition changes, and field-level runtime drift.
|
|
57
62
|
|
|
@@ -9,13 +9,16 @@ Project configuration lives in `.pi/forge/config.json` and is loaded only for a
|
|
|
9
9
|
```json
|
|
10
10
|
{
|
|
11
11
|
"webEditor": {
|
|
12
|
-
"port": 41738
|
|
12
|
+
"port": 41738,
|
|
13
|
+
"locale": "auto"
|
|
13
14
|
}
|
|
14
15
|
}
|
|
15
16
|
```
|
|
16
17
|
|
|
17
18
|
The port is preferred, not guaranteed. The editor binds only to `127.0.0.1` and chooses another available port when necessary.
|
|
18
19
|
|
|
20
|
+
`webEditor.locale` selects the editor's interface language: `"en"`, `"zh-CN"`, or `"auto"` (default). `"auto"` follows the browser language. The language selector in the editor's top bar writes this setting; `"auto"` removes the key.
|
|
21
|
+
|
|
19
22
|
## Experimental subagents
|
|
20
23
|
|
|
21
24
|
Subagent configuration is owned by the optional `@zihanw/pi-forge-subagents` package. Dedicated files are `.pi/forge/subagents.json` for a trusted project and `~/.pi/forge/subagents.json` for user defaults. Legacy `.pi/forge/config.json` / `~/.pi/forge/config.json` `subagents` sections are read-only fallback material and emit a warning.
|
|
@@ -72,12 +72,16 @@ This file tracks the currently implemented feature surface for agent profiles, t
|
|
|
72
72
|
- Chat history can filter summaries/roles, drop prior tool history, and cap recent history by message count or approximate characters with dangling tool calls/results repaired after filtering.
|
|
73
73
|
- Duplicate chat-history warning unless explicitly allowed.
|
|
74
74
|
- Synthetic `user`, `assistant`, and hidden `custom` messages.
|
|
75
|
+
- Optional consecutive-role merge (`context.mergeConsecutiveRoles`/`mergeSeparator`): runs of consecutive stack-authored `user`/`assistant` items compile into a single message; chat-history output and custom-role items are hard boundaries, and merging runs after compiled-stage regex.
|
|
76
|
+
- Validation warning when an enabled `system` item appears after non-system items (cross-channel item position has no effect on compilation).
|
|
75
77
|
- Context rewrite limited to the first provider request of each user-submitted turn.
|
|
76
78
|
- Tool policy filters Pi's active tool list while the stack is active and restores the previous active tools when the stack no longer applies.
|
|
77
79
|
- Tool policy restores its pre-policy baseline during extension shutdown so Pi reload/session replacement cannot carry a restricted built-in tool set into the replacement runtime.
|
|
78
80
|
- Startup tool enforcement waits until extension `session_start` configuration is complete, reasserts before user input and turns, and blocks disallowed model tool calls at execution time.
|
|
79
81
|
- Skill policy filters skills rendered by pi-forge `skills` slots.
|
|
80
82
|
- Outgoing regex transforms can run after `chat-history` insertion and after final prompt compilation.
|
|
83
|
+
- Per-rule `frequency: "request"` re-runs an outgoing message rule on every tool-result follow-up request over Pi's full natural context; the default `"turn"` keeps first-request-only behavior.
|
|
84
|
+
- `finalize` rules whose `roles` explicitly include `"toolResult"` also rewrite stored tool-result messages at completion time (destructive, documented); rules without `roles` stay assistant-only.
|
|
81
85
|
- Finalize regex transforms can rewrite completed assistant messages at `message_end`.
|
|
82
86
|
|
|
83
87
|
## Regex Transforms
|
|
@@ -197,6 +201,7 @@ This file tracks the currently implemented feature surface for agent profiles, t
|
|
|
197
201
|
- Collapsible prompt-stack sidebar.
|
|
198
202
|
- Collapsible stack metadata panel and main-area tabs for Items, Regex, Policy, and Stack JSON/context/variables work.
|
|
199
203
|
- Light/dark theme toggle, button icons, and tooltips for common actions.
|
|
204
|
+
- English/中文 interface switch (`webEditor.locale`: `"en"`, `"zh-CN"`, or `"auto"` following the browser language); contributed settings tabs remain provider-authored and are not translated.
|
|
200
205
|
- Unsaved-change badge in the top bar.
|
|
201
206
|
- Create a new prompt stack from the browser, including when no stack files exist yet; new stacks start from the default Pi prompt mirror layout.
|
|
202
207
|
- View immutable stack ID and edit name, mode, `autoActivate`, description, and existing stack file content; use Fork to create a new ID.
|
|
@@ -25,7 +25,7 @@ Block:
|
|
|
25
25
|
}
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
Valid roles are `system`, `user`, `assistant`, and `custom`. Custom-role content participates in compilation
|
|
28
|
+
Valid roles are `system`, `user`, `assistant`, and `custom`. Custom-role content participates in compilation and reaches the provider as a `user` message: Pi converts `custom` messages to `user` when it builds the wire request, so the wire carries no distinct custom role. Custom-role items never merge with other items (see [Context options](#context-options)).
|
|
29
29
|
|
|
30
30
|
Slot:
|
|
31
31
|
|
|
@@ -45,12 +45,30 @@ Slot:
|
|
|
45
45
|
|
|
46
46
|
Item IDs must be unique. Unsupported slots and missing required custom registrations produce diagnostics. Multiple chat-history slots warn unless explicitly permitted.
|
|
47
47
|
|
|
48
|
+
Item position only matters within each channel: all `system` items join the system prompt in their relative order, and all non-system items become messages in their relative order. A `system` item placed after non-system items therefore has no effect on placement and produces a validation warning; roles are never silently converted. Use a `user` item for in-conversation injection.
|
|
49
|
+
|
|
48
50
|
## Modes
|
|
49
51
|
|
|
50
52
|
- `replace` replaces Pi's base system prompt; empty output falls back to the base.
|
|
51
53
|
- `append` places stack system text after Pi's base.
|
|
52
54
|
- `prepend` places stack system text before Pi's base.
|
|
53
55
|
|
|
56
|
+
## Context options
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"context": {
|
|
61
|
+
"allowDuplicateChatHistory": false,
|
|
62
|
+
"mergeConsecutiveRoles": true,
|
|
63
|
+
"mergeSeparator": "\n\n"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
- `allowDuplicateChatHistory` permits multiple enabled chat-history slots; otherwise only the first expands.
|
|
69
|
+
- `mergeConsecutiveRoles` (default `false`) merges runs of consecutive stack items that share the same declared role into a single message, joined by `mergeSeparator` (default a blank line). Only stack-authored `user`/`assistant` items merge: chat-history output (including the implicit history tail) and `custom` items are hard boundaries, and merging runs after compiled-stage regex so regex semantics are unchanged. The web editor preview reflects the merged layout.
|
|
70
|
+
- `mergeSeparator` is inserted verbatim between merged texts and may be an empty string.
|
|
71
|
+
|
|
54
72
|
## Chat-history options
|
|
55
73
|
|
|
56
74
|
```json
|
|
@@ -151,6 +169,43 @@ Regex rules are ordered, deterministic JavaScript `RegExp` replacements. There i
|
|
|
151
169
|
|
|
152
170
|
Message rules may filter by `roles`, `maxMessages`, `maxChars`, `minDepth`, and `maxDepth` (depth 0 is latest). `trimStrings` removes literal strings from expanded matches/captures. Supported flags are `g`, `i`, `m`, `s`, and `u`. Replacements use JavaScript `$&`/`$1`; `$0` is accepted as a full-match alias and `$$` yields a literal dollar sign.
|
|
153
171
|
|
|
172
|
+
### Frequency
|
|
173
|
+
|
|
174
|
+
Outgoing rules default to `"frequency": "turn"`: they run during the full compilation on the first provider request of each user turn. Tool-result follow-up requests receive Pi's natural context, so a turn-scoped rule never sees tool output until the next user turn.
|
|
175
|
+
|
|
176
|
+
Set `"frequency": "request"` to also run an outgoing message rule on every tool-result follow-up request, applied to Pi's full natural context:
|
|
177
|
+
|
|
178
|
+
```json
|
|
179
|
+
{
|
|
180
|
+
"id": "redact-api-keys",
|
|
181
|
+
"stage": "history",
|
|
182
|
+
"effect": "outgoing",
|
|
183
|
+
"frequency": "request",
|
|
184
|
+
"pattern": "\\b(sk-[A-Za-z0-9_-]{12,})\\b",
|
|
185
|
+
"flags": "g",
|
|
186
|
+
"replace": "[REDACTED]"
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Each provider request is rebuilt from the stored transcript, so re-applying a rule to older messages is wire-consistent and never doubles. History-stage rules and compiled-stage rules with a `messages` target both participate; on follow-ups there is no stack layout rewrite, so both stages collapse onto the natural context (history-stage rules run first). `frequency` has no effect on `finalize` rules or system-only targets, and validation says so. It is wire-only scrubbing: the stored transcript keeps the original text.
|
|
191
|
+
|
|
192
|
+
Regex rules only cover the text targets and patterns you declare. They cannot recognize every credential format and do not scan system text, tool definitions, or arbitrary request metadata unless those targets are explicitly supported and selected. Treat them as deterministic text transforms, not as a security boundary.
|
|
193
|
+
|
|
194
|
+
To scrub the same recognized shapes from stored assistant/tool-result text, pair a request-frequency outgoing rule with a `finalize` rule:
|
|
195
|
+
|
|
196
|
+
```json
|
|
197
|
+
{
|
|
198
|
+
"id": "redact-api-keys-finalize",
|
|
199
|
+
"stage": "compiled",
|
|
200
|
+
"effect": "finalize",
|
|
201
|
+
"targets": ["messages"],
|
|
202
|
+
"roles": ["assistant", "toolResult"],
|
|
203
|
+
"pattern": "\\b(sk-[A-Za-z0-9_-]{12,})\\b",
|
|
204
|
+
"flags": "g",
|
|
205
|
+
"replace": "[REDACTED]"
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
154
209
|
Outgoing rules change future model input. To destructively change a completed assistant transcript message:
|
|
155
210
|
|
|
156
211
|
```json
|
|
@@ -170,3 +225,5 @@ Outgoing rules change future model input. To destructively change a completed as
|
|
|
170
225
|
> `finalize` runs at `message_end`, after raw output may have streamed. It replaces the stored assistant message, so the original output is not preserved.
|
|
171
226
|
|
|
172
227
|
`effect: "outgoing"` and `"finalize"` are the only valid effects; `"display"` and `"both"` are rejected during validation. Runtime diagnostics report match and changed-segment counts.
|
|
228
|
+
|
|
229
|
+
`finalize` applies to assistant messages by default, and additionally to stored tool-result messages when a rule's `roles` explicitly includes `"toolResult"` — useful for scrubbing secrets out of stored tool output before the follow-up request replays it. Rules without `roles` keep assistant-only behavior, user messages are never finalized, and unsupported roles warn.
|
package/docs/zh-CN/README.md
CHANGED
|
@@ -4,16 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
## 从这里开始
|
|
6
6
|
|
|
7
|
-
- [快速上手](getting-started.md)
|
|
8
|
-
- [
|
|
9
|
-
- [Agent
|
|
7
|
+
- [快速上手](getting-started.md):安装、创建预设、打开编辑器并保存 Profile。
|
|
8
|
+
- [预设与堆栈](concepts/prompt-stacks.md):完整预设及其有序 Block/Slot 编排。
|
|
9
|
+
- [Agent Profile](concepts/agent-profiles.md):一次性模型/思考等级/预设组合。
|
|
10
10
|
|
|
11
11
|
## 指南
|
|
12
12
|
|
|
13
13
|
- [Web 编辑器](guides/web-editor.md)
|
|
14
14
|
- [迁移到 0.5](guides/migrating-to-0.5.md)
|
|
15
15
|
- [实验性前台 delegation](guides/delegation.md):启用前请先阅读安全边界。
|
|
16
|
-
- [
|
|
16
|
+
- [预设使用场景(英文)](../guides/use-cases.md)
|
|
17
17
|
|
|
18
18
|
自定义 macros/slots 和调试的完整说明目前以英文版为准:
|
|
19
19
|
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 预设与堆栈
|
|
2
2
|
|
|
3
3
|
[中文文档](../README.md) · [English](../../concepts/prompt-stacks.md)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**Preset(预设)**是 Pi Forge 应用的完整声明式资源;其中由固定 **Block** 和动态 **Slot** 组成的有序 prompt 编排叫 **Stack(堆栈)**。同一份预设还会携带策略、Regex、参数和扩展引用。
|
|
6
|
+
|
|
7
|
+
> **0.5.3 兼容说明。** UI 使用“预设 → 堆栈”术语。这个补丁版本仍保留文件路径、JSON type、Profile 字段、API 路由和内部类型中的 `prompt-stack` / `promptStack` 拼写。
|
|
8
|
+
|
|
9
|
+
预设当前放在兼容路径 `.pi/forge/prompt-stacks/` 或用户全局 `~/.pi/forge/prompt-stacks/`。命令接受 `reviewer`、`project:reviewer` 和 `global:reviewer`;未限定 ID 优先解析项目预设,项目预设会遮蔽同 ID 全局预设。重复 ID 只在同一 scope 内算错误。
|
|
6
10
|
|
|
7
11
|
## 编译模型
|
|
8
12
|
|
|
@@ -13,8 +17,8 @@ Prompt stack 是一份有序、声明式的 prompt 与策略描述,由固定 *
|
|
|
13
17
|
3. 在可移动 `chat-history` 周围插入 user/assistant 消息。
|
|
14
18
|
4. 用 forge-v1 编译 `runtime.*` / `parameters.*` / `extensions.*` 模板。
|
|
15
19
|
5. 对 Pi 执行工具策略,并过滤 pi-forge 渲染的 skills。
|
|
16
|
-
6. 应用 history/compiled outgoing regex
|
|
17
|
-
7. 可选地在消息完成后应用破坏性的 finalize regex
|
|
20
|
+
6. 应用 history/compiled outgoing regex。`frequency: "request"` 的 outgoing 消息规则还会在 tool 结果后续请求上对 Pi 的完整自然上下文再次运行;默认 `"turn"` 保持仅在每轮首次请求运行。
|
|
21
|
+
7. 可选地在消息完成后应用破坏性的 finalize regex;`roles` 显式包含 `"toolResult"` 的 finalize 规则还会改写存储的 tool 结果消息。
|
|
18
22
|
|
|
19
23
|
## 常用历史布局
|
|
20
24
|
|
|
@@ -25,18 +29,20 @@ Prompt stack 是一份有序、声明式的 prompt 与策略描述,由固定 *
|
|
|
25
29
|
|
|
26
30
|
这样既保留旧上下文,又只在最后明确出现一次当前请求。History 还可以过滤 summary/role、去掉旧工具消息、移除 assistant thinking,并限制消息数或字符数。
|
|
27
31
|
|
|
32
|
+
堆栈还可以通过 `context.mergeConsecutiveRoles`(及可选的 `context.mergeSeparator`)把连续的同角色条目合并成一条消息;chat-history 输出和 custom 角色条目永远不会被合并。详见英文 [Preset schema](../../reference/stack-schema.md#context-options)。
|
|
33
|
+
|
|
28
34
|
## 策略边界
|
|
29
35
|
|
|
30
|
-
工具 `allow`/`deny` 会修改 Pi active tools,并在 tool call 时再次检查。具体的 `allow` 列表会从 Pi
|
|
36
|
+
工具 `allow`/`deny` 会修改 Pi active tools,并在 tool call 时再次检查。具体的 `allow` 列表会从 Pi 的完整已注册工具目录中选择,因此可以启用预设激活前处于 inactive 状态的工具;`deny` 只从原 active baseline 中移除工具,`allow: ["*"]` 仍表示不限制且不会启用全部工具。Skill policy 只过滤 pi-forge 渲染给模型的列表;它不能阻止明确调用,也不是安全边界。若必须控制模型可见 skill 列表,请使用 `replace`,因为 Pi 的基础 prompt 可能已经在 `append`/`prepend` 内容之前列出 skills。
|
|
31
37
|
|
|
32
38
|
## Scope 与自动启用
|
|
33
39
|
|
|
34
|
-
- 只有显式设置 `"autoActivate": true`
|
|
35
|
-
-
|
|
36
|
-
- 同 ID
|
|
40
|
+
- 只有显式设置 `"autoActivate": true` 的预设参与自动启用;文件名(包括 `default.json`)没有特殊作用。
|
|
41
|
+
- 项目预设优先于全局预设;项目 scope 存在候选时,即使项目候选无效或冲突也会 fail closed,不会回退到全局预设。
|
|
42
|
+
- 同 ID 项目预设会遮蔽全局预设,包括无效 shadow 或显式 opt-out。
|
|
37
43
|
- `/preset use none` 会记录 session branch 的 opt-out。
|
|
38
|
-
- Active
|
|
44
|
+
- Active Preset 选择会跟随 Pi session tree branch。
|
|
39
45
|
- 恢复的 branch 状态优先于新 session 自动启用。
|
|
40
|
-
- 自动启用的
|
|
46
|
+
- 自动启用的 Agent Profile 优先于独立预设 autoload。
|
|
41
47
|
|
|
42
48
|
完整字段见英文 [stack schema](../../reference/stack-schema.md)(schema v2 使用 `parameters`),模板语法见[参考](../../reference/macros-and-slots.md)。
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
`/preset ui restart` 会替换 server,`/preset ui stop` 会关闭它。
|
|
12
12
|
|
|
13
|
-
编辑器绑定在带 session token 的可用 `127.0.0.1` 端口;多个项目可以同时运行。读取、预览和 payload 检查在合适范围内可用;写入要求 Pi 信任项目,并且文件被限制在
|
|
13
|
+
编辑器绑定在带 session token 的可用 `127.0.0.1` 端口;多个项目可以同时运行。读取、预览和 payload 检查在合适范围内可用;写入要求 Pi 信任项目,并且文件被限制在 Pi Forge 的预设/Profile 存储内。可以在 `.pi/forge/config.json` 中设置偏好端口:
|
|
14
14
|
|
|
15
15
|
```json
|
|
16
16
|
{
|
|
@@ -20,11 +20,16 @@
|
|
|
20
20
|
|
|
21
21
|
端口被占用时会自动选择其他端口。请不要把带 token 的编辑器 URL 暴露或代理到不可信网络。写入操作要求项目已被 Pi 信任。
|
|
22
22
|
|
|
23
|
-
##
|
|
23
|
+
## 界面语言
|
|
24
|
+
|
|
25
|
+
编辑器界面提供英文和中文。使用顶栏的语言选择器(Auto / English / 中文);选择会写入项目配置中的 `webEditor.locale`。默认为 `Auto`,跟随浏览器语言,首次页面渲染也会参考浏览器的 `Accept-Language` 请求头。界面框架、内置预设/Profile 界面以及预览/差异停靠栏均已本地化;编译器诊断信息、插件提供的设置页面以及预设中自行编写的内容保持其原始语言。
|
|
26
|
+
|
|
27
|
+
## 预设工作区
|
|
24
28
|
|
|
25
29
|
支持:
|
|
26
30
|
|
|
27
|
-
- 从默认 Pi mirror
|
|
31
|
+
- 从默认 Pi mirror 新建预设;
|
|
32
|
+
- 在 **堆栈** tab 中编排有序的 Block/Slot;
|
|
28
33
|
- 结构化和原始 JSON 编辑;
|
|
29
34
|
- 拖拽排序、启用/禁用、校验和完整编译预览;
|
|
30
35
|
- 工具/skill 搜索、精确名称 chips 和通配符策略;
|
|
@@ -32,13 +37,13 @@
|
|
|
32
37
|
- 原生 pi-forge JSON 导入;
|
|
33
38
|
- 导出、fork、删除和 payload 捕获。
|
|
34
39
|
|
|
35
|
-
已有 ID 在编辑时不可修改;需要新 ID 时使用 **Fork**,避免破坏
|
|
40
|
+
已有 ID 在编辑时不可修改;需要新 ID 时使用 **Fork**,避免破坏 Profile 引用和当前选择。工具栏的 scope 下拉(默认 `project`)决定新建、导入和 fork 的写入位置:选择 `global` 写入用户全局 `~/.pi/forge/prompt-stacks`,选择 `project` 写入项目 `.pi/forge/prompt-stacks`;这些目录名在 0.5.3 中为兼容性暂时保留。列表会为全局预设显示 `global` badge;保存和删除通过 `global:<id>` 路由精确作用于全局文件。保存、导入、fork 和删除后会重新加载当前 Pi session。
|
|
36
41
|
|
|
37
42
|
## Agent profile 工作区
|
|
38
43
|
|
|
39
|
-
列表显示
|
|
44
|
+
列表显示 Profile ID、名称、模型、思考等级、预设、校验状态、auto-activation 和 last-applied provenance。每个 Profile 都带 `project` / `global` scope badge;同 ID 的 shadow 对会显示 `shadows global:<id>` 或 `shadowed by project:<id>`。
|
|
40
45
|
|
|
41
|
-
可信项目通过 **New profile** 旁的 scope 下拉(默认 `project`)选择目标 scope:选择 `global` 写入用户全局 `~/.pi/forge/agent-profiles`,选择 `project` 写入项目 `.pi/forge/agent-profiles`。全局
|
|
46
|
+
可信项目通过 **New profile** 旁的 scope 下拉(默认 `project`)选择目标 scope:选择 `global` 写入用户全局 `~/.pi/forge/agent-profiles`,选择 `project` 写入项目 `.pi/forge/agent-profiles`。全局 Profile 可通过显式 `global:<id>` 路由编辑、校验、保存、一次性应用和删除;未限定路由始终只作用于项目资源。编辑全局 Profile 时,预设下拉只显示全局预设。Model 选项来自 Pi registry,thinking 选项反映模型支持,预设选项来自同一个 repository。编辑器会拒绝同 scope 内第二个 auto-activation Profile。
|
|
42
47
|
|
|
43
48
|
## Delegation
|
|
44
49
|
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
This example shows how trusted pi-forge extension modules can register a custom macro and custom slot without importing `@zihanw/pi-forge` from a loose Pi extension file.
|
|
4
4
|
|
|
5
|
-
It registers:
|
|
5
|
+
It registers two renderers that sample the machine when the prompt is compiled:
|
|
6
6
|
|
|
7
|
-
- `{{ extensions.cpuLoad }}` macro: one-line CPU load summary.
|
|
8
|
-
- `machine-status` slot: CPU load, OS load average, memory, and uptime
|
|
7
|
+
- `{{ extensions.cpuLoad }}` macro: one-line CPU load summary sampled when that macro is rendered.
|
|
8
|
+
- `machine-status` slot: CPU load, OS load average, memory, and uptime sampled when that slot is rendered.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
This is compile-time telemetry, not a continuous sampler: no background timer runs and nothing streams while the model is generating. pi-forge performs the full Stack compilation for the first provider request of each user turn (and for explicit Preview/Diff compilation); tool-result follow-up requests do not rerun the full Stack. The macro and slot render independently, so their snapshots may differ slightly.
|
|
11
11
|
|
|
12
12
|
## Try It
|
|
13
13
|
|
|
@@ -26,7 +26,7 @@ Start Pi, trust the project if prompted, then run:
|
|
|
26
26
|
/preset use custom-system-status
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
Use `/preset diagnostics` to confirm the extension file is listed under loaded pi-forge extensions.
|
|
29
|
+
Use `/preset diagnostics` to confirm the extension file is listed under loaded pi-forge extensions. Start another user turn or recompile Preview to sample again. `/preset reload` is only needed after changing the extension or stack files.
|
|
30
30
|
|
|
31
31
|
## Where To Put The Extension
|
|
32
32
|
|
|
@@ -54,7 +54,7 @@ Each module exports a default function or named `register` function:
|
|
|
54
54
|
```ts
|
|
55
55
|
export default function register(api) {
|
|
56
56
|
api.registerMacro({ name: "cpuLoad", dependencies: [], render: ({ env, helpers }) => "..." });
|
|
57
|
-
api.registerSlot({ name: "machine-status", render: () => "..." });
|
|
57
|
+
api.registerSlot({ name: "machine-status", dependencies: [], render: ({ options, helpers }) => "..." });
|
|
58
58
|
}
|
|
59
59
|
```
|
|
60
60
|
|
|
@@ -12,10 +12,10 @@ interface ForgeRegistrationApi {
|
|
|
12
12
|
name: string;
|
|
13
13
|
source?: string;
|
|
14
14
|
description?: string;
|
|
15
|
+
dependencies?: string[];
|
|
15
16
|
options?: Record<string, unknown>;
|
|
16
17
|
render: (ctx: {
|
|
17
18
|
options: Record<string, unknown>;
|
|
18
|
-
format: () => "xml" | "plain" | "json";
|
|
19
19
|
helpers: {
|
|
20
20
|
escapeXml(value: string): string;
|
|
21
21
|
plainBullet(label: string, value: string): string;
|
|
@@ -24,7 +24,7 @@ interface ForgeRegistrationApi {
|
|
|
24
24
|
}): () => void;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
interface SystemStatusSnapshot {
|
|
27
|
+
export interface SystemStatusSnapshot {
|
|
28
28
|
logicalCores: number;
|
|
29
29
|
cpuModel: string;
|
|
30
30
|
load1: number;
|
|
@@ -37,18 +37,24 @@ interface SystemStatusSnapshot {
|
|
|
37
37
|
uptimeSeconds: number;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
export default function registerSystemStatus(
|
|
40
|
+
export default function registerSystemStatus(
|
|
41
|
+
api: ForgeRegistrationApi,
|
|
42
|
+
sampleSystemStatus: () => SystemStatusSnapshot = readSystemStatus,
|
|
43
|
+
): void {
|
|
41
44
|
api.registerMacro({
|
|
42
45
|
name: "cpuLoad",
|
|
43
46
|
source: "pi-forge-example-system-status",
|
|
44
|
-
description: "
|
|
45
|
-
|
|
47
|
+
description: "Machine CPU load sampled when the prompt is compiled.",
|
|
48
|
+
dependencies: [],
|
|
49
|
+
// Renderers run during prompt compilation. Read a fresh snapshot for each render.
|
|
50
|
+
render: () => formatCpuLoad(Object.freeze(sampleSystemStatus())),
|
|
46
51
|
});
|
|
47
52
|
|
|
48
53
|
api.registerSlot({
|
|
49
54
|
name: "machine-status",
|
|
50
55
|
source: "pi-forge-example-system-status",
|
|
51
|
-
description: "
|
|
56
|
+
description: "Machine CPU, memory, and uptime sampled when the prompt is compiled.",
|
|
57
|
+
dependencies: [],
|
|
52
58
|
options: {
|
|
53
59
|
format: { type: "enum", values: ["plain", "xml"], default: "plain" },
|
|
54
60
|
heading: { type: "string", default: "Machine status" },
|
|
@@ -56,14 +62,15 @@ export default function registerSystemStatus(api: ForgeRegistrationApi): void {
|
|
|
56
62
|
includeUptime: { type: "boolean", default: true },
|
|
57
63
|
},
|
|
58
64
|
render: (ctx) => {
|
|
59
|
-
|
|
65
|
+
// Do not capture this at registration time: sample when the slot is rendered.
|
|
66
|
+
const snapshot = Object.freeze(sampleSystemStatus());
|
|
60
67
|
const includeMemory = ctx.options.includeMemory !== false;
|
|
61
68
|
const includeUptime = ctx.options.includeUptime !== false;
|
|
62
69
|
const heading = typeof ctx.options.heading === "string" && ctx.options.heading.trim()
|
|
63
70
|
? ctx.options.heading.trim()
|
|
64
71
|
: "Machine status";
|
|
65
72
|
|
|
66
|
-
if (ctx.format
|
|
73
|
+
if (ctx.options.format === "xml") {
|
|
67
74
|
const lines = [
|
|
68
75
|
"<machine_status>",
|
|
69
76
|
` <cpu logical_cores=\"${snapshot.logicalCores}\" normalized_load_1m=\"${snapshot.normalizedLoad1.toFixed(3)}\" model=\"${ctx.helpers.escapeXml(snapshot.cpuModel)}\">${ctx.helpers.escapeXml(formatCpuLoad(snapshot))}</cpu>`,
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 2,
|
|
3
|
+
"type": "pi-forge.prompt-stack",
|
|
4
|
+
"id": "fake-assistant-direct-output",
|
|
5
|
+
"name": "Fake Assistant: Direct Output",
|
|
6
|
+
"description": "Model-specific experiment: append an ordinary assistant text message after chat history to suggest that tagged reasoning has already finished. Compatibility varies by model, provider, and endpoint; verify with an A/B run before use.",
|
|
7
|
+
"autoActivate": false,
|
|
8
|
+
"mode": "replace",
|
|
9
|
+
"defaults": {
|
|
10
|
+
"syntheticMessagesVisible": false,
|
|
11
|
+
"unresolvedMacroPolicy": "warn"
|
|
12
|
+
},
|
|
13
|
+
"context": {
|
|
14
|
+
"allowDuplicateChatHistory": false,
|
|
15
|
+
"mergeConsecutiveRoles": false
|
|
16
|
+
},
|
|
17
|
+
"tools": {
|
|
18
|
+
"deny": [
|
|
19
|
+
"*"
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
"items": [
|
|
23
|
+
{
|
|
24
|
+
"kind": "block",
|
|
25
|
+
"id": "direct-answer-role",
|
|
26
|
+
"name": "Direct Answer Role",
|
|
27
|
+
"enabled": true,
|
|
28
|
+
"role": "system",
|
|
29
|
+
"content": "You are a concise assistant. Answer the user's latest request directly and include only the requested result."
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"kind": "slot",
|
|
33
|
+
"id": "chat-history",
|
|
34
|
+
"name": "Chat History",
|
|
35
|
+
"enabled": true,
|
|
36
|
+
"slot": "chat-history"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"kind": "block",
|
|
40
|
+
"id": "fake-completed-thinking",
|
|
41
|
+
"name": "Fake Completed Thinking",
|
|
42
|
+
"enabled": true,
|
|
43
|
+
"role": "assistant",
|
|
44
|
+
"content": "<think>思考已完成,直接输出结果。</think>"
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
"parameters": {}
|
|
48
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 2,
|
|
3
|
+
"type": "pi-forge.prompt-stack",
|
|
4
|
+
"id": "regex-hack",
|
|
5
|
+
"name": "Regex Hack Pack",
|
|
6
|
+
"description": "Default layout plus outgoing-history regex rules: ANSI escapes are removed and illustrative sk-/ghp_ token shapes are redacted. This is a non-exhaustive demo, not a general secret scanner.",
|
|
7
|
+
"autoActivate": false,
|
|
8
|
+
"mode": "replace",
|
|
9
|
+
"defaults": {
|
|
10
|
+
"syntheticMessagesVisible": false,
|
|
11
|
+
"unresolvedMacroPolicy": "warn"
|
|
12
|
+
},
|
|
13
|
+
"context": {
|
|
14
|
+
"allowDuplicateChatHistory": false
|
|
15
|
+
},
|
|
16
|
+
"tools": {
|
|
17
|
+
"allow": [
|
|
18
|
+
"*"
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
"items": [
|
|
22
|
+
{
|
|
23
|
+
"kind": "block",
|
|
24
|
+
"id": "main-role",
|
|
25
|
+
"name": "Pi Default Role",
|
|
26
|
+
"enabled": true,
|
|
27
|
+
"role": "system",
|
|
28
|
+
"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."
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"kind": "slot",
|
|
32
|
+
"id": "tools",
|
|
33
|
+
"name": "Available Tools",
|
|
34
|
+
"enabled": true,
|
|
35
|
+
"role": "system",
|
|
36
|
+
"slot": "tools",
|
|
37
|
+
"options": {
|
|
38
|
+
"format": "plain",
|
|
39
|
+
"onlyWithSnippets": true
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"kind": "slot",
|
|
44
|
+
"id": "project-context",
|
|
45
|
+
"name": "Project Context",
|
|
46
|
+
"enabled": true,
|
|
47
|
+
"role": "system",
|
|
48
|
+
"slot": "project-context"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"kind": "slot",
|
|
52
|
+
"id": "date-cwd",
|
|
53
|
+
"name": "Date and Working Directory",
|
|
54
|
+
"enabled": true,
|
|
55
|
+
"role": "system",
|
|
56
|
+
"slot": "date-cwd"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"kind": "slot",
|
|
60
|
+
"id": "chat-history",
|
|
61
|
+
"name": "Chat History",
|
|
62
|
+
"enabled": true,
|
|
63
|
+
"slot": "chat-history",
|
|
64
|
+
"options": {
|
|
65
|
+
"stripAssistantThinking": false
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
],
|
|
69
|
+
"regex": {
|
|
70
|
+
"schemaVersion": 1,
|
|
71
|
+
"rules": [
|
|
72
|
+
{
|
|
73
|
+
"id": "strip-ansi-escapes",
|
|
74
|
+
"name": "ANSI terminal escape codes removed from outgoing history",
|
|
75
|
+
"enabled": true,
|
|
76
|
+
"stage": "history",
|
|
77
|
+
"targets": [
|
|
78
|
+
"messages"
|
|
79
|
+
],
|
|
80
|
+
"pattern": "\\x1B\\[[0-?]*[ -/]*[@-~]",
|
|
81
|
+
"flags": "g",
|
|
82
|
+
"replace": ""
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"id": "redact-api-keys-outgoing",
|
|
86
|
+
"name": "Illustrative sk-/ghp_ token shapes redacted on every provider request",
|
|
87
|
+
"enabled": true,
|
|
88
|
+
"stage": "history",
|
|
89
|
+
"effect": "outgoing",
|
|
90
|
+
"frequency": "request",
|
|
91
|
+
"targets": [
|
|
92
|
+
"messages"
|
|
93
|
+
],
|
|
94
|
+
"pattern": "\\b(sk-[A-Za-z0-9_-]{12,}|ghp_[A-Za-z0-9]{20,})\\b",
|
|
95
|
+
"flags": "g",
|
|
96
|
+
"replace": "[REDACTED]"
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"id": "redact-api-keys-finalize",
|
|
100
|
+
"name": "Illustrative sk-/ghp_ token shapes scrubbed from the stored transcript",
|
|
101
|
+
"enabled": true,
|
|
102
|
+
"stage": "compiled",
|
|
103
|
+
"effect": "finalize",
|
|
104
|
+
"targets": [
|
|
105
|
+
"messages"
|
|
106
|
+
],
|
|
107
|
+
"roles": [
|
|
108
|
+
"assistant",
|
|
109
|
+
"toolResult"
|
|
110
|
+
],
|
|
111
|
+
"pattern": "\\b(sk-[A-Za-z0-9_-]{12,}|ghp_[A-Za-z0-9]{20,})\\b",
|
|
112
|
+
"flags": "g",
|
|
113
|
+
"replace": "[REDACTED]"
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
},
|
|
117
|
+
"parameters": {}
|
|
118
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 2,
|
|
3
|
+
"type": "pi-forge.prompt-stack",
|
|
4
|
+
"id": "minimal",
|
|
5
|
+
"name": "Minimal Worker",
|
|
6
|
+
"description": "Minimal Pi approximation of the DeepSeek Harness Minimal shape: the exact one-line persona, chat history, and only Pi's stock bash plus edit. It does not replicate DSH's persistent shell, editor tool, PTY, sandbox, or deployment semantics.",
|
|
7
|
+
"autoActivate": false,
|
|
8
|
+
"mode": "replace",
|
|
9
|
+
"defaults": {
|
|
10
|
+
"syntheticMessagesVisible": false,
|
|
11
|
+
"unresolvedMacroPolicy": "warn"
|
|
12
|
+
},
|
|
13
|
+
"tools": {
|
|
14
|
+
"allow": [
|
|
15
|
+
"bash",
|
|
16
|
+
"edit"
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
"items": [
|
|
20
|
+
{
|
|
21
|
+
"kind": "block",
|
|
22
|
+
"id": "worker-role",
|
|
23
|
+
"name": "Worker Role",
|
|
24
|
+
"enabled": true,
|
|
25
|
+
"role": "system",
|
|
26
|
+
"content": "You are a helpful software engineer assistant."
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"kind": "slot",
|
|
30
|
+
"id": "chat-history",
|
|
31
|
+
"name": "Chat History",
|
|
32
|
+
"enabled": true,
|
|
33
|
+
"slot": "chat-history",
|
|
34
|
+
"options": {
|
|
35
|
+
"includeSummaries": false
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
"parameters": {}
|
|
40
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zihanw/pi-forge",
|
|
3
|
-
"version": "0.5.
|
|
4
|
-
"description": "Pi extension for
|
|
3
|
+
"version": "0.5.3",
|
|
4
|
+
"description": "Pi extension for editable context presets, one-shot agent profiles, tool policy, and request debugging.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/MacroSony/pi-forge.git"
|