@zihanw/pi-forge 0.3.2 → 0.4.0-beta.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.
Files changed (244) hide show
  1. package/CHANGELOG.md +160 -0
  2. package/PUBLIC_API.md +28 -0
  3. package/README.md +137 -11
  4. package/README.zh-CN.md +137 -11
  5. package/SUBAGENT_ADAPTER_CONTRACT.md +199 -0
  6. package/dist/agent-profile.d.ts +71 -0
  7. package/dist/agent-profile.d.ts.map +1 -0
  8. package/dist/agent-profile.js +303 -0
  9. package/dist/agent-profile.js.map +1 -0
  10. package/dist/forge-config.d.ts +8 -0
  11. package/dist/forge-config.d.ts.map +1 -0
  12. package/dist/forge-config.js +40 -0
  13. package/dist/forge-config.js.map +1 -0
  14. package/dist/forge-extensions.d.ts.map +1 -1
  15. package/dist/forge-extensions.js +19 -3
  16. package/dist/forge-extensions.js.map +1 -1
  17. package/dist/index.d.ts +7 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +75 -361
  20. package/dist/index.js.map +1 -1
  21. package/dist/lifecycle.d.ts +11 -3
  22. package/dist/lifecycle.d.ts.map +1 -1
  23. package/dist/lifecycle.js +90 -4
  24. package/dist/lifecycle.js.map +1 -1
  25. package/dist/loader.d.ts.map +1 -1
  26. package/dist/loader.js +116 -5
  27. package/dist/loader.js.map +1 -1
  28. package/dist/payload-capture.d.ts.map +1 -1
  29. package/dist/payload-capture.js +27 -0
  30. package/dist/payload-capture.js.map +1 -1
  31. package/dist/payload-command.d.ts +3 -3
  32. package/dist/payload-command.d.ts.map +1 -1
  33. package/dist/payload-command.js.map +1 -1
  34. package/dist/preview.d.ts +2 -2
  35. package/dist/preview.d.ts.map +1 -1
  36. package/dist/preview.js +2 -3
  37. package/dist/preview.js.map +1 -1
  38. package/dist/profile-command.d.ts +12 -0
  39. package/dist/profile-command.d.ts.map +1 -0
  40. package/dist/profile-command.js +291 -0
  41. package/dist/profile-command.js.map +1 -0
  42. package/dist/profile-service.d.ts +103 -0
  43. package/dist/profile-service.d.ts.map +1 -0
  44. package/dist/profile-service.js +215 -0
  45. package/dist/profile-service.js.map +1 -0
  46. package/dist/runtime/profile-runtime.d.ts +13 -0
  47. package/dist/runtime/profile-runtime.d.ts.map +1 -0
  48. package/dist/runtime/profile-runtime.js +47 -0
  49. package/dist/runtime/profile-runtime.js.map +1 -0
  50. package/dist/runtime/prompt-stack-runtime.d.ts +22 -0
  51. package/dist/runtime/prompt-stack-runtime.d.ts.map +1 -0
  52. package/dist/runtime/prompt-stack-runtime.js +104 -0
  53. package/dist/runtime/prompt-stack-runtime.js.map +1 -0
  54. package/dist/runtime/subagent-runtime.d.ts +30 -0
  55. package/dist/runtime/subagent-runtime.d.ts.map +1 -0
  56. package/dist/runtime/subagent-runtime.js +114 -0
  57. package/dist/runtime/subagent-runtime.js.map +1 -0
  58. package/dist/runtime/tool-policy-runtime.d.ts +15 -0
  59. package/dist/runtime/tool-policy-runtime.d.ts.map +1 -0
  60. package/dist/runtime/tool-policy-runtime.js +170 -0
  61. package/dist/runtime/tool-policy-runtime.js.map +1 -0
  62. package/dist/runtime/web-editor-runtime.d.ts +9 -0
  63. package/dist/runtime/web-editor-runtime.d.ts.map +1 -0
  64. package/dist/runtime/web-editor-runtime.js +131 -0
  65. package/dist/runtime/web-editor-runtime.js.map +1 -0
  66. package/dist/runtime-state.d.ts +4 -0
  67. package/dist/runtime-state.d.ts.map +1 -1
  68. package/dist/runtime-state.js +2 -0
  69. package/dist/runtime-state.js.map +1 -1
  70. package/dist/storage.d.ts +3 -0
  71. package/dist/storage.d.ts.map +1 -1
  72. package/dist/storage.js +9 -0
  73. package/dist/storage.js.map +1 -1
  74. package/dist/subagent/backend-registry.d.ts +75 -0
  75. package/dist/subagent/backend-registry.d.ts.map +1 -0
  76. package/dist/subagent/backend-registry.js +463 -0
  77. package/dist/subagent/backend-registry.js.map +1 -0
  78. package/dist/subagent/canonical.d.ts +10 -0
  79. package/dist/subagent/canonical.d.ts.map +1 -0
  80. package/dist/subagent/canonical.js +52 -0
  81. package/dist/subagent/canonical.js.map +1 -0
  82. package/dist/subagent/context.d.ts +8 -0
  83. package/dist/subagent/context.d.ts.map +1 -0
  84. package/dist/subagent/context.js +125 -0
  85. package/dist/subagent/context.js.map +1 -0
  86. package/dist/subagent/contract.d.ts +11 -0
  87. package/dist/subagent/contract.d.ts.map +1 -0
  88. package/dist/subagent/contract.js +11 -0
  89. package/dist/subagent/contract.js.map +1 -0
  90. package/dist/subagent/diagnostics.d.ts +3 -0
  91. package/dist/subagent/diagnostics.d.ts.map +1 -0
  92. package/dist/subagent/diagnostics.js +5 -0
  93. package/dist/subagent/diagnostics.js.map +1 -0
  94. package/dist/subagent/index.d.ts +13 -0
  95. package/dist/subagent/index.d.ts.map +1 -0
  96. package/dist/subagent/index.js +13 -0
  97. package/dist/subagent/index.js.map +1 -0
  98. package/dist/subagent/pi-model-runtime.d.ts +8 -0
  99. package/dist/subagent/pi-model-runtime.d.ts.map +1 -0
  100. package/dist/subagent/pi-model-runtime.js +22 -0
  101. package/dist/subagent/pi-model-runtime.js.map +1 -0
  102. package/dist/subagent/pi-sdk-backend.d.ts +23 -0
  103. package/dist/subagent/pi-sdk-backend.d.ts.map +1 -0
  104. package/dist/subagent/pi-sdk-backend.js +383 -0
  105. package/dist/subagent/pi-sdk-backend.js.map +1 -0
  106. package/dist/subagent/pi-subprocess-backend.d.ts +72 -0
  107. package/dist/subagent/pi-subprocess-backend.d.ts.map +1 -0
  108. package/dist/subagent/pi-subprocess-backend.js +756 -0
  109. package/dist/subagent/pi-subprocess-backend.js.map +1 -0
  110. package/dist/subagent/plan.d.ts +14 -0
  111. package/dist/subagent/plan.d.ts.map +1 -0
  112. package/dist/subagent/plan.js +160 -0
  113. package/dist/subagent/plan.js.map +1 -0
  114. package/dist/subagent/preflight.d.ts +4 -0
  115. package/dist/subagent/preflight.d.ts.map +1 -0
  116. package/dist/subagent/preflight.js +108 -0
  117. package/dist/subagent/preflight.js.map +1 -0
  118. package/dist/subagent/request.d.ts +4 -0
  119. package/dist/subagent/request.d.ts.map +1 -0
  120. package/dist/subagent/request.js +122 -0
  121. package/dist/subagent/request.js.map +1 -0
  122. package/dist/subagent/response.d.ts +8 -0
  123. package/dist/subagent/response.d.ts.map +1 -0
  124. package/dist/subagent/response.js +155 -0
  125. package/dist/subagent/response.js.map +1 -0
  126. package/dist/subagent/subprocess-bridge.d.ts +21 -0
  127. package/dist/subagent/subprocess-bridge.d.ts.map +1 -0
  128. package/dist/subagent/subprocess-bridge.js +87 -0
  129. package/dist/subagent/subprocess-bridge.js.map +1 -0
  130. package/dist/subagent/subprocess-report.d.ts +4 -0
  131. package/dist/subagent/subprocess-report.d.ts.map +1 -0
  132. package/dist/subagent/subprocess-report.js +55 -0
  133. package/dist/subagent/subprocess-report.js.map +1 -0
  134. package/dist/subagent/tools.d.ts +4 -0
  135. package/dist/subagent/tools.d.ts.map +1 -0
  136. package/dist/subagent/tools.js +42 -0
  137. package/dist/subagent/tools.js.map +1 -0
  138. package/dist/subagent/types.d.ts +384 -0
  139. package/dist/subagent/types.d.ts.map +1 -0
  140. package/dist/subagent/types.js +3 -0
  141. package/dist/subagent/types.js.map +1 -0
  142. package/dist/subagent/validation.d.ts +35 -0
  143. package/dist/subagent/validation.d.ts.map +1 -0
  144. package/dist/subagent/validation.js +500 -0
  145. package/dist/subagent/validation.js.map +1 -0
  146. package/dist/subagent-command.d.ts +4 -0
  147. package/dist/subagent-command.d.ts.map +1 -0
  148. package/dist/subagent-command.js +153 -0
  149. package/dist/subagent-command.js.map +1 -0
  150. package/dist/subagent-contract.d.ts +8 -0
  151. package/dist/subagent-contract.d.ts.map +1 -0
  152. package/dist/subagent-contract.js +8 -0
  153. package/dist/subagent-contract.js.map +1 -0
  154. package/dist/subagent-host.d.ts +44 -0
  155. package/dist/subagent-host.d.ts.map +1 -0
  156. package/dist/subagent-host.js +291 -0
  157. package/dist/subagent-host.js.map +1 -0
  158. package/dist/subagent-profile-tool.d.ts +26 -0
  159. package/dist/subagent-profile-tool.d.ts.map +1 -0
  160. package/dist/subagent-profile-tool.js +93 -0
  161. package/dist/subagent-profile-tool.js.map +1 -0
  162. package/dist/subagent-tool.d.ts +50 -0
  163. package/dist/subagent-tool.d.ts.map +1 -0
  164. package/dist/subagent-tool.js +385 -0
  165. package/dist/subagent-tool.js.map +1 -0
  166. package/dist/web-editor/client/api.d.ts +9 -0
  167. package/dist/web-editor/client/api.d.ts.map +1 -0
  168. package/dist/web-editor/client/api.js +26 -0
  169. package/dist/web-editor/client/api.js.map +1 -0
  170. package/dist/web-editor/client/dom.d.ts +13 -0
  171. package/dist/web-editor/client/dom.d.ts.map +1 -0
  172. package/dist/web-editor/client/dom.js +30 -0
  173. package/dist/web-editor/client/dom.js.map +1 -0
  174. package/dist/web-editor/client/inspector.d.ts +22 -0
  175. package/dist/web-editor/client/inspector.d.ts.map +1 -0
  176. package/dist/web-editor/client/inspector.js +226 -0
  177. package/dist/web-editor/client/inspector.js.map +1 -0
  178. package/dist/web-editor/client/main.d.ts +2 -0
  179. package/dist/web-editor/client/main.d.ts.map +1 -0
  180. package/dist/web-editor/client/main.js +1468 -0
  181. package/dist/web-editor/client/main.js.map +1 -0
  182. package/dist/web-editor/client/policy-editor.d.ts +16 -0
  183. package/dist/web-editor/client/policy-editor.d.ts.map +1 -0
  184. package/dist/web-editor/client/policy-editor.js +330 -0
  185. package/dist/web-editor/client/policy-editor.js.map +1 -0
  186. package/dist/web-editor/client/regex-editor.d.ts +19 -0
  187. package/dist/web-editor/client/regex-editor.d.ts.map +1 -0
  188. package/dist/web-editor/client/regex-editor.js +281 -0
  189. package/dist/web-editor/client/regex-editor.js.map +1 -0
  190. package/dist/web-editor/client/types.d.ts +60 -0
  191. package/dist/web-editor/client/types.d.ts.map +1 -0
  192. package/dist/web-editor/client/types.js +2 -0
  193. package/dist/web-editor/client/types.js.map +1 -0
  194. package/dist/web-editor/client-script.d.ts +2 -0
  195. package/dist/web-editor/client-script.d.ts.map +1 -0
  196. package/dist/web-editor/client-script.generated.d.ts +2 -0
  197. package/dist/web-editor/client-script.generated.d.ts.map +1 -0
  198. package/dist/web-editor/client-script.generated.js +3 -0
  199. package/dist/web-editor/client-script.generated.js.map +1 -0
  200. package/dist/web-editor/client-script.js +2 -0
  201. package/dist/web-editor/client-script.js.map +1 -0
  202. package/dist/web-editor/page.d.ts.map +1 -1
  203. package/dist/web-editor/page.js +6 -3249
  204. package/dist/web-editor/page.js.map +1 -1
  205. package/dist/web-editor/styles.d.ts +2 -0
  206. package/dist/web-editor/styles.d.ts.map +1 -0
  207. package/dist/web-editor/styles.js +996 -0
  208. package/dist/web-editor/styles.js.map +1 -0
  209. package/dist/web-host.d.ts +3 -3
  210. package/dist/web-host.d.ts.map +1 -1
  211. package/dist/web-host.js +6 -0
  212. package/dist/web-host.js.map +1 -1
  213. package/package.json +42 -14
  214. package/src/compiler.ts +0 -578
  215. package/src/extension-registry.ts +0 -33
  216. package/src/forge-extensions.ts +0 -223
  217. package/src/index.ts +0 -445
  218. package/src/lifecycle.ts +0 -171
  219. package/src/loader.ts +0 -394
  220. package/src/macro-engine.ts +0 -358
  221. package/src/payload-capture.ts +0 -85
  222. package/src/payload-command.ts +0 -138
  223. package/src/policy.ts +0 -42
  224. package/src/preset-command.ts +0 -280
  225. package/src/preview.ts +0 -226
  226. package/src/regex.ts +0 -500
  227. package/src/render-helpers.ts +0 -169
  228. package/src/runtime-state.ts +0 -40
  229. package/src/sillytavern-importer/items.ts +0 -98
  230. package/src/sillytavern-importer/macros.ts +0 -159
  231. package/src/sillytavern-importer/prompt-order.ts +0 -54
  232. package/src/sillytavern-importer/regex.ts +0 -270
  233. package/src/sillytavern-importer/report.ts +0 -202
  234. package/src/sillytavern-importer/types.ts +0 -120
  235. package/src/sillytavern-importer.ts +0 -152
  236. package/src/slot-renderers.ts +0 -414
  237. package/src/stack-migration.ts +0 -159
  238. package/src/storage.ts +0 -45
  239. package/src/types.ts +0 -209
  240. package/src/web-editor/index.ts +0 -2
  241. package/src/web-editor/page.ts +0 -3330
  242. package/src/web-editor/server.ts +0 -294
  243. package/src/web-editor/types.ts +0 -98
  244. package/src/web-host.ts +0 -232
package/README.zh-CN.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  ![pi-forge header](https://raw.githubusercontent.com/MacroSony/pi-forge/main/assets/pi-forge-header-concept-1.png)
6
6
 
7
- **pi-forge** 让你自定义 Pi 的思考方式和行为。它提供 prompt stack(提示栈):这些 JSON 文件可以替换、追加到或插入到 Pi 的默认系统提示词之前,并控制 AI 的性格、可见工具、对话历史布局、模板变量和 prompt 转换。
7
+ **pi-forge** 让你自定义 Pi 的思考方式和行为。它提供用于 prompt/工具策略的 prompt stack(提示栈),也提供可一次性应用模型、思考等级和提示栈的 agent profile(agent 配置预设)。
8
8
 
9
9
  可以把它理解为 AI agent 的角色卡。
10
10
 
@@ -12,6 +12,7 @@
12
12
 
13
13
  - **赋予 Pi 个性** — 把它变成创意写手、角色扮演搭档、严格的代码审查员,或任何你想要的风格。
14
14
  - **一键切换模式** — 在"写代码"、"写小说"、"做翻译"之间用一条命令切换。
15
+ - **保存完整 agent 预设** — 捕获当前模型、思考等级和提示栈,以后一条命令一起应用。
15
16
  - **控制 AI 看到什么** — 选择每个 prompt 中出现哪些工具、技能和项目上下文。
16
17
  - **按栈限制工具和技能** — 为专注模式启用工具策略,并过滤技能可见性。
17
18
  - **使用模板变量** — 定义 `{{char}}` / `{{user}}` 这样的静态值,并在 prompt 文本里使用 ST 风格的轮次/会话变量宏。
@@ -24,9 +25,13 @@
24
25
  ### 安装
25
26
 
26
27
  ```bash
27
- pi install npm:@zihanw/pi-forge
28
+ pi install npm:@zihanw/pi-forge@0.4.0-beta.1
28
29
  ```
29
30
 
31
+ 此 beta 会发布到 npm 的 `next` channel,不会替换稳定版 `latest`。它要求 Node.js 22.19 或更高版本,并且必须使用 Pi 0.80.10 所采用的精确 `@earendil-works/pi-*` 0.80.10 package 版本。
32
+
33
+ > **Pi 版本兼容性:** Pi 在 0.80.x 系列内部修改了 session 认证/runtime 的接线方式。此 beta 只以 0.80.10 为目标;不声明兼容 0.80.6–0.80.9,也不声明兼容尚未验证的后续 0.80.x 版本。安装或重新 build pi-forge 后请重启 Pi,确保 extension 与 host SDK 使用同一套接口。如果主 agent 可以正常使用 provider,但 subagent preparation 报告 `No API key found`,请先检查是否仍在运行旧的 pi-forge build,不要直接执行 `/login`:使用 0.80.10 之前 session API 的 build 会在 preparation 时丢失主 session 的认证信息,重新登录无法修复这个版本不匹配。
34
+
30
35
  ### 第一个 prompt stack
31
36
 
32
37
  从 [examples/default-prompt-stack.json](examples/default-prompt-stack.json) 创建 `.pi/forge/prompt-stacks/default.json`。
@@ -50,11 +55,11 @@ $EDITOR .pi/forge/prompt-stacks/default.json
50
55
  /preset ui
51
56
  ```
52
57
 
53
- 拖拽、新建、编辑、校验、查看完整预览和捕获的 payload、用 tabs 管理变量/context/regex 规则、切换深色模式、通过原始 stack JSON 修复高级字段、导入、导出、fork、删除栈 —— 全在浏览器里完成。新栈会从默认 Pi prompt mirror 布局开始。Stack metadata 可以折叠,方便把当前编辑区留在屏幕内。Policy tab 会显示已注册工具和已加载 skills,并提供已选 pattern chips 和过滤输入,方便用精确名称编写 allow/deny 规则,同时保留通配符写法。
58
+ 拖拽、新建、编辑、校验、查看完整预览和捕获的 payload、用 tabs 管理变量/context/regex 规则、切换深色模式、通过原始 stack JSON 修复高级字段、导入、导出、fork、删除栈 —— 全在浏览器里完成。新栈会从默认 Pi prompt mirror 布局开始。已有 stack ID 不可在保存时修改;需要新 ID 时请使用 Fork,避免破坏 profile 引用或当前选择。Stack metadata 可以折叠,方便把当前编辑区留在屏幕内。Policy tab 会显示已注册工具和已加载 skills,并提供已选 pattern chips 和过滤输入,方便用精确名称编写 allow/deny 规则,同时保留通配符写法。
54
59
 
55
60
  导入支持原生 pi-forge stack JSON,也支持 SillyTavern 预设 JSON。SillyTavern 预设会自动转换成 prompt stack;如果一个预设里有多个 `character_id` 配置,编辑器会询问要使用哪一个。
56
61
 
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`。
62
+ 编辑器默认运行在一个可用的 `127.0.0.1` 端口,并带有会话 token,所以多个 Pi 实例可以同时打开各自的编辑器。如果 Pi 在 session navigation 或新会话后重新初始化扩展,同一项目中的 `/preset ui` 会复用已有编辑器 URL,不会遗留旧 server 后再开一个新端口;resources 和 preview 在生命周期刷新后仍可使用。写入需要项目被信任,且只会写入 prompt-stack 存储目录。新建的栈会写入 `.pi/forge/prompt-stacks`;旧的 `.pi/prompt-stacks` 栈仍然可读取和编辑。保存、导入、fork、删除成功后会重新加载到当前 Pi 会话。需要时可以用 `/preset ui restart` 或 `/preset ui stop`。
58
63
 
59
64
  要把旧栈复制到新位置,执行 `/preset migrate-stacks`。加 `--dry-run` 可先预览,加 `--overwrite` 可覆盖目标文件,加 `--delete-legacy` 会在复制成功后删除旧文件。
60
65
 
@@ -68,6 +73,70 @@ $EDITOR .pi/forge/prompt-stacks/default.json
68
73
  }
69
74
  ```
70
75
 
76
+ ### Agent profile
77
+
78
+ Agent profile 是保存在 `.pi/forge/agent-profiles` 下的项目级 JSON 文件。先正常配置 Pi,然后捕获当前模型、思考等级和 prompt stack,就能快速创建:
79
+
80
+ ```text
81
+ /profile save reviewer
82
+ /profile use reviewer
83
+ ```
84
+
85
+ Profile 只应用一次,不会持续接管 Pi 的模型或思考等级;之后的手动修改会一直保留,直到再次执行 `/profile use reviewer`。被选中的 prompt stack 仍会在激活期间持续执行严格工具策略。
86
+
87
+ 也可以直接编写 profile:
88
+
89
+ ```json
90
+ {
91
+ "schemaVersion": 1,
92
+ "type": "pi-forge.agent-profile",
93
+ "id": "reviewer",
94
+ "name": "Reviewer",
95
+ "description": "只审查代码,不做修改。",
96
+ "autoActivate": true,
97
+ "model": {
98
+ "provider": "provider-id",
99
+ "id": "model-id"
100
+ },
101
+ "thinkingLevel": "high",
102
+ "promptStack": "reviewer"
103
+ }
104
+ ```
105
+
106
+ `autoActivate: true` 会在 Pi 启动全新 session 时一次性应用整个 profile。最多只能有一个 profile 请求自动应用。自动应用的 profile 优先于独立 prompt stack 的自动加载,即使它的 `promptStack` 为 `null` 也不会回退;如果没有 profile 请求自动应用,则继续使用现有的 `default.json`/`autoActivate` stack 规则。已恢复的 session branch 选择优先于这两种自动加载机制。
107
+
108
+ `promptStack` 可以为 `null`。Profile v1 不保存工具名或 skill 列表;引用的 prompt stack 是工具策略和模型可见 skill 过滤的唯一来源。校验会拒绝不支持的字段,避免悄悄保留无效的生成参数或 runner 配置。
109
+
110
+ `/profile preview <id>` 会解析模型、认证、思考等级支持、prompt stack 和最终工具集,但不会改变运行时。`/profile status` 显示上次应用的 profile 和当前 drift;profile provenance 会跟随 session branch 恢复用于状态显示,但 reload、resume、tree navigation 或 compaction 绝不会自动重新应用 profile。全新 session 的自动应用仍然是一次性的,因此之后的手动修改会被保留。
111
+
112
+ ### 实验性前台 subagent
113
+
114
+ 0.4 beta 可以把已有 profile 作为独立、干净、一次性的 Pi 子进程运行。无数据外发的 `forge_subagent_profiles` 工具让主 agent 查看当前已加载 profile 的 ID、名称、描述、声明的模型/思考等级/stack、当前解析状态和审批模式。用户没有指定 profile 时,主 agent 应先调用该工具,再调用 `forge_subagent`。限制严格的主 agent prompt stack 必须同时允许这两个工具名。用户也可以继续使用同一执行路径的命令:
115
+
116
+ ```text
117
+ /forge-agent backends
118
+ /forge-agent plan reviewer 检查这个 API 设计是否正确。
119
+ /forge-agent run reviewer 检查这个 API 设计是否正确。
120
+ ```
121
+
122
+ `plan` 会解析 profile 和 stack、编译实际将发送给 provider 的 prompt、校验不可变执行计划,然后丢弃它,不会联系 provider。`/forge-agent run` 和默认配置下的 `forge_subagent` 会先准备完全相同的精确计划,再显示审批界面。默认界面显示 agent 任务、profile/stack、provider、模型、思考等级、最终工具、工作目录、安全边界、payload 大小和执行 fingerprint。选择 **View full prompt** 可以在批准前查看完整 system prompt 和按顺序排列的 provider-bound messages;在查看器中的编辑不会生效。
123
+
124
+ 如果要明确允许父 agent 无需逐次审批即可调用 `forge_subagent`,可以在受信任项目的 `.pi/forge/config.json` 中设置:
125
+
126
+ ```json
127
+ {
128
+ "subagents": {
129
+ "allowAgentInvocationWithoutApproval": true
130
+ }
131
+ }
132
+ ```
133
+
134
+ 此选项只影响模型可调用的 `forge_subagent` 工具;`/forge-agent run` 仍然需要交互审批。精确 preflight 和不可变计划校验仍会执行,tool result 也会记录 `trusted-project-config` 授权来源,但 provider transport 会在不向人类显示 prompt 的情况下开始。Profile discovery 会报告当前审批模式。未受信任项目会忽略该设置,格式错误的值会 fail closed。请把项目 config 当作授权文件:除非允许所有能调用 `forge_subagent` 的父 agent 无需再次询问就把编译后的 prompt 和可读文件内容发送给指定 provider,否则不要启用或提交此选项。
135
+
136
+ 子 agent 从干净对话开始,不会自动继承主 agent 历史。它在前台运行,并使用 profile 指定的精确模型、思考等级和 prompt stack。候选工具只有 `read`、`grep`、`find` 和 `ls`,还会继续受到 stack 工具策略限制;不会加载 write/edit/shell 工具、skills、prompt templates、context files 或第三方 extensions。最终工具结果包含有界的模型可见报告和可展开的人类可见执行详情。保留的 transcript 会限制每个字符串的大小、删去类似 base64 的文本,并只保留 512 KiB 的滚动尾部,以便保留最终报告而不让 TUI 持有无界工具历史。内联图片数据会留在 child 内供所选视觉模型使用,但专用 report channel 会在任何内容进入主 session 前,把二进制 payload 替换成 MIME type 和编码体积元数据。
137
+
138
+ 重要:首个 backend 是 **shared-user**,不是操作系统沙箱。只读是模型工具策略;子进程仍然拥有启动它的用户权限,因此可以读取该用户可读的绝对路径,把内容发送给所选 provider,并把文本保留在父级 tool-result details 中。Host timeout 和取消仅为 best effort。`/tree` 会从当前对话分支移除调用和结果,但被放弃的 entry 仍可能留在 Pi 的磁盘 session JSONL 中;要删除敏感的保留文本,需要删除相应 session 数据。`/tree` 也不能撤销 provider 请求、计费或外部副作用。默认工具集刻意不提供文件系统写入路径;bubblewrap 类沙箱和 staged write mode 留待后续实现。
139
+
71
140
  ## 使用场景
72
141
 
73
142
  ### 🎭 角色扮演 & 创意写作
@@ -154,7 +223,7 @@ pi-forge 会把预设转换为 prompt stack,并生成迁移报告,标明哪
154
223
  /payload next save=.pi/forge/payloads/last.json
155
224
  ```
156
225
 
157
- 或者打开 `/preset ui`,点击 **Arm payload**,发送下一条 Pi prompt,然后在浏览器里查看脱敏后的 provider payload。
226
+ 或者打开 `/preset ui`,点击 **Arm payload**,发送下一条 Pi prompt,然后在浏览器里查看脱敏后的 provider payload。凭据形式的 token 字段仍会隐藏,而 `max_tokens`、`input_tokens`、`output_tokens` 等正常限制和计数字段会保留显示。
158
227
 
159
228
  或者不发送只预览编译结果:
160
229
 
@@ -218,6 +287,29 @@ pi-forge 会把预设转换为 prompt stack,并生成迁移报告,标明哪
218
287
  | `/preset migrate-stacks [--dry-run] [--overwrite] [--delete-legacy]` | 将旧 `.pi/prompt-stacks` 文件复制到 `.pi/forge/prompt-stacks` |
219
288
  | `/preset ui [stop\|restart]` | 打开、停止或重启 Web 编辑器 |
220
289
 
290
+ ### 管理 agent profile
291
+
292
+ | 命令 | 作用 |
293
+ |------|------|
294
+ | `/profile list` | 显示项目 profile 和解析诊断 |
295
+ | `/profile use <id>` | 预检并一次性应用 profile |
296
+ | `/profile save <id> [--overwrite]` | 捕获当前模型、思考等级和 prompt stack |
297
+ | `/profile status` | 显示当前运行时、上次应用来源和 drift |
298
+ | `/profile preview <id>` | 不应用,只预览解析结果和最终工具 |
299
+ | `/profile validate [id]` | 校验一个 profile;省略 id 时校验全部 |
300
+ | `/profile reload` | 从磁盘重新加载 profile,但不应用 |
301
+ | `/profile forget` | 忘记上次应用来源,不改变运行时 |
302
+
303
+ ### 实验性前台 subagent
304
+
305
+ | 命令 | 作用 |
306
+ |------|------|
307
+ | `/forge-agent backends` | 显示实验性 backend 及其能力 |
308
+ | `/forge-agent plan <profile> <task>` | 不进行 provider transport,准备、校验、显示并丢弃精确执行计划 |
309
+ | `/forge-agent run <profile> <task>` | 审查精确计划并在批准后运行一个前台只读文本任务 |
310
+
311
+ 模型可调用的工具包括用于本地元数据发现的 `forge_subagent_profiles`,以及用于执行的 `forge_subagent`。发现工具不需要审批,也不会请求 provider 或准备 subagent prompt。当前主 agent 工具策略必须允许执行工具;之后还必须存在交互式审批 UI,或者启用上文明确说明的受信任项目免审批选项,subagent 才可运行。
312
+
221
313
  ### 导入 & 调试
222
314
 
223
315
  | 命令 | 作用 |
@@ -405,7 +497,7 @@ API 包含 `cwd`、`forgeDir`、`extensionPath`、`helpers`、`registerMacro`、
405
497
 
406
498
  ### 工具和技能策略
407
499
 
408
- Prompt stack 可以用栈级 `allow` 或 `deny` 列表限制工具和技能。模式默认精确匹配,也支持 `*` 通配符。
500
+ Prompt stack 可以用栈级 `allow` 或 `deny` 列表限制 active tools,并过滤模型可见的技能。模式默认精确匹配,也支持 `*` 通配符。
409
501
 
410
502
  ```json
411
503
  {
@@ -418,11 +510,11 @@ Prompt stack 可以用栈级 `allow` 或 `deny` 列表限制工具和技能。
418
510
  }
419
511
  ```
420
512
 
421
- 使用 `allow` 时,只有匹配的工具或技能保持启用。使用 `deny` 时,除匹配项以外的工具或技能保持启用。同一个资源策略不能同时包含非空 `allow` 和 `deny` 列表;混用会产生 validation error。
513
+ 对于工具,`allow` 只保留匹配的 active tools,`deny` 移除匹配的 active tools。对于技能,同样的 pattern 控制哪些技能保留在 pi-forge 渲染的 `skills` slot 中。同一个资源策略不能同时包含非空 `allow` 和 `deny` 列表;混用会产生 validation error。
422
514
 
423
- 工具策略会在栈激活期间通过 Pi 的 active tool list 强制执行。pi-forge 会记住之前的 active tools,并在禁用 prompt stack 或切换到没有工具策略的 stack 时恢复。
515
+ 工具策略会在栈激活期间通过 Pi 的 active tool list 强制执行。启动和 reload 时,pi-forge 会等其它扩展完成 `session_start` 工具配置,再记录 baseline 并应用 stack 策略;之后还会在用户输入和 turn 开始前重新应用策略。即使其它扩展稍后调用 `setActiveTools()`,tool-call guard 也会阻止模型执行策略之外的工具。外部扩展新增的工具会保留在可恢复 baseline 中,并在禁用 prompt stack 或切换到没有工具策略的 stack 时恢复。
424
516
 
425
- 技能策略会过滤 pi-forge `skills` slot 渲染出的技能。如果 stack 使用 `mode: "append"` 或 `"prepend"`,Pi base prompt 里可能已经包含未过滤的技能;需要控制技能可见性时请使用 `mode: "replace"`。
517
+ 技能策略会过滤 pi-forge `skills` slot 渲染出的技能。它不会禁用显式技能调用,也不是 capability 或安全边界。如果 stack 使用 `mode: "append"` 或 `"prepend"`,Pi base prompt 里可能已经包含未过滤的技能;需要控制模型可见的技能列表时请使用 `mode: "replace"`。
426
518
 
427
519
  ### Regex 转换
428
520
 
@@ -492,20 +584,46 @@ SillyTavern 导入会把确定性的 prompt-only `{{match}}` / `$0` full-match r
492
584
  ## 开发环境搭建
493
585
 
494
586
  ```bash
495
- git clone <repo>
587
+ git clone https://github.com/MacroSony/pi-forge.git
496
588
  cd pi-forge
497
589
  npm install
498
590
  npm run build
499
- # .pi/settings.json 已指向包根目录
591
+ # .pi/settings.json 会加载 package 构建后的 dist/index.js
500
592
  pi # 启动 Pi,信任项目,必要时 /reload
501
593
  ```
502
594
 
595
+ npm package 会有意省略实际的 `src/` 文件,并在运行时加载编译后的 `dist/`。需要查看或修改 pi-forge 本身时,请 clone 或 fork 仓库,不要直接修改 `node_modules` 或生成的 `dist/`。仓库 clone 可以用 Git 保留改动,并包含开发依赖、测试以及 source-to-dist 一致性检查。
596
+
597
+ 进行接近 release 的本地测试时,在 `.pi/settings.json` 中注册 clone 后的 package 目录;package manifest 会加载已跟踪的 `dist/index.js`:
598
+
599
+ ```json
600
+ {
601
+ "packages": ["../pi-forge"]
602
+ }
603
+ ```
604
+
605
+ 进行实时源码开发时,请移除上面的 pi-forge package entry,再通过 `.pi/settings.json` 直接加载 TypeScript extension:
606
+
607
+ ```json
608
+ {
609
+ "extensions": ["../pi-forge/src/index.ts"]
610
+ }
611
+ ```
612
+
613
+ 也可以用 `pi -e ../pi-forge/src/index.ts` 做一次性的源码级 smoke test。不要同时加载 package 和 source entry,否则 pi-forge 会初始化两次。修改 browser client 源码后还需要执行 `npm run build:client`,因为本地编辑器提供的是生成后的 browser bundle。
614
+
503
615
  运行测试:
504
616
 
505
617
  ```bash
506
618
  npm test
507
619
  ```
508
620
 
621
+ 运行真实浏览器中的编辑器 smoke test(如果 Chrome 不在标准路径,请设置 `CHROME_PATH`):
622
+
623
+ ```bash
624
+ npm run test:browser
625
+ ```
626
+
509
627
  类型检查:
510
628
 
511
629
  ```bash
@@ -518,6 +636,14 @@ npm run typecheck
518
636
  npm run build
519
637
  ```
520
638
 
639
+ 运行完整仓库验证,包括在临时目录中执行干净构建,并逐字节检查已跟踪的 `dist/` 是否与 `src/` 一致:
640
+
641
+ ```bash
642
+ npm run verify
643
+ ```
644
+
645
+ CI 会运行同一套验证。源代码变更影响生成输出时,请运行 `npm run build`,并将对应的 `dist/` 变更与源代码一起提交。
646
+
521
647
  ## License
522
648
 
523
649
  MIT
@@ -0,0 +1,199 @@
1
+ # Subagent Adapter Contract
2
+
3
+ Status: exported pure contract, host-preparation utilities, optional backend registry, retained `pi-sdk-isolated` compatibility adapter, and a default-approval `pi-subprocess-readonly` foreground path for the 0.4 beta. This is a narrow one-shot delegation boundary, not a background orchestration runner or an OS sandbox.
4
+
5
+ ## Public Surface
6
+
7
+ New integrations should import this experimental 0.4 surface from `@zihanw/pi-forge/subagent`. The package root retains the same exports through the 0.4 prereleases for compatibility. Stability classifications and compatibility-path policy are recorded in [`PUBLIC_API.md`](PUBLIC_API.md).
8
+
9
+ The package root exports:
10
+
11
+ - `AgentRequest`, `AgentProfileSnapshot`, `BackendPreflightResult`, `AgentExecutionPlan`, and `AgentResponse`.
12
+ - Granular access, limit, tool, media, context, artifact, trace, usage, and diagnostic types.
13
+ - Host resolution through `resolveSubagentHostProfile()`.
14
+ - Tool negotiation through `negotiateSubagentTools()`.
15
+ - Deterministic context preparation through `budgetSubagentContext()`, `renderSubagentSelectedContext()`, and `prepareSubagentInitialMessages()`.
16
+ - Protected Pi-message helpers used by the SDK spike.
17
+ - Plan construction through `createAgentExecutionPlan()`.
18
+ - Pure request, snapshot, preflight, plan, response, artifact, and trace validators.
19
+ - Canonical `sha256:v1` profile, stack, and execution fingerprints.
20
+ - Optional backend registration, validated dispatch, cancellation/timeout arbitration, response normalization, and authorization-scoped trace routing through `SubagentBackendRegistry`.
21
+ - Experimental `PiSdkIsolatedBackend` compatibility adapter and the default `PiSubprocessBackend`, including their descriptors/IDs, report types, and host preparation through `prepareSubagentHostPlan()`.
22
+
23
+ The existing `agentProfileFingerprint()` remains unchanged. It is still the legacy JSON provenance value used for branch drift. New portable fingerprints use separately named functions and semantics.
24
+
25
+ ## Required Flow
26
+
27
+ ```text
28
+ AgentRequest
29
+ -> resolveSubagentHostProfile
30
+ -> SubagentBackendRegistry discovery/preflight
31
+ -> registry-mediated exact or backend-assisted preparation
32
+ -> createAgentExecutionPlan
33
+ -> registry-validated backend execution
34
+ -> validateAgentResponse
35
+ ```
36
+
37
+ No stage may substitute parent-runtime model objects, credentials, source file paths, or raw session history for the portable artifacts.
38
+
39
+ ### 1. Request validation
40
+
41
+ `validateAgentRequest()` checks:
42
+
43
+ - Schema, IDs, task text/media references, and media digests.
44
+ - Explicit selected-context byte budgets and provenance.
45
+ - Delegation depth.
46
+ - Access-level/workspace/working-directory/network/process combinations.
47
+ - Required versus best-effort hard limits.
48
+ - Result-projection bounds and remote-egress consent.
49
+
50
+ Media references are opaque host resources with content digests. The contract does not place local absolute paths or media bytes in the portable request.
51
+
52
+ ### 2. Host resolution
53
+
54
+ `resolveSubagentHostProfile()` performs only backend-independent work:
55
+
56
+ - Validates the loaded profile and exact prompt-stack reference.
57
+ - Accepts null, default/replace, append, and prepend stack modes.
58
+ - Scans prompt-stack items for custom macro and slot dependencies.
59
+ - Requires those registrations to be loaded before final resolution.
60
+ - Produces a path-free immutable profile snapshot and portable fingerprints.
61
+
62
+ It deliberately does not inspect a model registry, authentication, backend tools, mounts, or limits. Parent `/profile use` resolution remains separate.
63
+
64
+ Unknown macro commands and custom slots are treated as missing subagent dependencies. Static stack variables and built-in macros/slots are excluded. Custom registrations without a `source` still resolve but produce a warning because their dependency identity is anonymous.
65
+
66
+ ### 3. Backend preflight
67
+
68
+ An accepted `BackendPreflightResult` must identify the exact model/thinking level, dynamic tool catalog, granular capabilities, effective access receipt, and accepted limit receipt.
69
+
70
+ `validateBackendPreflight()` enforces:
71
+
72
+ - Exact profile model and thinking-level agreement.
73
+ - Explicit consent for remote provider transport.
74
+ - Requested media MIME support.
75
+ - No missing, extra, upgraded, or mode-mismatched mounts.
76
+ - Working-directory containment through backend mount IDs.
77
+ - Read/write, symlink, process, and denied-network enforcement claims.
78
+ - Every required limit uses `backend-hard` enforcement.
79
+ - Best-effort limits are reported honestly, such as Pi SDK host-abort timeouts.
80
+ - Rejected preflight results contain at least one error diagnostic.
81
+
82
+ Prompt tool filtering is not accepted as an access receipt.
83
+
84
+ ### 4. Tool negotiation
85
+
86
+ Each backend tool declares a stable backend ID, policy-facing name, and effects:
87
+
88
+ - `filesystem-read`
89
+ - `filesystem-write`
90
+ - `process`
91
+ - `network`
92
+
93
+ `negotiateSubagentTools()` applies prompt-stack policy to names, then removes tools whose declared effects exceed request access. Effect-free tools may remain under filesystem access `none`; network and process are independently controlled. Unmatched allow patterns remain warnings.
94
+
95
+ Adapters must classify tool effects conservatively. A tool with undeclared effects invalidates the backend's enforcement claim even if name filtering succeeds.
96
+
97
+ ### 5. Context and exact preparation
98
+
99
+ `budgetSubagentContext()` measures the exact UTF-8 bytes of the rendered selected-context envelope. Required items are retained first. Optional items are considered newest-to-oldest without partial item truncation, and returned in original order. Required overflow fails preparation.
100
+
101
+ `prepareSubagentInitialMessages()` creates:
102
+
103
+ 1. One quoted selected-context message when the budget retains context.
104
+ 2. Host-prepared prompt-stack messages.
105
+ 3. The complete protected task/media message as the final user message.
106
+
107
+ Prompt-stack messages cannot claim reserved selected-context or delegated-task markers.
108
+
109
+ Backends such as Pi SDK may expose exact base-prompt runtime inputs only in a pre-provider hook. They may call the host preparer there, but provider transport must remain blocked until `createAgentExecutionPlan()` succeeds. A `partial` prompt-runtime preflight cannot produce an execution plan.
110
+
111
+ ### 6. Plan and fingerprints
112
+
113
+ `createAgentExecutionPlan()` revalidates the request, snapshot, preflight, deterministic context receipt, tool negotiation, runtime fidelity, and protected final task. It creates the run ID correlation and execution fingerprint before provider transport.
114
+
115
+ The execution fingerprint covers all serialized plan fields except itself, including compiled system/messages, profile/stack/dependency provenance, the complete preflight receipt and adapter version, exact model/thinking, effective backend tool IDs, access and limit receipts, prompt-runtime fingerprint, context receipt, and result-projection bound.
116
+
117
+ Canonical serialization sorts object keys, omits undefined object fields, rejects cycles/non-finite numbers/non-JSON values, preserves array order, and normalizes negative zero.
118
+
119
+ ### 7. Response validation
120
+
121
+ `validateAgentResponse()` enforces the terminal status matrix:
122
+
123
+ | Status | Required terminal field | Output rule |
124
+ |---|---|---|
125
+ | `completed` | none | absent or `partial: false` |
126
+ | `failed` | structured `error` | absent or `partial: true` |
127
+ | `cancelled` | `reason` | absent or `partial: true` |
128
+ | `timed-out` | `reason`, `enforcedTimeoutMs` | absent or `partial: true` |
129
+ | `limit-reached` | `reachedLimit` | absent or `partial: true` |
130
+
131
+ It also validates request/run/backend correlation, model and fingerprints, effective backend tool IDs, backend-produced enforcement receipts, duration, token/cost units, artifact namespaces, relative paths, cleanup ownership, and authorized trace handles. Cost requires an ISO 4217 currency code.
132
+
133
+ ### 8. Optional backend registry
134
+
135
+ `SubagentBackendRegistry` starts empty and never installs a default backend. It:
136
+
137
+ - Validates backend descriptors and rejects duplicate identities.
138
+ - Binds accepted preflight IDs to the exact backend, request, and profile fingerprint used during discovery.
139
+ - Routes exact-preflight preparation directly to the host preparer and requires backend-assisted adapters to invoke the same host boundary.
140
+ - Binds the exact runtime fingerprint, compiled system/messages, effective tools, and context receipt returned by host preparation; recomputing an execution fingerprint cannot substitute a different plan.
141
+ - Routes dry-plan discard through the owning backend before forgetting the preflight binding.
142
+ - Rejects malformed, tampered, foreign, or unbound execution plans before transport.
143
+ - Arbitrates backend completion, explicit user cancellation, external abort signals, and declared host-abort timeouts through one terminal result.
144
+ - Discards prepared backend state without invoking execution when cancellation wins before backend dispatch.
145
+ - Normalizes thrown provider failures and malformed backend responses into contract-valid failed responses.
146
+ - Replaces backend-reported duration with host-observed duration.
147
+ - Keeps opaque backend trace IDs behind host-generated handles and enforces authorization scope, backend routing, expiry, and explicit forgetting during inspection.
148
+ - Refuses backend unregistration while an execution remains active or is draining after cancellation.
149
+
150
+ The registry validates receipts but does not manufacture filesystem, process, network, token, turn, or output isolation. Those remain adapter responsibilities.
151
+
152
+ Access receipts may explicitly declare `executionBoundary: "shared-user"`. This boundary means the subprocess retains the invoking user's operating-system permissions and its effective access is constrained only by the tools exposed to the model. A shared-user receipt cannot claim mount, symlink, process, or network isolation. Omitting the field preserves the legacy `isolated` interpretation.
153
+
154
+ ### 9. Experimental foreground subprocess and approval path
155
+
156
+ `PiSubprocessBackend` is the extension's deliberately narrow default adapter:
157
+
158
+ - It resolves the exact profile model through Pi's existing `ModelRegistry`, reuses the parent Pi 0.80.10 `ModelRuntime` so preparation sees the same authentication, and prepares the exact prompt inside an in-process Pi session held behind a provider gate.
159
+ - After approval, it disposes the preparation session and launches a fresh foreground Pi subprocess with the approved model, thinking level, system prompt, messages, and tool IDs. Pi's ordinary text stdout is drained separately from a dedicated newline-delimited report channel.
160
+ - Its bridge preserves the exact prepared messages and rejects tools outside the approved allowlist. Candidate tools are limited to `read`, `grep`, `find`, and `ls`, then intersected with prompt-stack policy.
161
+ - It loads no write/edit/shell tools, skills, prompt templates, context files, themes, or third-party Pi extensions and writes no child session file.
162
+ - It accepts text-only, one-shot, sequential `read-only` requests rooted at the project working directory, with no process tool and optional host-abort timeout. It advertises no artifact retention or contract trace inspection.
163
+ - It records a bounded foreground execution report containing sanitized transcript events, tool calls/results, usage, stderr, status, and execution identity. Inline images remain available to the child model but cross the report boundary only as MIME/encoded-size metadata. Base64-like text is redacted, individual strings are capped, and retained messages form a 512 KiB rolling tail so large tool histories cannot make the parent TUI/session retain unbounded data. Temporary bridge inputs are mode `0600` and removed during cleanup.
164
+ - Retained textual tool results are ordinary parent-session tool details. `/tree` can move the active branch away from them but does not erase abandoned entries from Pi's on-disk session JSONL; callers handling sensitive files must treat session-data deletion as a separate operation.
165
+
166
+ This backend declares `executionBoundary: "shared-user"`. It does not create allowed-root mount containment, symlink-safe path containment, process isolation, or agent-network isolation. The subprocess retains the invoking user's OS permissions; `read-only` describes the tools exposed to the model, not a security sandbox. Network is therefore honestly recorded as allowed even though no dedicated network or shell tool is exposed.
167
+
168
+ The model-callable `forge_subagent_profiles` tool reads the already-loaded host profile catalog without preparing a prompt or contacting a provider. It exposes IDs, names, descriptions, declared model/thinking/stack metadata, ready/unavailable resolution diagnostics, and whether parent policy currently exposes the invocation tool. A restrictive parent stack must allow both `forge_subagent_profiles` and `forge_subagent` for discovery followed by delegation.
169
+
170
+ The model-callable `forge_subagent` tool and `/forge-agent run` use the same registry path. Both prepare an exact immutable plan while provider transport remains closed. `/forge-agent run` always shows a compact approval summary, allows inspection of the complete prompt, and requires interactive approval bound to the execution fingerprint. The tool does the same by default, but a trusted project may set `subagents.allowAgentInvocationWithoutApproval: true` in `.pi/forge/config.json`; this permits non-UI model invocation and records `trusted-project-config` in the result receipt without weakening preflight or plan binding. Missing, malformed, and untrusted-project settings fail closed. The tool returns bounded content to the parent model and expandable execution details to the human. `/forge-agent plan` still prepares and discards without provider transport; `/forge-agent backends` shows capabilities. The older access-none `PiSdkIsolatedBackend` remains exported and tested for compatibility but is not the extension default.
171
+
172
+ ## Adapter-Enforced Responsibilities
173
+
174
+ The exported validators cannot create isolation. Every adapter remains responsible for:
175
+
176
+ - Credential and model availability in its own runtime.
177
+ - Backend-side mount materialization and path canonicalization immediately before access.
178
+ - Symlink-race-safe containment.
179
+ - Process and agent-network isolation.
180
+ - Accurate tool effects and stable tool mappings.
181
+ - Required hard timeout, turn, token, and output limits.
182
+ - Cancellation settlement and cleanup.
183
+ - Media transport and remote-egress behavior.
184
+ - Artifact authorization, retention, and cleanup.
185
+ - Trace storage, authorization, redaction, pagination, and expiry.
186
+ - Returning actual enforcement receipts rather than echoing request fields.
187
+
188
+ An adapter must reject preflight when it cannot enforce a required field. The retained Pi SDK adapter can execute only access `none`; the subprocess adapter accepts shared-user read-only access and network allow. Both use best-effort host abort rather than a backend-hard timeout. Provider transport is always a separate, explicitly approved egress path.
189
+
190
+ ## Deliberately Not Included
191
+
192
+ - Filesystem writes, process/shell tools, media input, background runs, or general backend selection/configuration in the shipped path.
193
+ - OS-level filesystem, process, or network sandboxing for the shared-user subprocess.
194
+ - Automatic parent-history/context selection; the delegated task is explicit and starts a clean conversation.
195
+ - Session resume, retries, queues, chains, or pipelines.
196
+ - Artifact/trace storage implementations.
197
+ - Automatic provider fallback.
198
+
199
+ Those belong to later iterations and cannot be inferred from these pure types alone.
@@ -0,0 +1,71 @@
1
+ import type { ThinkingLevel } from "@earendil-works/pi-agent-core";
2
+ import { type Model } from "@earendil-works/pi-ai";
3
+ import type { LoadedPromptStack } from "./types.ts";
4
+ export declare const AGENT_PROFILE_TYPE: "pi-forge.agent-profile";
5
+ export declare const AGENT_PROFILE_THINKING_LEVELS: readonly ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
6
+ export interface AgentProfileModelReference {
7
+ provider: string;
8
+ id: string;
9
+ }
10
+ export interface AgentProfile {
11
+ schemaVersion: 1;
12
+ type: typeof AGENT_PROFILE_TYPE;
13
+ id: string;
14
+ name?: string;
15
+ description?: string;
16
+ autoActivate?: boolean;
17
+ model: AgentProfileModelReference;
18
+ thinkingLevel: ThinkingLevel;
19
+ promptStack: string | null;
20
+ }
21
+ export type AgentProfileDiagnosticLevel = "error" | "warning" | "info";
22
+ export interface AgentProfileDiagnostic {
23
+ level: AgentProfileDiagnosticLevel;
24
+ message: string;
25
+ field?: string;
26
+ }
27
+ export interface LoadedAgentProfile {
28
+ profile: AgentProfile;
29
+ filePath: string;
30
+ diagnostics: AgentProfileDiagnostic[];
31
+ }
32
+ export interface AgentProfileResolutionResources {
33
+ models: readonly Model<any>[];
34
+ availableModels?: readonly Model<any>[];
35
+ promptStacks: readonly LoadedPromptStack[];
36
+ toolNames?: readonly string[];
37
+ }
38
+ export interface ResolvedAgentProfile {
39
+ loaded: LoadedAgentProfile;
40
+ model?: Model<any>;
41
+ promptStack?: LoadedPromptStack;
42
+ effectiveThinkingLevel: ThinkingLevel;
43
+ diagnostics: AgentProfileDiagnostic[];
44
+ }
45
+ export interface AgentProfileRuntimeSnapshot {
46
+ model: AgentProfileModelReference;
47
+ thinkingLevel: ThinkingLevel;
48
+ promptStack: string | null;
49
+ }
50
+ export interface AgentProfileProvenance {
51
+ profileId: string;
52
+ sourcePath: string;
53
+ sourceFingerprint: string;
54
+ appliedAt: string;
55
+ snapshot: AgentProfileRuntimeSnapshot;
56
+ }
57
+ export { agentProfilePath, agentProfilesDir } from "./storage.ts";
58
+ export declare function isValidAgentProfileId(id: string): boolean;
59
+ export declare function loadAgentProfiles(cwd: string): LoadedAgentProfile[];
60
+ export declare function chooseAutoActivateAgentProfile(profiles: readonly LoadedAgentProfile[]): LoadedAgentProfile | undefined;
61
+ export declare function hasAutoActivateAgentProfile(profiles: readonly LoadedAgentProfile[]): boolean;
62
+ export declare function loadAgentProfileFile(filePath: string): LoadedAgentProfile;
63
+ export declare function validateAgentProfile(profile: AgentProfile): AgentProfileDiagnostic[];
64
+ export declare function resolveAgentProfile(loaded: LoadedAgentProfile, resources: AgentProfileResolutionResources): ResolvedAgentProfile;
65
+ export declare function isUsableAgentProfile(loaded: LoadedAgentProfile): boolean;
66
+ export declare function isResolvedAgentProfileUsable(resolved: ResolvedAgentProfile): boolean;
67
+ export declare function hasAgentProfileErrors(diagnostics: readonly AgentProfileDiagnostic[]): boolean;
68
+ export declare function renderAgentProfileDiagnostics(diagnostics: readonly AgentProfileDiagnostic[]): string;
69
+ export declare function agentProfileFingerprint(profile: AgentProfile): string;
70
+ export declare function isAgentProfileProvenance(value: unknown): value is AgentProfileProvenance;
71
+ //# sourceMappingURL=agent-profile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-profile.d.ts","sourceRoot":"","sources":["../src/agent-profile.ts"],"names":[],"mappings":"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"}