@ai-agent-forge/agent-forge 0.88.0 → 0.88.2

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 (445) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/bundled-plugins/agent-loop-policy/agent-forge.json +19 -0
  3. package/bundled-plugins/agent-loop-policy/dist/entry.d.ts +28 -0
  4. package/bundled-plugins/agent-loop-policy/dist/entry.d.ts.map +1 -0
  5. package/bundled-plugins/agent-loop-policy/dist/entry.js +69 -0
  6. package/bundled-plugins/agent-loop-policy/dist/entry.js.map +1 -0
  7. package/bundled-plugins/agent-loop-policy/dist/loop-guard.d.ts +199 -0
  8. package/bundled-plugins/agent-loop-policy/dist/loop-guard.d.ts.map +1 -0
  9. package/bundled-plugins/agent-loop-policy/dist/loop-guard.js +208 -0
  10. package/bundled-plugins/agent-loop-policy/dist/loop-guard.js.map +1 -0
  11. package/bundled-plugins/agent-loop-policy/dist/run-loop-strategy.d.ts +17 -0
  12. package/bundled-plugins/agent-loop-policy/dist/run-loop-strategy.d.ts.map +1 -0
  13. package/bundled-plugins/agent-loop-policy/dist/run-loop-strategy.js +18 -0
  14. package/bundled-plugins/agent-loop-policy/dist/run-loop-strategy.js.map +1 -0
  15. package/bundled-plugins/agent-loop-policy/plugin.json +7 -0
  16. package/bundled-plugins/coding-tools/agent-forge.json +19 -0
  17. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/bash.d.ts +5 -44
  18. package/bundled-plugins/coding-tools/dist/bash.d.ts.map +1 -0
  19. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/bash.js +15 -119
  20. package/bundled-plugins/coding-tools/dist/bash.js.map +1 -0
  21. package/bundled-plugins/coding-tools/dist/capability.d.ts +25 -0
  22. package/bundled-plugins/coding-tools/dist/capability.d.ts.map +1 -0
  23. package/bundled-plugins/coding-tools/dist/capability.js +98 -0
  24. package/bundled-plugins/coding-tools/dist/capability.js.map +1 -0
  25. package/bundled-plugins/coding-tools/dist/config.d.ts +8 -0
  26. package/bundled-plugins/coding-tools/dist/config.d.ts.map +1 -0
  27. package/bundled-plugins/coding-tools/dist/config.js +8 -0
  28. package/bundled-plugins/coding-tools/dist/config.js.map +1 -0
  29. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/edit.d.ts +3 -3
  30. package/bundled-plugins/coding-tools/dist/edit.d.ts.map +1 -0
  31. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/edit.js +12 -10
  32. package/bundled-plugins/coding-tools/dist/edit.js.map +1 -0
  33. package/bundled-plugins/coding-tools/dist/entry.d.ts +14 -0
  34. package/bundled-plugins/coding-tools/dist/entry.d.ts.map +1 -0
  35. package/bundled-plugins/coding-tools/dist/entry.js +23 -0
  36. package/bundled-plugins/coding-tools/dist/entry.js.map +1 -0
  37. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/find.d.ts +4 -4
  38. package/bundled-plugins/coding-tools/dist/find.d.ts.map +1 -0
  39. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/find.js +10 -8
  40. package/bundled-plugins/coding-tools/dist/find.js.map +1 -0
  41. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/grep.d.ts +3 -3
  42. package/bundled-plugins/coding-tools/dist/grep.d.ts.map +1 -0
  43. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/grep.js +10 -8
  44. package/bundled-plugins/coding-tools/dist/grep.js.map +1 -0
  45. package/bundled-plugins/coding-tools/dist/index.d.ts +17 -0
  46. package/bundled-plugins/coding-tools/dist/index.d.ts.map +1 -0
  47. package/bundled-plugins/coding-tools/dist/index.js +17 -0
  48. package/bundled-plugins/coding-tools/dist/index.js.map +1 -0
  49. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/ls.d.ts +3 -3
  50. package/bundled-plugins/coding-tools/dist/ls.d.ts.map +1 -0
  51. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/ls.js +8 -6
  52. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/ls.js.map +1 -1
  53. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/powershell.d.ts +2 -1
  54. package/bundled-plugins/coding-tools/dist/powershell.d.ts.map +1 -0
  55. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/powershell.js +6 -3
  56. package/bundled-plugins/coding-tools/dist/powershell.js.map +1 -0
  57. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/read.d.ts +3 -3
  58. package/bundled-plugins/coding-tools/dist/read.d.ts.map +1 -0
  59. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/read.js +15 -13
  60. package/bundled-plugins/coding-tools/dist/read.js.map +1 -0
  61. package/bundled-plugins/coding-tools/dist/types.d.ts +74 -0
  62. package/bundled-plugins/coding-tools/dist/types.d.ts.map +1 -0
  63. package/bundled-plugins/coding-tools/dist/types.js +28 -0
  64. package/bundled-plugins/coding-tools/dist/types.js.map +1 -0
  65. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/write.d.ts +2 -2
  66. package/bundled-plugins/coding-tools/dist/write.d.ts.map +1 -0
  67. package/{dist/core/tools → bundled-plugins/coding-tools/dist}/write.js +11 -9
  68. package/bundled-plugins/coding-tools/dist/write.js.map +1 -0
  69. package/bundled-plugins/coding-tools/plugin.json +10 -0
  70. package/bundled-plugins/compaction-policy/agent-forge.json +19 -0
  71. package/bundled-plugins/compaction-policy/dist/branch-summary-policy.d.ts +6 -0
  72. package/bundled-plugins/compaction-policy/dist/branch-summary-policy.d.ts.map +1 -0
  73. package/bundled-plugins/compaction-policy/dist/branch-summary-policy.js +19 -0
  74. package/bundled-plugins/compaction-policy/dist/branch-summary-policy.js.map +1 -0
  75. package/bundled-plugins/compaction-policy/dist/compaction-policy.d.ts +6 -0
  76. package/bundled-plugins/compaction-policy/dist/compaction-policy.d.ts.map +1 -0
  77. package/bundled-plugins/compaction-policy/dist/compaction-policy.js +38 -0
  78. package/bundled-plugins/compaction-policy/dist/compaction-policy.js.map +1 -0
  79. package/bundled-plugins/compaction-policy/dist/entry.d.ts +13 -0
  80. package/bundled-plugins/compaction-policy/dist/entry.d.ts.map +1 -0
  81. package/bundled-plugins/compaction-policy/dist/entry.js +23 -0
  82. package/bundled-plugins/compaction-policy/dist/entry.js.map +1 -0
  83. package/bundled-plugins/compaction-policy/plugin.json +10 -0
  84. package/bundled-plugins/mcp-http/dist/index.d.ts +8 -0
  85. package/bundled-plugins/mcp-http/dist/index.d.ts.map +1 -0
  86. package/bundled-plugins/mcp-http/dist/index.js +8 -0
  87. package/bundled-plugins/mcp-http/dist/index.js.map +1 -0
  88. package/bundled-plugins/mcp-http/dist/mcp-http.d.ts.map +1 -0
  89. package/{dist/plugins → bundled-plugins/mcp-http/dist}/mcp-http.js +1 -1
  90. package/bundled-plugins/mcp-http/dist/mcp-http.js.map +1 -0
  91. package/bundled-plugins/overflow-policy/agent-forge.json +19 -0
  92. package/bundled-plugins/overflow-policy/dist/entry.d.ts +16 -0
  93. package/bundled-plugins/overflow-policy/dist/entry.d.ts.map +1 -0
  94. package/bundled-plugins/overflow-policy/dist/entry.js +35 -0
  95. package/bundled-plugins/overflow-policy/dist/entry.js.map +1 -0
  96. package/bundled-plugins/overflow-policy/plugin.json +10 -0
  97. package/bundled-plugins/provider-failover/agent-forge.json +19 -0
  98. package/bundled-plugins/provider-failover/dist/entry.d.ts +8 -0
  99. package/bundled-plugins/provider-failover/dist/entry.d.ts.map +1 -0
  100. package/bundled-plugins/provider-failover/dist/entry.js +8 -0
  101. package/bundled-plugins/provider-failover/dist/entry.js.map +1 -0
  102. package/bundled-plugins/provider-failover/dist/provider-failover.d.ts +122 -0
  103. package/bundled-plugins/provider-failover/dist/provider-failover.d.ts.map +1 -0
  104. package/{dist/core/extensions → bundled-plugins/provider-failover/dist}/provider-failover.js +143 -56
  105. package/bundled-plugins/provider-failover/dist/provider-failover.js.map +1 -0
  106. package/bundled-plugins/provider-failover/plugin.json +7 -0
  107. package/bundled-plugins/retry-policy/agent-forge.json +19 -0
  108. package/bundled-plugins/retry-policy/dist/entry.d.ts +16 -0
  109. package/bundled-plugins/retry-policy/dist/entry.d.ts.map +1 -0
  110. package/bundled-plugins/retry-policy/dist/entry.js +34 -0
  111. package/bundled-plugins/retry-policy/dist/entry.js.map +1 -0
  112. package/bundled-plugins/retry-policy/plugin.json +10 -0
  113. package/dist/bundle/.build-manifest.json +109 -155
  114. package/dist/bundle/chunks/{anthropic-messages-ALDZBUKI.js → anthropic-messages-PLAKXR73.js} +1 -1
  115. package/dist/bundle/chunks/{azure-openai-responses-A2WJWZFB.js → azure-openai-responses-OUWQ2AZD.js} +1 -1
  116. package/dist/bundle/chunks/chunk-44I47ACN.js +13 -0
  117. package/dist/bundle/chunks/chunk-6F5JWGKE.js +4 -0
  118. package/dist/bundle/chunks/{chunk-CIX3FSBK.js → chunk-A3JYRWB6.js} +1 -1
  119. package/dist/bundle/chunks/{chunk-SQFG22WN.js → chunk-AC2FIS4G.js} +1 -1
  120. package/dist/bundle/chunks/chunk-HTC5K5SM.js +866 -0
  121. package/dist/bundle/chunks/{chunk-YJCQVXW5.js → chunk-HTEVUY7F.js} +1 -1
  122. package/dist/bundle/chunks/{chunk-Y7HXTASS.js → chunk-HV64ASMT.js} +1 -1
  123. package/dist/bundle/chunks/chunk-LSP24WNH.js +665 -0
  124. package/dist/bundle/chunks/{chunk-7ZY7IXZD.js → chunk-TRDNDS6A.js} +1 -1
  125. package/dist/bundle/chunks/{google-generative-ai-NIB4WONV.js → google-generative-ai-DLII6DAT.js} +1 -1
  126. package/dist/bundle/chunks/{google-vertex-DCPYUEUO.js → google-vertex-G7BZL7GM.js} +1 -1
  127. package/dist/bundle/chunks/image-resize-worker.js +4 -4
  128. package/dist/bundle/chunks/{mistral-conversations-OC6LA5XL.js → mistral-conversations-JXUK24ID.js} +1 -1
  129. package/dist/bundle/chunks/{openai-codex-responses-IO2X4Y7L.js → openai-codex-responses-5GSGFIPG.js} +1 -1
  130. package/dist/bundle/chunks/{openai-completions-XYQQHETU.js → openai-completions-EI2I6DTG.js} +1 -1
  131. package/dist/bundle/chunks/{openai-responses-DLIRN3CI.js → openai-responses-AUJQ3NWT.js} +1 -1
  132. package/dist/bundle/chunks/{pi-messages-E6RRYBO7.js → pi-messages-PWU2VJMR.js} +1 -1
  133. package/dist/bundle/chunks/virtual-modules-MRXD3RWG.js +5 -0
  134. package/dist/bundle/cli.js +1 -1
  135. package/dist/bundle/client.js +1 -1
  136. package/dist/bundle/index.js +3 -3
  137. package/dist/bundle/rpc-entry.js +1 -1
  138. package/dist/capabilities/builtin.d.ts +1 -1
  139. package/dist/capabilities/builtin.d.ts.map +1 -1
  140. package/dist/capabilities/builtin.js +5 -0
  141. package/dist/capabilities/builtin.js.map +1 -1
  142. package/dist/cli/plugin-command.d.ts.map +1 -1
  143. package/dist/cli/plugin-command.js +25 -3
  144. package/dist/cli/plugin-command.js.map +1 -1
  145. package/dist/config.d.ts +2 -3
  146. package/dist/config.d.ts.map +1 -1
  147. package/dist/config.js +2 -4
  148. package/dist/config.js.map +1 -1
  149. package/dist/core/agent-session-bash.d.ts +1 -1
  150. package/dist/core/agent-session-bash.d.ts.map +1 -1
  151. package/dist/core/agent-session-bash.js +1 -1
  152. package/dist/core/agent-session-bash.js.map +1 -1
  153. package/dist/core/agent-session-compaction.d.ts.map +1 -1
  154. package/dist/core/agent-session-compaction.js +14 -1
  155. package/dist/core/agent-session-compaction.js.map +1 -1
  156. package/dist/core/agent-session-internal.d.ts +3 -1
  157. package/dist/core/agent-session-internal.d.ts.map +1 -1
  158. package/dist/core/agent-session-internal.js.map +1 -1
  159. package/dist/core/agent-session-loop.d.ts +4 -3
  160. package/dist/core/agent-session-loop.d.ts.map +1 -1
  161. package/dist/core/agent-session-loop.js +9 -6
  162. package/dist/core/agent-session-loop.js.map +1 -1
  163. package/dist/core/agent-session-retry.d.ts +1 -1
  164. package/dist/core/agent-session-retry.d.ts.map +1 -1
  165. package/dist/core/agent-session-retry.js +32 -3
  166. package/dist/core/agent-session-retry.js.map +1 -1
  167. package/dist/core/agent-session-services.d.ts +2 -0
  168. package/dist/core/agent-session-services.d.ts.map +1 -1
  169. package/dist/core/agent-session-services.js +31 -9
  170. package/dist/core/agent-session-services.js.map +1 -1
  171. package/dist/core/agent-session-store.d.ts.map +1 -1
  172. package/dist/core/agent-session-store.js +6 -1
  173. package/dist/core/agent-session-store.js.map +1 -1
  174. package/dist/core/agent-session-tools.d.ts.map +1 -1
  175. package/dist/core/agent-session-tools.js +18 -1
  176. package/dist/core/agent-session-tools.js.map +1 -1
  177. package/dist/core/agent-session.d.ts +34 -11
  178. package/dist/core/agent-session.d.ts.map +1 -1
  179. package/dist/core/agent-session.js +114 -38
  180. package/dist/core/agent-session.js.map +1 -1
  181. package/dist/core/bash-executor.d.ts +1 -1
  182. package/dist/core/bash-executor.d.ts.map +1 -1
  183. package/dist/core/bash-executor.js.map +1 -1
  184. package/dist/core/extensions/bootstrap-agent-loop.d.ts +23 -151
  185. package/dist/core/extensions/bootstrap-agent-loop.d.ts.map +1 -1
  186. package/dist/core/extensions/bootstrap-agent-loop.js +28 -290
  187. package/dist/core/extensions/bootstrap-agent-loop.js.map +1 -1
  188. package/dist/core/extensions/capability-runtime-types.d.ts +5 -3
  189. package/dist/core/extensions/capability-runtime-types.d.ts.map +1 -1
  190. package/dist/core/extensions/capability-runtime-types.js.map +1 -1
  191. package/dist/core/extensions/capability-runtime.d.ts.map +1 -1
  192. package/dist/core/extensions/capability-runtime.js +42 -6
  193. package/dist/core/extensions/capability-runtime.js.map +1 -1
  194. package/dist/core/extensions/index.d.ts +12 -5
  195. package/dist/core/extensions/index.d.ts.map +1 -1
  196. package/dist/core/extensions/index.js +12 -5
  197. package/dist/core/extensions/index.js.map +1 -1
  198. package/dist/core/extensions/virtual-modules.d.ts.map +1 -1
  199. package/dist/core/extensions/virtual-modules.js +65 -0
  200. package/dist/core/extensions/virtual-modules.js.map +1 -1
  201. package/dist/core/facade/coding-agent-facade.d.ts +1 -1
  202. package/dist/core/facade/coding-agent-facade.d.ts.map +1 -1
  203. package/dist/core/facade/coding-agent-facade.js.map +1 -1
  204. package/dist/core/i18n/locales/zh-cn/cli.d.ts.map +1 -1
  205. package/dist/core/i18n/locales/zh-cn/cli.js +2 -0
  206. package/dist/core/i18n/locales/zh-cn/cli.js.map +1 -1
  207. package/dist/core/i18n/locales/zh-cn/core-contract-core.d.ts +1 -1
  208. package/dist/core/i18n/locales/zh-cn/core-contract-core.d.ts.map +1 -1
  209. package/dist/core/i18n/locales/zh-cn/core-contract-core.js +1 -1
  210. package/dist/core/i18n/locales/zh-cn/core-contract-core.js.map +1 -1
  211. package/dist/core/i18n/locales/zh-cn/core-contract-extensions.d.ts.map +1 -1
  212. package/dist/core/i18n/locales/zh-cn/core-contract-extensions.js +2 -4
  213. package/dist/core/i18n/locales/zh-cn/core-contract-extensions.js.map +1 -1
  214. package/dist/core/i18n/locales/zh-cn/core-errors.d.ts.map +1 -1
  215. package/dist/core/i18n/locales/zh-cn/core-errors.js +3 -1
  216. package/dist/core/i18n/locales/zh-cn/core-errors.js.map +1 -1
  217. package/dist/core/i18n/locales/zh-cn/index.d.ts.map +1 -1
  218. package/dist/core/i18n/locales/zh-cn/index.js +2 -0
  219. package/dist/core/i18n/locales/zh-cn/index.js.map +1 -1
  220. package/dist/core/i18n/locales/zh-cn/interactive-mode.d.ts.map +1 -1
  221. package/dist/core/i18n/locales/zh-cn/interactive-mode.js +5 -0
  222. package/dist/core/i18n/locales/zh-cn/interactive-mode.js.map +1 -1
  223. package/dist/core/i18n/locales/zh-cn/session-cleanup.d.ts +7 -0
  224. package/dist/core/i18n/locales/zh-cn/session-cleanup.d.ts.map +1 -0
  225. package/dist/core/i18n/locales/zh-cn/session-cleanup.js +15 -0
  226. package/dist/core/i18n/locales/zh-cn/session-cleanup.js.map +1 -0
  227. package/dist/core/i18n/locales/zh-cn/slash-commands.d.ts.map +1 -1
  228. package/dist/core/i18n/locales/zh-cn/slash-commands.js +1 -0
  229. package/dist/core/i18n/locales/zh-cn/slash-commands.js.map +1 -1
  230. package/dist/core/sdk.d.ts +10 -3
  231. package/dist/core/sdk.d.ts.map +1 -1
  232. package/dist/core/sdk.js +287 -78
  233. package/dist/core/sdk.js.map +1 -1
  234. package/dist/core/session-cleanup.d.ts +49 -0
  235. package/dist/core/session-cleanup.d.ts.map +1 -0
  236. package/dist/core/session-cleanup.js +159 -0
  237. package/dist/core/session-cleanup.js.map +1 -0
  238. package/dist/core/session-index.d.ts +75 -0
  239. package/dist/core/session-index.d.ts.map +1 -0
  240. package/dist/core/session-index.js +455 -0
  241. package/dist/core/session-index.js.map +1 -0
  242. package/dist/core/session-manager.d.ts +9 -0
  243. package/dist/core/session-manager.d.ts.map +1 -1
  244. package/dist/core/session-manager.js +202 -47
  245. package/dist/core/session-manager.js.map +1 -1
  246. package/dist/core/slash-commands.d.ts.map +1 -1
  247. package/dist/core/slash-commands.js +5 -0
  248. package/dist/core/slash-commands.js.map +1 -1
  249. package/dist/core/system-prompt.d.ts.map +1 -1
  250. package/dist/core/system-prompt.js +12 -1
  251. package/dist/core/system-prompt.js.map +1 -1
  252. package/dist/core/tools/bash-operations.d.ts +41 -0
  253. package/dist/core/tools/bash-operations.d.ts.map +1 -0
  254. package/dist/core/tools/bash-operations.js +113 -0
  255. package/dist/core/tools/bash-operations.js.map +1 -0
  256. package/dist/core/tools/capability-mount.d.ts +40 -0
  257. package/dist/core/tools/capability-mount.d.ts.map +1 -0
  258. package/dist/core/tools/capability-mount.js +112 -0
  259. package/dist/core/tools/capability-mount.js.map +1 -0
  260. package/dist/core/tools/index.d.ts +12 -36
  261. package/dist/core/tools/index.d.ts.map +1 -1
  262. package/dist/core/tools/index.js +1 -117
  263. package/dist/core/tools/index.js.map +1 -1
  264. package/dist/core/tools/readme-path.d.ts +3 -0
  265. package/dist/core/tools/readme-path.d.ts.map +1 -0
  266. package/dist/core/tools/readme-path.js +15 -0
  267. package/dist/core/tools/readme-path.js.map +1 -0
  268. package/dist/index.d.ts +3 -19
  269. package/dist/index.d.ts.map +1 -1
  270. package/dist/index.js +6 -39
  271. package/dist/index.js.map +1 -1
  272. package/dist/main.d.ts.map +1 -1
  273. package/dist/main.js +1 -0
  274. package/dist/main.js.map +1 -1
  275. package/dist/modes/interactive/components/assistant-message.d.ts +3 -0
  276. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  277. package/dist/modes/interactive/components/assistant-message.js +27 -5
  278. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  279. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
  280. package/dist/modes/interactive/components/session-selector-search.js +5 -1
  281. package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  282. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  283. package/dist/modes/interactive/components/session-selector.js +9 -0
  284. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  285. package/dist/modes/interactive/components/tool-execution.d.ts +17 -1
  286. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  287. package/dist/modes/interactive/components/tool-execution.js +52 -25
  288. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  289. package/dist/modes/interactive/components/tool-run-group.d.ts +44 -0
  290. package/dist/modes/interactive/components/tool-run-group.d.ts.map +1 -0
  291. package/dist/modes/interactive/components/tool-run-group.js +121 -0
  292. package/dist/modes/interactive/components/tool-run-group.js.map +1 -0
  293. package/dist/modes/interactive/interactive-commands.d.ts +2 -0
  294. package/dist/modes/interactive/interactive-commands.d.ts.map +1 -1
  295. package/dist/modes/interactive/interactive-commands.js +7 -0
  296. package/dist/modes/interactive/interactive-commands.js.map +1 -1
  297. package/dist/modes/interactive/interactive-mode.d.ts +18 -0
  298. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  299. package/dist/modes/interactive/interactive-mode.js +85 -3
  300. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  301. package/dist/plugins/ecosystem/cli.d.ts.map +1 -1
  302. package/dist/plugins/ecosystem/cli.js +20 -5
  303. package/dist/plugins/ecosystem/cli.js.map +1 -1
  304. package/dist/plugins/ecosystem/node-npm-registry-source.d.ts +7 -2
  305. package/dist/plugins/ecosystem/node-npm-registry-source.d.ts.map +1 -1
  306. package/dist/plugins/ecosystem/node-npm-registry-source.js +64 -9
  307. package/dist/plugins/ecosystem/node-npm-registry-source.js.map +1 -1
  308. package/dist/plugins/ecosystem/node-plugin-acquisition-host.d.ts.map +1 -1
  309. package/dist/plugins/ecosystem/node-plugin-acquisition-host.js +6 -0
  310. package/dist/plugins/ecosystem/node-plugin-acquisition-host.js.map +1 -1
  311. package/dist/plugins/ecosystem/node-plugin-bootstrap.d.ts +7 -1
  312. package/dist/plugins/ecosystem/node-plugin-bootstrap.d.ts.map +1 -1
  313. package/dist/plugins/ecosystem/node-plugin-bootstrap.js +50 -3
  314. package/dist/plugins/ecosystem/node-plugin-bootstrap.js.map +1 -1
  315. package/dist/plugins/ecosystem/plugin-bootstrap.d.ts +28 -16
  316. package/dist/plugins/ecosystem/plugin-bootstrap.d.ts.map +1 -1
  317. package/dist/plugins/ecosystem/plugin-bootstrap.js +35 -33
  318. package/dist/plugins/ecosystem/plugin-bootstrap.js.map +1 -1
  319. package/dist/profile/plugin-profiles.d.ts +1 -1
  320. package/dist/profile/plugin-profiles.d.ts.map +1 -1
  321. package/dist/profile/plugin-profiles.js +18 -0
  322. package/dist/profile/plugin-profiles.js.map +1 -1
  323. package/dist/profiles/builtin-suites.d.ts +19 -5
  324. package/dist/profiles/builtin-suites.d.ts.map +1 -1
  325. package/dist/profiles/builtin-suites.js +26 -6
  326. package/dist/profiles/builtin-suites.js.map +1 -1
  327. package/docs/settings.md +354 -354
  328. package/docs/usage.md +292 -292
  329. package/examples/extensions/bash-spawn-hook/index.ts +7 -2
  330. package/examples/extensions/built-in-tool-renderer/index.ts +4 -2
  331. package/examples/extensions/minimal-mode/index.ts +2 -2
  332. package/examples/extensions/truncated-tool/index.ts +1 -1
  333. package/examples/extensions/with-deps/package-lock.json +2 -2
  334. package/examples/extensions/with-deps/package.json +1 -1
  335. package/examples/extensions/with-deps/plugin.json +1 -1
  336. package/package.json +3 -2
  337. package/dist/bundle/chunks/chunk-6ZKDNZHA.js +0 -145
  338. package/dist/bundle/chunks/chunk-HLJEVRWP.js +0 -13
  339. package/dist/bundle/chunks/chunk-YGHQME4V.js +0 -1456
  340. package/dist/bundle/chunks/virtual-modules-KZ5DRH7Q.js +0 -2
  341. package/dist/core/extensions/bootstrap-branch-summary-policy.d.ts +0 -7
  342. package/dist/core/extensions/bootstrap-branch-summary-policy.d.ts.map +0 -1
  343. package/dist/core/extensions/bootstrap-branch-summary-policy.js +0 -28
  344. package/dist/core/extensions/bootstrap-branch-summary-policy.js.map +0 -1
  345. package/dist/core/extensions/bootstrap-compaction-policy.d.ts +0 -7
  346. package/dist/core/extensions/bootstrap-compaction-policy.d.ts.map +0 -1
  347. package/dist/core/extensions/bootstrap-compaction-policy.js +0 -48
  348. package/dist/core/extensions/bootstrap-compaction-policy.js.map +0 -1
  349. package/dist/core/extensions/bootstrap-overflow-policy.d.ts +0 -7
  350. package/dist/core/extensions/bootstrap-overflow-policy.d.ts.map +0 -1
  351. package/dist/core/extensions/bootstrap-overflow-policy.js +0 -30
  352. package/dist/core/extensions/bootstrap-overflow-policy.js.map +0 -1
  353. package/dist/core/extensions/bootstrap-retry-policy.d.ts +0 -7
  354. package/dist/core/extensions/bootstrap-retry-policy.d.ts.map +0 -1
  355. package/dist/core/extensions/bootstrap-retry-policy.js +0 -29
  356. package/dist/core/extensions/bootstrap-retry-policy.js.map +0 -1
  357. package/dist/core/extensions/bootstrap-tools.d.ts +0 -20
  358. package/dist/core/extensions/bootstrap-tools.d.ts.map +0 -1
  359. package/dist/core/extensions/bootstrap-tools.js +0 -36
  360. package/dist/core/extensions/bootstrap-tools.js.map +0 -1
  361. package/dist/core/extensions/provider-failover.d.ts +0 -110
  362. package/dist/core/extensions/provider-failover.d.ts.map +0 -1
  363. package/dist/core/extensions/provider-failover.js.map +0 -1
  364. package/dist/core/tools/bash.d.ts.map +0 -1
  365. package/dist/core/tools/bash.js.map +0 -1
  366. package/dist/core/tools/edit.d.ts.map +0 -1
  367. package/dist/core/tools/edit.js.map +0 -1
  368. package/dist/core/tools/find.d.ts.map +0 -1
  369. package/dist/core/tools/find.js.map +0 -1
  370. package/dist/core/tools/grep.d.ts.map +0 -1
  371. package/dist/core/tools/grep.js.map +0 -1
  372. package/dist/core/tools/ls.d.ts.map +0 -1
  373. package/dist/core/tools/powershell.d.ts.map +0 -1
  374. package/dist/core/tools/powershell.js.map +0 -1
  375. package/dist/core/tools/read.d.ts.map +0 -1
  376. package/dist/core/tools/read.js.map +0 -1
  377. package/dist/core/tools/write.d.ts.map +0 -1
  378. package/dist/core/tools/write.js.map +0 -1
  379. package/dist/plugins/mcp-http.d.ts.map +0 -1
  380. package/dist/plugins/mcp-http.js.map +0 -1
  381. package/dist/profile/child-facade.d.ts +0 -44
  382. package/dist/profile/child-facade.d.ts.map +0 -1
  383. package/dist/profile/child-facade.js +0 -56
  384. package/dist/profile/child-facade.js.map +0 -1
  385. package/dist/profile/dependency-wiring.d.ts +0 -48
  386. package/dist/profile/dependency-wiring.d.ts.map +0 -1
  387. package/dist/profile/dependency-wiring.js +0 -56
  388. package/dist/profile/dependency-wiring.js.map +0 -1
  389. package/dist/profile/domain-recovery.d.ts +0 -60
  390. package/dist/profile/domain-recovery.d.ts.map +0 -1
  391. package/dist/profile/domain-recovery.js +0 -94
  392. package/dist/profile/domain-recovery.js.map +0 -1
  393. package/dist/profile/first-roles.d.ts +0 -30
  394. package/dist/profile/first-roles.d.ts.map +0 -1
  395. package/dist/profile/first-roles.js +0 -83
  396. package/dist/profile/first-roles.js.map +0 -1
  397. package/dist/profile/goal-plugin.d.ts +0 -38
  398. package/dist/profile/goal-plugin.d.ts.map +0 -1
  399. package/dist/profile/goal-plugin.js +0 -132
  400. package/dist/profile/goal-plugin.js.map +0 -1
  401. package/dist/profile/plan-plugin.d.ts +0 -44
  402. package/dist/profile/plan-plugin.d.ts.map +0 -1
  403. package/dist/profile/plan-plugin.js +0 -157
  404. package/dist/profile/plan-plugin.js.map +0 -1
  405. package/dist/profile/policy-manifest.d.ts +0 -53
  406. package/dist/profile/policy-manifest.d.ts.map +0 -1
  407. package/dist/profile/policy-manifest.js +0 -53
  408. package/dist/profile/policy-manifest.js.map +0 -1
  409. package/dist/profile/role-assembly.d.ts +0 -47
  410. package/dist/profile/role-assembly.d.ts.map +0 -1
  411. package/dist/profile/role-assembly.js +0 -31
  412. package/dist/profile/role-assembly.js.map +0 -1
  413. package/dist/profile/role-catalog.d.ts +0 -43
  414. package/dist/profile/role-catalog.d.ts.map +0 -1
  415. package/dist/profile/role-catalog.js +0 -132
  416. package/dist/profile/role-catalog.js.map +0 -1
  417. package/dist/profile/role-orchestrator.d.ts +0 -123
  418. package/dist/profile/role-orchestrator.d.ts.map +0 -1
  419. package/dist/profile/role-orchestrator.js +0 -195
  420. package/dist/profile/role-orchestrator.js.map +0 -1
  421. package/dist/profile/role-runner.d.ts +0 -99
  422. package/dist/profile/role-runner.d.ts.map +0 -1
  423. package/dist/profile/role-runner.js +0 -79
  424. package/dist/profile/role-runner.js.map +0 -1
  425. package/dist/profile/root-facade.d.ts +0 -36
  426. package/dist/profile/root-facade.d.ts.map +0 -1
  427. package/dist/profile/root-facade.js +0 -49
  428. package/dist/profile/root-facade.js.map +0 -1
  429. package/dist/profile/skill-discovery-wiring.d.ts +0 -58
  430. package/dist/profile/skill-discovery-wiring.d.ts.map +0 -1
  431. package/dist/profile/skill-discovery-wiring.js +0 -80
  432. package/dist/profile/skill-discovery-wiring.js.map +0 -1
  433. package/dist/profile/state-store.d.ts +0 -62
  434. package/dist/profile/state-store.d.ts.map +0 -1
  435. package/dist/profile/state-store.js +0 -144
  436. package/dist/profile/state-store.js.map +0 -1
  437. package/dist/profile/todo-plugin.d.ts +0 -37
  438. package/dist/profile/todo-plugin.d.ts.map +0 -1
  439. package/dist/profile/todo-plugin.js +0 -137
  440. package/dist/profile/todo-plugin.js.map +0 -1
  441. package/examples/extensions/mcp-stdio/index.d.ts +0 -64
  442. package/examples/extensions/mcp-stdio/index.d.ts.map +0 -1
  443. package/examples/extensions/mcp-stdio/index.js +0 -292
  444. package/examples/extensions/mcp-stdio/index.js.map +0 -1
  445. /package/{dist/plugins → bundled-plugins/mcp-http/dist}/mcp-http.d.ts +0 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,79 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.88.2] - 2026-10-05
6
+
7
+ ### Added
8
+
9
+ - Plugin on-demand activation (插件按需挂载与能力手册设计): capability manifests may declare `activation: "on-demand"`, a one-line `description`, and an optional `manual` path. On-demand plugins register their tools but keep them out of the initial active surface; the system prompt carries a mountable-capabilities card per still-deferred plugin, and the new built-in `capability_mount` tool activates the full tool set (next request) and returns the plugin's AI manual, while `capability_unmount` removes only the schema (runtime state follows the plugin's own idle timeout; session teardown clears all mounts). The framework never unmounts automatically — default `activation` stays `always`, so existing and third-party plugins are unaffected (user ruling 2026-10-05 "临时/常驻分级、渐进式按需加载"). First batch on-demand (7): browser-playwright, the four desktop plugins, subagent-delegate, and image-generation — each ships an AI `MANUAL.md` and joins the package `files` whitelist. Deployment semantics: activation reads the install-store copy, so manifest changes require a `plugin install` re-run. Known defect (logged, workaround verified): local-directory installs package the tree inconsistently and may include `tsconfig.json`, whose repo-relative `extends` breaks jiti loading in the store; installing the `npm pack` tarball (files whitelist) is clean. Covered by `test/capability-mount.test.ts` and verified against a real grok-4.7 session: the model mounted the capability itself before any browser call, and a non-browser session sent zero browser tool schemas.
10
+
11
+ ### Fixed
12
+
13
+ - desktop-windows-input: key and no-target type actions now post through the real keyboard queue (`keybd_event`): named keys and Ctrl/Alt/Shift combinations go as virtual-key events, no-target `type` is typed as VK_PACKET unicode events addressed at the current focus. Previously `key` sent WM_CHAR window messages to the target window (so `Enter` typed the letters R-E-T-U-R-N) and `WScript.SendKeys` handled the rest; neither reaches UIA-invisible surfaces. The native file-picker flow (coordinate click to open the dialog → foreground type the path → Enter) was verified end-to-end against a real Chrome dialog, which UIA cannot enumerate at all (both TreeWalker and FindAll top-level scans miss it; Win32 EnumWindows sees it).
14
+ - Custom `--session-id` values (non-UUID short ids like `mount-test-13`) could not delegate subagents: the subagent mailbox and session-lineage addressing gate rejected any id outside the UUID/`st:` shapes, so the whole delegation failed with "mailbox owner id is not a session id" (macCRM dogfood 2026-10-05, the model itself traced the cause to `session-lineage.ts`). Addressing safety only requires a single path-safe segment; `isAgentSessionId` now also accepts `[A-Za-z0-9][A-Za-z0-9._-]*` except `.`/`..`, and the shape tests cover the custom-id family.
15
+ - `--rebind-suite` now actually works on `--session` resume: the flag was collected in `main.ts` but dropped on the `createAgentSessionFromServices` hop, so the sdk suite-binding guard still rejected the resume (macCRM dogfood 2026-10-04, reproduced on Windows too). It is forwarded through `CreateAgentSessionFromServicesOptions` and covered by a regression test.
16
+ - `plugin install` failures surface the installer's real message instead of the bare "The plugin installer operation failed" code (e.g. a missing `dist/entry.js` in the source directory now says so).
17
+ - Suite `capabilities` declaring a bundled-channel plugin (e.g. `agent-forge.plugin.provider-failover`) no longer warn "has no installed active plugin": bundled plugins ship with the host and load without an install-store entry, and the warning now knows that.
18
+ - browser-playwright: internal in-page scripts (performance collection, localStorage get/set/clear) are now passed to `page.evaluate` as function objects. Passing the equivalent `() => ...` arrow *string* is silently wrong on real Playwright — the string is evaluated as an expression, the resulting function object serializes to `undefined`, which crashed `browser_performance` with "Cannot read properties of undefined (reading 'paints')" and made the three `browser_storage` localStorage actions no-ops (macCRM dogfood 2026-10-05, verified against real Chromium). `browser_evaluate` docs now steer multi-statement logic to IIFE strings.
19
+ - browser-playwright: `browser_setup` no longer crashes with "Cannot read properties of undefined (reading 'options')" — the capability extracted `runtime.setup` into a local before calling it, dropping `this` on the production class runtime (closure-shaped test mocks never read `this`, so 73 deterministic tests stayed green; first-install dogfood 2026-10-05). A class-shaped runtime regression test now pins the call path, and `browser_setup` was verified end-to-end on a fresh host: AI gets the structured guidance, self-installs Playwright + Chromium through `browser_setup`, and continues the page task in the same session.
20
+ - browser-playwright: browser-binary lookup and install now share one directory. `browser_setup` installs Chromium into `<agentDir>/browser-deps/browsers` (isolated via `PLAYWRIGHT_BROWSERS_PATH`), but launch silently looked in the shared OS cache, so a fresh host with no cache failed with the install guidance even right after a successful setup. `connect()` now defaults `PLAYWRIGHT_BROWSERS_PATH` to the same isolated directory (never overriding an explicit user setting), and the manual-install guidance command pins the same path.
21
+ - browser-playwright: `browser_drag` no longer times out on pages using `setPointerCapture` (the standard drag idiom): after `mouse.down` the tool now moves to the target by geometry (`boundingBox` + stepped `mouse.move`) instead of `locator.hover()`, whose hit-target check is defeated by pointer capture retargeting events to the source element. `browser_locator_action` `scroll` now parks the cursor over the target element before wheeling — the wheel delta used to land on whatever container the mouse happened to hover, so scrolling an explicit container silently scrolled something else. Found by a 43-assertion business-effect matrix against a purpose-built test page; both sequences are pinned in the mock tests.
22
+
23
+ ### Added
24
+
25
+ - Visual baseline roles join the factory suite (factory contents revision 7,
26
+ 2026-10-04 user ruling "术有专攻、角色隔离"): `design-proposer` and
27
+ `visual-reviewer` join the factory role seeds and the default
28
+ `associations.roles` of both builtin suites, so the design-proposal and
29
+ visual-review roles are visible out of the box (dispatch stays an explicit
30
+ `role` choice; role files are disk-only and seeds never overwrite user
31
+ edits). Workspaces provisioned at revision 6 receive the upgrade-proposal
32
+ diagnostic and adopt via `--suite-reset`. See
33
+ `docs/plans/视觉保底角色设计注记.md`.
34
+
35
+ - macOS desktop plugin profiles and packages: three new builtin plugin profiles (`desktop-observe-macos`, `desktop-control-macos`, `desktop-qa-macos`) resolve the two new self-contained plugin packages `plugins/desktop-macos-observe` (`agent-forge.plugin.desktop-macos-observe`, read-only `desktop_probe`/`desktop_session_open`/`desktop_observe`/`desktop_reobserve`/`desktop_session_stop` over a JXA osascript Accessibility driver, source `macos-ax`) and `plugins/desktop-macos-input` (`agent-forge.plugin.desktop-macos-input`, bounded `desktop_execute` with click-only coordinate targets, no replay, shared `needs_user` gate). Both declare `platform.os: ["macos"]`, report fail-closed `unsupported` with probe reason `accessibility-permission-required` without an Accessibility grant, and stay separate profiles from the Windows desktop trio (a profile with an installed-but-platform-unavailable plugin is blocked wholesale by the resolver). Real darwin behavior is contract-tested with an injected fake `spawnSync`; on a real macOS host (app-mac-host, macOS 15.7.5, 2026-10-04) the deterministic suites pass, the driver's app location was fixed from by-name `Application('systemEvents')` to by-bundle-id `Application('com.apple.systemevents')` (by-name resolution fails under SSH launchd sessions), and the real-host cases now `ctx.skip(reason)` instead of silently passing when the probe reports unavailable. With `/usr/bin/osascript` granted Accessibility (TCC judges the calling binary itself, not sshd), the full real-injection suite on a TextEdit fixture passed on app-mac-host: type, key(BACKSPACE), control click, coordinate click, and focus all really injected and were re-observed.
36
+
37
+ - Session metadata index (`session-index.json` in the agent dir): `SessionManager.listAll`'s default-layout branch is now served by a single-file JSON projection of session metadata (name/cwd/created/modified/message count/first message, no transcript text), written on first flush, rename, fork/branch, and selector deletion, and throttled (10s) for in-flight appends — cross-project resume listing is instant on the index-hit path instead of re-reading every session header. Index entries split relations (`file`/`dir`/`id`/`cwd`, reconciled against readdir) from content cache validated by a `file_mtime_ms` token: cache fields are trusted only while the file's stat mtime is unchanged, and refreshed by re-reading the file when it differs (write hooks are warm-up optimization, never correctness); project rows hold dir/cwd only with last-activity derived at serve time. The index is a projection, never the source of truth: missing, corrupt (JSON-level or field-level), or version-mismatched indexes rebuild from the existing full scan, so drift self-heals without user-visible errors. Accepted visible change (设计 `docs/design/会话索引.md` §5): All-scope search matches name/first message/id/cwd only — full-text search stays on the current-directory scope.
38
+
39
+ - `/clean-sessions [days]` interactive command (single text-command entry point, no keybinding; 设计 `docs/design/会话索引.md` §7): deletes session files untouched for N days (default 7, positive-integer argument, usage echoed on invalid input) to keep session storage from filling the disk. Scanning stats every `*.jsonl` under all project directories of the default sessions root including `_agents/` (trace/guard sidecars excluded; the index cache is never trusted for this disk-reclaim decision), then runs a two-phase flow — preview of hit count, total size, and cutoff time, confirmation through the host dialog, then deletion of each hit with its paired `*.trace.jsonl` and `*.jsonl.guard`, index-entry removal, and emptied project directories — reporting deleted count and freed bytes. Zero hits report directly without entering confirmation.
40
+
41
+ ### Changed
42
+
43
+ - TUI transcript silencing (D-083, 设计 `docs/design/终端输出模式设计.md` §3): interactive mode's transcript is now quiet by default — one assistant turn's tool calls merge into a single dim marker line (`⏺ bash` while running, `⏺ 3 个工具`/`⏺ 3 tools` when done; the sole tool keeps its name), with an error-colored failure count appended when any result was an error (`· 1 个失败`). Thinking blocks stay fully visible while streaming, then collapse to one dim line (`✻ 思考`/`✻ thinking`); `hideThinkingBlock` hides even that line. `Ctrl+O` (`app.tools.expand`, unchanged key) enters detail mode: per-tool full cards and full thinking text. Quiet rendering skips child tool components entirely (no kv arg lines, no result previews, no "(ctrl+o to expand)" meta hints); session records and tool results are untouched. Tool rendering contracts (`ToolExecutionComponent`, plugin `renderCall`/`renderResult`) are unchanged — only the transcript assembly (streaming and session-restore paths) groups per turn.
44
+ - TUI quiet transcript follow-up (D-083 增补): a failing turn's marker now carries the failing result's first output line (single line, error color) under the `· N failed` count, and tool-result images (desktop/browser screenshots) render under the marker in quiet mode — both are user-visible conclusions, so neither stays hidden behind a global ctrl+o expansion. Text cards stay hidden; plugin render contracts unchanged.
45
+ - Startup plugin bootstrap now realigns factory-listed first-party plugins automatically instead of warning (2026-10-04 install-and-use ruling, 设计 `插件独立分发与启动装配设计.md` §1 G5 例外 + §4.4): an active installation whose version misses the factory range (`^framework version`) is upgraded in place at startup — previously it only produced a `range_not_satisfied` diagnostic with a manual `plugin install`/`update --all` command, leaving every CLI upgrade one manual step away from a working tool surface. The `range_not_satisfied` diagnostic code, the `diagnosed` action status, and the `degraded` aggregate status are removed accordingly; aligned entries report `installed` with reason `range_aligned`, failures report `align_failed` with a "next startup retries automatically" diagnostic, and `AGENT_FORGE_PLUGIN_BOOTSTRAP=off` plus the offline posture gate still skip the whole run. Download failures retry 3 times with exponential backoff at the node wiring layer (the decision loop stays pure), and each install/align/failure now renders one stderr progress line (`{pluginId}: installed {version}` / install-failed with retry note, i18n'd) so a fresh install or upgrade shows live state instead of silence; fully-satisfied startups stay silent. `plugin install` of a factory plugin now prints "restart agent-forge to load it" instead of directing users to edit suite.json (factory plugins resolve through the suite's `builtin.*` capability aliases that default suites already declare).
46
+
47
+ ## [0.88.1] - 2026-10-04
48
+
49
+ ## [0.88.1] - 2026-10-04
50
+
51
+ ### Breaking Changes
52
+
53
+ - The embedded provider-failover plugin retired into the `plugins/provider-failover` plugin package (`@agent-forge/plugin-provider-failover`, id `agent-forge.plugin.provider-failover`, D-082 批 3b): it still assembles out of the box through the bundled distribution channel, now config-gated — the host injects the settings `failover` node as `{version: 1, failover: <node>}` through `capabilityPluginConfigs` only when the node exists, and a configured failover without the host `modelCatalog` service fails the plugin load loudly instead of degrading silently. Its source module (`src/core/extensions/provider-failover.ts`) is deleted; the removed export surface (`installProviderFailoverPlugin`, `parseProviderFailoverConfig`, `readProviderFailoverSettingsNode`, `resetProviderFailoverStateForTests`, `PROVIDER_FAILOVER_PLUGIN_ID`, `PROVIDER_FAILOVER_WRAPPER_NAME`, `PROVIDER_FAILOVER_STATE_ENTRY_TYPE`, and the `ProviderFailoverStateSnapshot`/`ProviderFailoverPreflightChecks`/`ProviderFailoverInstallOptions` types) was internal to the assembly and is simply gone from the source tree. Event names (`provider.failover.switched@1`/`recovered@1`/`probe.failed@1`) and the `provider.failover.state` entry type are unchanged, but the event `source` attribution changes from `agent-forge.provider-failover` to `agent-forge.plugin.provider-failover` — consumers filtering events by source id must match the new id. The three events also moved delivery channel: they are published through the public event bus (`api.publish`) instead of the internal lifecycle observe chain, so observers registered via `lifecycle.registerObserve` no longer receive them and must subscribe through the event bus instead; each published event additionally carries an optional `correlationId` (the chain id), with the event payload data unchanged.
54
+ - The four embedded default policy bootstrap installs retired into bundled first-party plugin packages (D-082 批 3): `installBootstrapRetryPolicy` (`agent-forge.bootstrap-retry` → `plugins/retry-policy`, id `agent-forge.plugin.retry-policy`), `installBootstrapOverflowPolicy` (`agent-forge.bootstrap-overflow` → `plugins/overflow-policy`, id `agent-forge.plugin.overflow-policy`), and `installBootstrapCompactionPolicy` + `installBootstrapBranchSummaryPolicy` (`agent-forge.bootstrap-compaction` / `agent-forge.bootstrap-branch-summary` → `plugins/compaction-policy`, id `agent-forge.plugin.compaction-policy`, one package carrying both the compaction decision and branch summarization). Their source modules (`src/core/extensions/bootstrap-{retry,overflow,compaction,branch-summary}-policy.ts`) are deleted; removed export surface: `BOOTSTRAP_RETRY_PLUGIN_ID`, `BOOTSTRAP_COMPACTION_PLUGIN_ID`, `installBootstrapRetryPolicy`, `installBootstrapCompactionPolicy` (the overflow/branch-summary ids and installers were never package-root exports and are simply gone from the source tree). `disabledBootstrapPlugins` no longer covers these four — disable them per plugin with the existing `disabledPluginIds` sdk option or the plugin disable state; the `DEFAULT_RETRY_POLICY_NAME`/`DEFAULT_COMPACTION_POLICY_NAME` (and internal `DEFAULT_OVERFLOW_POLICY_NAME`/`DEFAULT_BRANCH_SUMMARY_POLICY_NAME`) session defaults are retained, now defined host-side in `core/extensions`. The bundled distribution channel widens accordingly: the bundled default face is now the id set `BUNDLED_DEFAULT_PLUGIN_IDS` (coding-tools plus the four policy packages — noTools skips only the tool face, matching the embedded installs' unconditional assembly), and the bundle build ships the four packages under `bundled-plugins/<name>/`.
55
+ - The default agent-loop's repeated-tool-call guard and default run-loop strategy moved out of the embedded executor into the new `plugins/agent-loop-policy` package (`@agent-forge/plugin-agent-loop-policy`, id `agent-forge.plugin.agent-loop-policy`, D-082 批 3): they consume only the public `SessionAPI`/`LoggerAPI` faces, so they assemble through the bundled distribution channel and disable via `disabledPluginIds` — `disabledBootstrapPlugins: ["agent-forge.bootstrap-agent-loop"]` now removes only the four embedded event-dispatch links (beforeToolCall / afterToolCall / transformContext / prepareNextTurn), which stay host-side because they consume the session-closure wiring (`AgentLoopWiringV1`) no plugin channel can supply. Guard algorithm, thresholds, notice texts, custom types, and the registered link order (guard injection after the default context-strategy link, before third-party links) are unchanged; `DEFAULT_RUN_LOOP_STRATEGY_NAME` stays exported and the strategy's absence still degrades to the host's own continuation decision. Guard unit/registration tests live in the plugin package; host tests keep the four-chain and assembled-face coverage.
56
+
57
+ - The MCP HTTP transport moved out of the host package into the `plugins/mcp-http` plugin package (`@agent-forge/plugin-mcp-http`, D-082 批 2 / S7 MCP 批): the mcp-http block left the host package-root export surface. Removed exports: `createMcpHttpTransport` and the types `McpRequestOptions`, `McpHttpTransportEventV1`, `McpHttpTransportOptionsV1`, `McpHttpTransportV1` — import them from the plugin package instead (`createMcpHttpServerPlugin` and `McpHttpServerPluginApiV1` were never package-root exports; they retire from the host source tree together with the module file and live in the plugin package). The package is not an independent capability plugin (it ships no manifest files); it stays the factory library the suite MCP registration pool imports from generated url-configured pool entries, which now resolve the implementation dev-first from the repo-root `plugins/mcp-http/src/mcp-http.ts` working copy with the bundled `bundled-plugins/mcp-http/dist` snapshot as the published-layout fallback.
58
+ - Default coding tools moved out of the host package into the `plugins/coding-tools` plugin package (`@agent-forge/plugin-coding-tools`, D-082 批 1 / S6 工具批): the embedded `agent-forge.bootstrap-tools` plugin id is retired and the default tool face assembles through the bundled distribution channel (插件独立分发与启动装配设计 §4.9) over the same manifest/jiti channel every plugin uses. Removed export surface: the `createBashTool`/`createCodingTools`/`createEditTool`/`createFindTool`/`createGrepTool`/`createLsTool`/`createPowerShellTool`/`createReadOnlyTools`/`createReadTool`/`createWriteTool` factory family, the `ToolsOptions` type, and the per-tool `*ToolOptions`/`*Operations`/`*ToolDetails`/`*ToolInput` types of the seven relocated tools — import them from the plugin package instead (the bash operations face stays host-side: `BashOperations`/`BashSpawnContext`/`BashSpawnHook`/`createLocalBashOperations` remain exported; the internal `core/tools` aggregators `createToolDefinition`/`createTool`/`createCodingToolDefinitions`/`createReadOnlyToolDefinitions`/`createAllToolDefinitions`/`createAllTools` were never package-root exports and are simply gone from `core/tools`). `AgentSessionConfig.baseToolsOverride` and the sdk/session plumbing behind it are removed (pass `customTools` with `ToolDefinition`s); supplying custom tools to a readonly session keeps the retired "Readonly mode does not allow base tool overrides" rejection at the harness layer. `disabledBootstrapPlugins` no longer covers the coding tools (nor, since 批 3, the policy-family plugins — see below) — disable the coding tool face with the existing `disabledPluginIds` sdk option or the plugin disable state instead. The suite capability declaration `builtin.coding-tools` maps onto `agent-forge.plugin.coding-tools` (`BUILTIN_CAPABILITY_PACKAGE_IDS`).
59
+ - The multi-agent orchestration slices moved out of the host package into the `plugins/multi-agent` plugin package (`@agent-forge/plugin-multi-agent`, D-082 批 4): role catalog/runner/assembly/orchestrator, root/child agent facades, the transition-store Goal/Plan/Todo domain plugins, first-batch role slices, domain recovery, and the dependency/skill-discovery wiring plus the policy manifest builder. The package ships as a factory library only (no plugin manifest files — these are composition faces, not independently installable capabilities), and its export surface left the host package root: `createChildAgentFacade`, `wireProfileDependencies`, `buildRestartReport`, `recoverPlansForBranch`, `createFirstBatchRoleSlices`, `FIRST_BATCH_ROLES`, `createGoalPlugin`, `createPlanPlugin`, `createTodoPlugin`, `createPolicyManifestBuilder`, `assembleRoles`, `createRoleCatalog`, `validateRoleMetadataV1`, `createRoleOrchestrator`, `DEFAULT_ROLE_AGGREGATION_LIMIT_BYTES`, `createRoleRunner`, `runFirstBatchRole`, `createRootAgentFacade`, `createSkillDiscoveryWiring`, `createTransitionStore`, and their `*V1` companion types — import them from `@agent-forge/plugin-multi-agent` instead. The six host profile mechanisms stay: `identity`, `lock`, `profile-registry`, `profile-assembly`, `profile-migration`, `plugin-profiles` (suite-loader/sdk/main keep consuming them host-side).
60
+
61
+ ### Added
62
+
63
+ - `createLocalShellOperations` joins the package-root export surface: the bash operations extraction (D-082 批 1) separated the shell-operations layer from the relocated `bash` tool definition, and the shared operations face is now exported explicitly for host and plugin consumers.
64
+ - Bundled distribution channel (D-082 §4.9, S6 工具批): the host probes a `bundled-plugins/` root next to the package root (release form — the bundle build copies `plugins/coding-tools`' `plugin.json`, `agent-forge.json`, and built `dist/**` there as data files) plus the dev-repository working copy, and loads the discovered manifests through the same manifest channel as the install store, with precedence `suiteLocal → installed → bundled → discovered → explicit`; bundled candidates yield silently to higher-priority copies of the same plugin id and — since 批 3 — `noTools` skips only the tool face while `disabledPluginIds` applies to the whole layer. The new `capabilityPluginConfigs` sdk option (`Record<string, PluginConfig>`) merges per-plugin config overrides over the host-injected assembly facts (the session cwd plus settings-resolved read/bash options for coding-tools) with caller keys winning per top level; the plugin-side agent-dir config file still merges above everything. Host-declared config overrides are recorded per manifest path and replayed across session reload.
65
+ - Stream-function wrapper priority and the model-catalog host service (D-082 批 3b): `registerStreamFnWrapper` accepts `options.priority` (lower = outermost, default 0, stable order by priority then registration order; omitting options keeps the legacy first-registered-outermost semantics), and the provider-failover plugin registers at `-100` so the wrapper chain order no longer depends on plugin load order. The new optional `HostCapabilities.modelCatalog` service exposes the host's model catalog to capability plugins as a structural projection (`ModelCatalogV1`/`ModelCatalogModelViewV1`: provider, contextWindow, maxTokens, compat, thinkingLevelMap) with zero network and zero OAuth — the failover plugin's load preflight resolves chain models through it instead of private session internals.
66
+
67
+ ### Changed
68
+
69
+ - The suite MCP registration pool's url-configured entries now import the mcp-http implementation from the `plugins/mcp-http` package layout (dev source first, bundled dist fallback; see Breaking Changes), and the bundle build attaches `plugins/mcp-http/dist/**` to `bundled-plugins/mcp-http/` — dist only, no manifest files, so bundled discovery never loads it as a plugin (D-082 批 2).
70
+ - The default tool factories and their per-tool option types are no longer re-exported from the host package (see Breaking Changes); the host `core/tools` surface shrinks to the shared support face (tool definition contract and wrapper, tool_search, truncate, edit-diff, file-mutation-queue, output-accumulator, path-utils, render-utils, bash-operations, readme-path, `ToolName`/`allToolNames`). Interactive tool-call rendering now takes its renderers solely from the session registry's tool definitions — definitions missing from the registry fall back to the generic text rendering instead of a hardcoded built-in definition table.
71
+
72
+ ### Fixed
73
+
74
+ - `plugin update --all` no longer re-downloads factory plugins whose recorded version already satisfies the factory range: the batch loop issued `install <npmName>@^range` unconditionally, and acquisition downloads the package before its `already_installed` check, so satisfied entries were re-fetched every run and a single network blip misreported them as failed. An offline satisfiability pre-check now classifies hits as `already up to date` without any network request, reusing the npm range selector (`selectNpmPackageVersionV1`); misses still go through the normal install path, `latest`/absent ranges stay online-only, and non-factory bare `update` semantics are unchanged.
75
+ - npm registry source failures are now diagnosable end to end: `429` and `403` responses with `X-RateLimit-Remaining: 0` surface as a new source-level `rate_limited` error carrying the `Retry-After` seconds (isomorphic with the release source) and map through to the acquisition-layer `rate_limited`; transport failures keep the original error as `cause` on `request_failed` instead of discarding it; a body-read abort triggered by the module timeout now classifies as `request_timed_out` (reported as `download_failed` with a `request timed out` detail) instead of escaping as a raw AbortError, an externally cancelled read reports `cancelled`, and `response_too_large` maps to `budget_exceeded` matching the URL source. The 15s default timeout, retry posture, and configuration surface are unchanged.
76
+ - Plugin state visibility: `plugin state list` text output appends `disabled` to records with `enabled: false` (enabled rows stay unannotated), and enabling a record whose lifecycle is not `active` (e.g. `retained`) now states in both the text response and JSON data that the command only toggles the enabled flag and the runtime will not load the record, instead of implying activation.
77
+
5
78
  ## [0.88.0] - 2026-10-03
6
79
 
7
80
  ### Breaking Changes
@@ -0,0 +1,19 @@
1
+ {
2
+ "packageFormatVersion": 1,
3
+ "id": "agent-forge.plugin.agent-loop-policy",
4
+ "pluginVersion": "0.88.2",
5
+ "apiVersion": "1",
6
+ "minHostVersion": "0.88.0",
7
+ "platform": {
8
+ "os": [
9
+ "windows",
10
+ "macos",
11
+ "linux"
12
+ ],
13
+ "runtime": [
14
+ {
15
+ "name": "node"
16
+ }
17
+ ]
18
+ }
19
+ }
@@ -0,0 +1,28 @@
1
+ import type { CapabilityAPI } from "@agent-forge/plugin-sdk";
2
+ /**
3
+ * Default-export factory consumed by the host's manifest plugin loader
4
+ * (D-082 批 3:宿主内嵌 `bootstrap-agent-loop.ts` 的护栏与默认 strategy 装配
5
+ * 逐字迁出为本插件;四条事件分发链留在宿主内嵌,见宿主模块头注释)。
6
+ *
7
+ * The guard rides the public loop-hook chains like any other first-party
8
+ * link; disabling this plugin (`disabledPluginIds`) removes both of its links
9
+ * and the default continuation strategy. It answers with two levels
10
+ * (judgments can be wrong, so an irreversible stop is never the first
11
+ * response):
12
+ * - warn (third identical call): the shouldStopAfterTurn link votes false and
13
+ * the transformContext link injects a reminder into the next request view
14
+ * (the host's runLoop consumes transformContext after shouldStopAfterTurn
15
+ * and before the next model call); the user-facing warn notice is delivered
16
+ * through the public SessionAPI sendMessage face (persisted custom_message
17
+ * entry with live message_start/message_end rendering), plus a warn log
18
+ * through the public LoggerAPI.
19
+ * - stop (fifth identical call): the shouldStopAfterTurn link votes true; the
20
+ * stop notice rides agent_end newMessages, sendMessage persistence +
21
+ * rendering, and a warn log — all channels on.
22
+ * Absent host features (session/logger) degrade to the remaining channels
23
+ * instead of blocking the guard.
24
+ */
25
+ export default function createAgentLoopPolicyPluginEntry(api: CapabilityAPI): {
26
+ dispose: () => void;
27
+ };
28
+ //# sourceMappingURL=entry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry.d.ts","sourceRoot":"","sources":["../src/entry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAI7D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,OAAO,UAAU,gCAAgC,CAAC,GAAG,EAAE,aAAa,GAAG;IAAE,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,CA0CpG","sourcesContent":["import type { CapabilityAPI } from \"@agent-forge/plugin-sdk\";\nimport { createRepeatedToolCallStopPolicy } from \"./loop-guard.ts\";\nimport { DEFAULT_RUN_LOOP_STRATEGY_NAME, defaultRunLoopStrategy } from \"./run-loop-strategy.ts\";\n\n/**\n * Default-export factory consumed by the host's manifest plugin loader\n * (D-082 批 3:宿主内嵌 `bootstrap-agent-loop.ts` 的护栏与默认 strategy 装配\n * 逐字迁出为本插件;四条事件分发链留在宿主内嵌,见宿主模块头注释)。\n *\n * The guard rides the public loop-hook chains like any other first-party\n * link; disabling this plugin (`disabledPluginIds`) removes both of its links\n * and the default continuation strategy. It answers with two levels\n * (judgments can be wrong, so an irreversible stop is never the first\n * response):\n * - warn (third identical call): the shouldStopAfterTurn link votes false and\n * the transformContext link injects a reminder into the next request view\n * (the host's runLoop consumes transformContext after shouldStopAfterTurn\n * and before the next model call); the user-facing warn notice is delivered\n * through the public SessionAPI sendMessage face (persisted custom_message\n * entry with live message_start/message_end rendering), plus a warn log\n * through the public LoggerAPI.\n * - stop (fifth identical call): the shouldStopAfterTurn link votes true; the\n * stop notice rides agent_end newMessages, sendMessage persistence +\n * rendering, and a warn log — all channels on.\n * Absent host features (session/logger) degrade to the remaining channels\n * instead of blocking the guard.\n */\nexport default function createAgentLoopPolicyPluginEntry(api: CapabilityAPI): { dispose: () => void } {\n\tconst loopGuard = createRepeatedToolCallStopPolicy({\n\t\tdeliverWarn: (notice) => {\n\t\t\tvoid api.session?.sendMessage?.(notice, { triggerTurn: false });\n\t\t},\n\t\tonWarn: (info) => {\n\t\t\tapi.logger?.warn(\"Loop guard warned the model\", {\n\t\t\t\ttool: info.toolName,\n\t\t\t\trepeats: info.warnThreshold,\n\t\t\t\targsSummary: info.argsSummary,\n\t\t\t});\n\t\t},\n\t\tdeliverNotice: (notice) => {\n\t\t\tvoid api.session?.sendMessage?.(notice, { triggerTurn: false });\n\t\t},\n\t\tonStop: (info) => {\n\t\t\tapi.logger?.warn(\"Loop guard stopped the turn\", {\n\t\t\t\ttool: info.toolName,\n\t\t\t\trepeats: info.stopThreshold,\n\t\t\t\targsSummary: info.argsSummary,\n\t\t\t});\n\t\t},\n\t});\n\tconst stopLink = api.registerLoopHook(\"shouldStopAfterTurn\", loopGuard.shouldStopAfterTurn);\n\t// Registered after the default context-strategy link (the host's embedded\n\t// executor registers first at session construction), so the reminder is\n\t// appended to the final post-strategy request view (survives any strategy\n\t// pruning) at its tail.\n\tconst warnLink = api.registerLoopHook(\"transformContext\", loopGuard.transformContext);\n\t// The default continuation strategy reproduces the host's own post-run\n\t// decision byte for byte; a replacement strategy overrides the\n\t// continue/stop call through registerRunLoopStrategy.\n\tconst strategyRegistration = api.registerRunLoopStrategy(DEFAULT_RUN_LOOP_STRATEGY_NAME, defaultRunLoopStrategy);\n\treturn {\n\t\tdispose: () => {\n\t\t\t// Registration disposal in the capability runtime is synchronous;\n\t\t\t// void consumes the declared Promise possibility of the contract.\n\t\t\tvoid strategyRegistration.dispose();\n\t\t\tvoid warnLink.dispose();\n\t\t\tvoid stopLink.dispose();\n\t\t},\n\t};\n}\n"]}
@@ -0,0 +1,69 @@
1
+ import { createRepeatedToolCallStopPolicy } from "./loop-guard.js";
2
+ import { DEFAULT_RUN_LOOP_STRATEGY_NAME, defaultRunLoopStrategy } from "./run-loop-strategy.js";
3
+ /**
4
+ * Default-export factory consumed by the host's manifest plugin loader
5
+ * (D-082 批 3:宿主内嵌 `bootstrap-agent-loop.ts` 的护栏与默认 strategy 装配
6
+ * 逐字迁出为本插件;四条事件分发链留在宿主内嵌,见宿主模块头注释)。
7
+ *
8
+ * The guard rides the public loop-hook chains like any other first-party
9
+ * link; disabling this plugin (`disabledPluginIds`) removes both of its links
10
+ * and the default continuation strategy. It answers with two levels
11
+ * (judgments can be wrong, so an irreversible stop is never the first
12
+ * response):
13
+ * - warn (third identical call): the shouldStopAfterTurn link votes false and
14
+ * the transformContext link injects a reminder into the next request view
15
+ * (the host's runLoop consumes transformContext after shouldStopAfterTurn
16
+ * and before the next model call); the user-facing warn notice is delivered
17
+ * through the public SessionAPI sendMessage face (persisted custom_message
18
+ * entry with live message_start/message_end rendering), plus a warn log
19
+ * through the public LoggerAPI.
20
+ * - stop (fifth identical call): the shouldStopAfterTurn link votes true; the
21
+ * stop notice rides agent_end newMessages, sendMessage persistence +
22
+ * rendering, and a warn log — all channels on.
23
+ * Absent host features (session/logger) degrade to the remaining channels
24
+ * instead of blocking the guard.
25
+ */
26
+ export default function createAgentLoopPolicyPluginEntry(api) {
27
+ const loopGuard = createRepeatedToolCallStopPolicy({
28
+ deliverWarn: (notice) => {
29
+ void api.session?.sendMessage?.(notice, { triggerTurn: false });
30
+ },
31
+ onWarn: (info) => {
32
+ api.logger?.warn("Loop guard warned the model", {
33
+ tool: info.toolName,
34
+ repeats: info.warnThreshold,
35
+ argsSummary: info.argsSummary,
36
+ });
37
+ },
38
+ deliverNotice: (notice) => {
39
+ void api.session?.sendMessage?.(notice, { triggerTurn: false });
40
+ },
41
+ onStop: (info) => {
42
+ api.logger?.warn("Loop guard stopped the turn", {
43
+ tool: info.toolName,
44
+ repeats: info.stopThreshold,
45
+ argsSummary: info.argsSummary,
46
+ });
47
+ },
48
+ });
49
+ const stopLink = api.registerLoopHook("shouldStopAfterTurn", loopGuard.shouldStopAfterTurn);
50
+ // Registered after the default context-strategy link (the host's embedded
51
+ // executor registers first at session construction), so the reminder is
52
+ // appended to the final post-strategy request view (survives any strategy
53
+ // pruning) at its tail.
54
+ const warnLink = api.registerLoopHook("transformContext", loopGuard.transformContext);
55
+ // The default continuation strategy reproduces the host's own post-run
56
+ // decision byte for byte; a replacement strategy overrides the
57
+ // continue/stop call through registerRunLoopStrategy.
58
+ const strategyRegistration = api.registerRunLoopStrategy(DEFAULT_RUN_LOOP_STRATEGY_NAME, defaultRunLoopStrategy);
59
+ return {
60
+ dispose: () => {
61
+ // Registration disposal in the capability runtime is synchronous;
62
+ // void consumes the declared Promise possibility of the contract.
63
+ void strategyRegistration.dispose();
64
+ void warnLink.dispose();
65
+ void stopLink.dispose();
66
+ },
67
+ };
68
+ }
69
+ //# sourceMappingURL=entry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry.js","sourceRoot":"","sources":["../src/entry.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gCAAgC,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,8BAA8B,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAEhG;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,OAAO,UAAU,gCAAgC,CAAC,GAAkB,EAA2B;IACrG,MAAM,SAAS,GAAG,gCAAgC,CAAC;QAClD,WAAW,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC;YACxB,KAAK,GAAG,CAAC,OAAO,EAAE,WAAW,EAAE,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;QAAA,CAChE;QACD,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC;YACjB,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,6BAA6B,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,QAAQ;gBACnB,OAAO,EAAE,IAAI,CAAC,aAAa;gBAC3B,WAAW,EAAE,IAAI,CAAC,WAAW;aAC7B,CAAC,CAAC;QAAA,CACH;QACD,aAAa,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC;YAC1B,KAAK,GAAG,CAAC,OAAO,EAAE,WAAW,EAAE,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;QAAA,CAChE;QACD,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC;YACjB,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,6BAA6B,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,QAAQ;gBACnB,OAAO,EAAE,IAAI,CAAC,aAAa;gBAC3B,WAAW,EAAE,IAAI,CAAC,WAAW;aAC7B,CAAC,CAAC;QAAA,CACH;KACD,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,GAAG,CAAC,gBAAgB,CAAC,qBAAqB,EAAE,SAAS,CAAC,mBAAmB,CAAC,CAAC;IAC5F,0EAA0E;IAC1E,wEAAwE;IACxE,0EAA0E;IAC1E,wBAAwB;IACxB,MAAM,QAAQ,GAAG,GAAG,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,SAAS,CAAC,gBAAgB,CAAC,CAAC;IACtF,uEAAuE;IACvE,+DAA+D;IAC/D,sDAAsD;IACtD,MAAM,oBAAoB,GAAG,GAAG,CAAC,uBAAuB,CAAC,8BAA8B,EAAE,sBAAsB,CAAC,CAAC;IACjH,OAAO;QACN,OAAO,EAAE,GAAG,EAAE,CAAC;YACd,kEAAkE;YAClE,kEAAkE;YAClE,KAAK,oBAAoB,CAAC,OAAO,EAAE,CAAC;YACpC,KAAK,QAAQ,CAAC,OAAO,EAAE,CAAC;YACxB,KAAK,QAAQ,CAAC,OAAO,EAAE,CAAC;QAAA,CACxB;KACD,CAAC;AAAA,CACF","sourcesContent":["import type { CapabilityAPI } from \"@agent-forge/plugin-sdk\";\nimport { createRepeatedToolCallStopPolicy } from \"./loop-guard.ts\";\nimport { DEFAULT_RUN_LOOP_STRATEGY_NAME, defaultRunLoopStrategy } from \"./run-loop-strategy.ts\";\n\n/**\n * Default-export factory consumed by the host's manifest plugin loader\n * (D-082 批 3:宿主内嵌 `bootstrap-agent-loop.ts` 的护栏与默认 strategy 装配\n * 逐字迁出为本插件;四条事件分发链留在宿主内嵌,见宿主模块头注释)。\n *\n * The guard rides the public loop-hook chains like any other first-party\n * link; disabling this plugin (`disabledPluginIds`) removes both of its links\n * and the default continuation strategy. It answers with two levels\n * (judgments can be wrong, so an irreversible stop is never the first\n * response):\n * - warn (third identical call): the shouldStopAfterTurn link votes false and\n * the transformContext link injects a reminder into the next request view\n * (the host's runLoop consumes transformContext after shouldStopAfterTurn\n * and before the next model call); the user-facing warn notice is delivered\n * through the public SessionAPI sendMessage face (persisted custom_message\n * entry with live message_start/message_end rendering), plus a warn log\n * through the public LoggerAPI.\n * - stop (fifth identical call): the shouldStopAfterTurn link votes true; the\n * stop notice rides agent_end newMessages, sendMessage persistence +\n * rendering, and a warn log — all channels on.\n * Absent host features (session/logger) degrade to the remaining channels\n * instead of blocking the guard.\n */\nexport default function createAgentLoopPolicyPluginEntry(api: CapabilityAPI): { dispose: () => void } {\n\tconst loopGuard = createRepeatedToolCallStopPolicy({\n\t\tdeliverWarn: (notice) => {\n\t\t\tvoid api.session?.sendMessage?.(notice, { triggerTurn: false });\n\t\t},\n\t\tonWarn: (info) => {\n\t\t\tapi.logger?.warn(\"Loop guard warned the model\", {\n\t\t\t\ttool: info.toolName,\n\t\t\t\trepeats: info.warnThreshold,\n\t\t\t\targsSummary: info.argsSummary,\n\t\t\t});\n\t\t},\n\t\tdeliverNotice: (notice) => {\n\t\t\tvoid api.session?.sendMessage?.(notice, { triggerTurn: false });\n\t\t},\n\t\tonStop: (info) => {\n\t\t\tapi.logger?.warn(\"Loop guard stopped the turn\", {\n\t\t\t\ttool: info.toolName,\n\t\t\t\trepeats: info.stopThreshold,\n\t\t\t\targsSummary: info.argsSummary,\n\t\t\t});\n\t\t},\n\t});\n\tconst stopLink = api.registerLoopHook(\"shouldStopAfterTurn\", loopGuard.shouldStopAfterTurn);\n\t// Registered after the default context-strategy link (the host's embedded\n\t// executor registers first at session construction), so the reminder is\n\t// appended to the final post-strategy request view (survives any strategy\n\t// pruning) at its tail.\n\tconst warnLink = api.registerLoopHook(\"transformContext\", loopGuard.transformContext);\n\t// The default continuation strategy reproduces the host's own post-run\n\t// decision byte for byte; a replacement strategy overrides the\n\t// continue/stop call through registerRunLoopStrategy.\n\tconst strategyRegistration = api.registerRunLoopStrategy(DEFAULT_RUN_LOOP_STRATEGY_NAME, defaultRunLoopStrategy);\n\treturn {\n\t\tdispose: () => {\n\t\t\t// Registration disposal in the capability runtime is synchronous;\n\t\t\t// void consumes the declared Promise possibility of the contract.\n\t\t\tvoid strategyRegistration.dispose();\n\t\t\tvoid warnLink.dispose();\n\t\t\tvoid stopLink.dispose();\n\t\t},\n\t};\n}\n"]}
@@ -0,0 +1,199 @@
1
+ /**
2
+ * 默认重复工具调用护栏(主对话循环护栏,两级响应)。逐字迁移自宿主内嵌
3
+ * `bootstrap-agent-loop.ts` 的护栏切片(D-082 批 3:迁出为
4
+ * `agent-forge.plugin.agent-loop-policy` 插件包,算法、阈值与消息文本保持不变)。
5
+ *
6
+ * 每个完成的回合从 assistant 消息中按序取出工具调用,签名(工具名 + 键序参数
7
+ * + 本轮结果哈希,结果按 toolCallId 对应)追加进滑动窗口并裁剪到 windowSize;
8
+ * 然后按窗口尾部连续相同签名段(含同一回合内多次相同调用)做两级响应:
9
+ *
10
+ * - 第一级(达到 warnThreshold,缺省 3):不停机,改为提醒——内部标记
11
+ * pendingWarn,由 {@link createRepeatedToolCallStopPolicy} 返回的
12
+ * transformContext 链路在下一轮请求前把提醒消息追加到请求视图尾部;同时把
13
+ * 用户可见提醒经 deliverWarn 投递、事实经 onWarn 记日志。同一连续重复段只
14
+ * 提醒一次(warnedForRun 闩);连续段断开(模型改变行为)即复位。
15
+ * - 第二级(达到 stopThreshold,缺省 5):请求停机——先向 stop 上下文的
16
+ * newMessages 追加一条用户可见的停机消息并交给 deliverNotice(禁止静默停
17
+ * 机),再经 onStop 记日志。判据不可能完美,因此不可逆停机不是第一响应。
18
+ *
19
+ * 同参不同果(合法轮询,如等待外部状态就绪)不计重复:结果要素是全量哈希,
20
+ * 任何字节差异(包括 >200 字符长结果仅尾部变化)都产生不同签名;无文本结果
21
+ * 退化为两要素(见 {@link toolResultHash} 局限声明)。无工具调用或结果缺席的
22
+ * 轮次不进窗口。
23
+ */
24
+ /** 结构化镜像 `@agent-forge/ai` 的 TextContent(内核类型不跨入插件面)。 */
25
+ export interface TextContent {
26
+ type: "text";
27
+ text: string;
28
+ }
29
+ /** 结构化镜像 `@agent-forge/ai` 的 ImageContent(内核类型不跨入插件面)。 */
30
+ export interface ImageContent {
31
+ type: "image";
32
+ data: string;
33
+ mimeType: string;
34
+ }
35
+ /**
36
+ * 结构化镜像宿主 `core/messages.ts` 的 CustomMessage(D-082 批 3):护栏的三种
37
+ * 通知消息与宿主自定义消息同形,经 `SessionAPI.sendMessage` 投递后由宿主按
38
+ * role:"custom" 持久化与渲染。字段与宿主逐字一致,漂移由宿主 e2e(通知持久化
39
+ * 与渲染事件断言)拦截。
40
+ */
41
+ export interface CustomMessage<T = unknown> {
42
+ role: "custom";
43
+ customType: string;
44
+ content: string | (TextContent | ImageContent)[];
45
+ display: boolean;
46
+ details?: T;
47
+ timestamp: number;
48
+ }
49
+ /** 结构化镜像 `@agent-forge/ai` 的 ToolCall(护栏只消费 id/name/arguments)。 */
50
+ export interface ToolCall {
51
+ type: "toolCall";
52
+ id: string;
53
+ name: string;
54
+ arguments: Record<string, unknown>;
55
+ }
56
+ /** 结构化镜像 `@agent-forge/ai` 的 ToolResultMessage(护栏只消费 content/isError)。 */
57
+ export interface ToolResultMessage {
58
+ role: "toolResult";
59
+ toolCallId: string;
60
+ toolName: string;
61
+ content: (TextContent | ImageContent)[];
62
+ isError: boolean;
63
+ timestamp: number;
64
+ }
65
+ /**
66
+ * 结构化镜像 `@agent-forge/agent-core` 的 ShouldStopAfterTurnContext(内核类型
67
+ * 不跨入 plugin-sdk,D-075 S2;插件只消费 message/toolResults/newMessages)。
68
+ * 宿主把同一个运行时对象交给内核回调与本插件链路,字段读取语义不变。
69
+ */
70
+ export interface ShouldStopAfterTurnContext {
71
+ /** The assistant message that completed the turn. */
72
+ message: {
73
+ content: readonly (ToolCall | {
74
+ type: string;
75
+ })[];
76
+ };
77
+ /** Tool result messages passed to the preceding `turn_end` event. */
78
+ toolResults: readonly ToolResultMessage[];
79
+ /** Current agent context after the turn (consumed by the host, not the guard). */
80
+ context: unknown;
81
+ /** Messages this loop invocation returns if it exits at this point. */
82
+ newMessages: CustomMessage[];
83
+ }
84
+ /** 滑动窗口大小:护栏只回看最近 N 个工具调用签名(跨回合累计)。 */
85
+ export declare const REPEATED_TOOL_CALL_WINDOW_SIZE = 6;
86
+ /** 提醒阈值:窗口尾部连续相同签名达到该次数时提醒模型(不停机,两级响应第一级)。 */
87
+ export declare const REPEATED_TOOL_CALL_WARN_THRESHOLD = 3;
88
+ /** 停机阈值:提醒后仍连续相同达到该次数才请求停机(两级响应第二级兜底)。 */
89
+ export declare const REPEATED_TOOL_CALL_STOP_THRESHOLD = 5;
90
+ /** 停机提示消息的 customType(用户可见面,随 agent_end 的 messages 带出)。 */
91
+ export declare const REPEATED_TOOL_CALL_STOP_CUSTOM_TYPE = "loop_guard_stop";
92
+ /** 提醒消息的 customType(用户可见面经 sendMessage 持久化+渲染;模型面注入复用同一标记)。 */
93
+ export declare const REPEATED_TOOL_CALL_WARN_CUSTOM_TYPE = "loop_guard_warn";
94
+ /** 提示消息中参数串的最大长度,超出截断(只影响提示文本,不影响检测签名)。 */
95
+ export declare const REPEATED_TOOL_CALL_NOTICE_MAX_ARGS_CHARS = 200;
96
+ /** {@link createRepeatedToolCallStopPolicy} 的窗口与两级阈值参数(缺省用上方命名常量)。 */
97
+ export interface RepeatedToolCallStopPolicyOptions {
98
+ /** 滑动窗口大小,缺省 {@link REPEATED_TOOL_CALL_WINDOW_SIZE}。 */
99
+ windowSize?: number;
100
+ /** 提醒阈值(第一级,不停机),缺省 {@link REPEATED_TOOL_CALL_WARN_THRESHOLD}。 */
101
+ warnThreshold?: number;
102
+ /** 停机阈值(第二级兜底),缺省 {@link REPEATED_TOOL_CALL_STOP_THRESHOLD}。显式设为不大于提醒阈值时停机优先。 */
103
+ stopThreshold?: number;
104
+ /**
105
+ * 提醒时的日志面回调(与 {@link onStop} 同纪律:info 只携带脱敏后的事实——
106
+ * 工具名、截断参数摘要、提醒阈值,不含完整工具参数)。只在第一级实际提醒的
107
+ * 回合调用一次;缺省不接 = 行为不变。
108
+ */
109
+ onWarn?: (info: RepeatedToolCallWarnInfo) => void;
110
+ /**
111
+ * 停机时的日志面回调(D-072 治理纪律 6(a):用户可见 + 日志可见双通道)。
112
+ * 只在策略实际请求停机的回合调用一次;缺省不接 = 行为不变。info 只携带
113
+ * 脱敏后的事实(工具名、截断参数摘要、阈值),不含完整工具参数。
114
+ */
115
+ onStop?: (info: RepeatedToolCallStopInfo) => void;
116
+ /**
117
+ * 提醒通知投递缝:策略把提醒消息交给宿主选定的公共面。默认安装把它接到
118
+ * `SessionAPI.sendMessage`(持久化 + message_start 实时渲染);缺席时提醒
119
+ * 仍经 transformContext 注入模型请求(模型面不依赖该缝)。
120
+ */
121
+ deliverWarn?: (notice: CustomMessage) => void;
122
+ /**
123
+ * 停机通知投递缝:策略把停机提示消息交给宿主选定的公共面。默认安装把它接到
124
+ * `SessionAPI.sendMessage`(运行中排队、run 收尾 flush 落为 custom_message
125
+ * 条目——持久化 + message_start 实时渲染);缺席时停机事实仅随 agent_end 的
126
+ * newMessages 带出(行为不变)。
127
+ */
128
+ deliverNotice?: (notice: CustomMessage) => void;
129
+ }
130
+ /** 提醒事实(脱敏):{@link RepeatedToolCallStopPolicyOptions.onWarn} 的载荷。 */
131
+ export interface RepeatedToolCallWarnInfo {
132
+ /** 触发提醒的最后一个工具名。 */
133
+ toolName: string;
134
+ /** 截断后的参数稳定序列化摘要(复用 {@link REPEATED_TOOL_CALL_NOTICE_MAX_ARGS_CHARS})。 */
135
+ argsSummary: string;
136
+ /** 达到的连续重复提醒阈值。 */
137
+ warnThreshold: number;
138
+ }
139
+ /** 停机事实(脱敏):{@link RepeatedToolCallStopPolicyOptions.onStop} 的载荷。 */
140
+ export interface RepeatedToolCallStopInfo {
141
+ /** 触发停机的最后一个工具名。 */
142
+ toolName: string;
143
+ /** 截断后的参数稳定序列化摘要(复用 {@link REPEATED_TOOL_CALL_NOTICE_MAX_ARGS_CHARS})。 */
144
+ argsSummary: string;
145
+ /** 达到的连续重复停机阈值。 */
146
+ stopThreshold: number;
147
+ }
148
+ /**
149
+ * 参数稳定字符串化:对象键递归排序后逐层拼接(数组保持顺序),循环引用输出
150
+ * 固定占位。只用于签名比较与提示文本,不是通用 JSON 序列化器。
151
+ */
152
+ export declare function stableSerializeValue(value: unknown, seen?: WeakSet<object>): string;
153
+ /**
154
+ * 工具结果哈希(签名第三要素):拼接结果的 text 内容后做全量 SHA-256(十六进制),
155
+ * isError 一并纳入(同参同果且同错误状态才计重复)。任何字节差异都产生不同哈希,
156
+ * 因此长结果(前缀稳定、尾部变化)的合法轮询不会被误判成"同果"——签名不受任何
157
+ * 截断影响。无文本结果(纯图像等)与结果缺席都返回空串占位:签名退化为两要素
158
+ * (工具名 + 参数),这是已知局限——无文本的同参结果彼此不可区分。
159
+ * 调用与结果按 toolCallId 对应,正常流程中每个调用都有结果;无结果返回空串。
160
+ */
161
+ export declare function toolResultHash(result: ToolResultMessage | undefined): string;
162
+ /** 工具调用签名:工具名 + 参数稳定字符串化 + 结果哈希。 */
163
+ export declare function repeatedToolCallSignature(toolName: string, args: unknown, resultHash: string): string;
164
+ /** 停机提示消息:随停机回合的 newMessages 带出(agent_end 可见),并经 deliverNotice 投递到宿主公共面。 */
165
+ export declare function createRepeatedToolCallStopNotice(toolName: string, argsText: string, stopThreshold: number): CustomMessage;
166
+ /**
167
+ * 提醒通知消息(用户可见面,loop_guard_warn):经 deliverWarn 投递(默认安装接
168
+ * `SessionAPI.sendMessage`,持久化 + 实时渲染),与停机通知(loop_guard_stop)
169
+ * 的 customType 区分。提醒不进入 newMessages——模型面提醒由 transformContext
170
+ * 注入承担,用户面提醒由本消息的持久化+渲染承担。
171
+ */
172
+ export declare function createRepeatedToolCallWarnNotice(toolName: string, argsText: string, warnThreshold: number): CustomMessage;
173
+ /**
174
+ * 模型面提醒消息(transformContext 注入用):display:false 的 custom 消息,
175
+ * 经宿主 convertToLlm 转为 user 文本进入下一次模型请求。只存在于该次请求视图
176
+ * (不写 context.messages、不进 newMessages,故不持久化);customType 复用
177
+ * loop_guard_warn 标记来源。
178
+ */
179
+ export declare function createRepeatedToolCallWarnReminder(warnThreshold: number): CustomMessage;
180
+ /** {@link createRepeatedToolCallStopPolicy} 返回的两条链路(共享同一滑动窗口与两级状态)。 */
181
+ export interface RepeatedToolCallGuard {
182
+ /**
183
+ * "shouldStopAfterTurn" 链路:两级判定的决策面(返回 true 即请求停机)。
184
+ */
185
+ shouldStopAfterTurn: (context: ShouldStopAfterTurnContext) => boolean;
186
+ /**
187
+ * "transformContext" 链路:提醒注入面。有待注入提醒时返回追加了提醒消息的
188
+ * 新数组(进入下一次模型请求视图),否则返回 undefined(保留输入)。
189
+ */
190
+ transformContext: (messages: readonly unknown[], signal?: AbortSignal) => Promise<readonly unknown[] | undefined>;
191
+ }
192
+ /**
193
+ * 默认重复工具调用护栏工厂(两级响应)。算法与阈值逐字迁移自宿主内嵌实现的
194
+ * 同名工厂;两条链路由 `entry.ts` 经公共扩展面 `api.registerLoopHook` 注册为
195
+ * 默认链路(transformContext 注入链注册在默认上下文策略链之后,提醒落到最终
196
+ * 请求视图尾部);`disabledPluginIds` 跳过本插件时均不注册,护栏随之关闭。
197
+ */
198
+ export declare function createRepeatedToolCallStopPolicy(options?: RepeatedToolCallStopPolicyOptions): RepeatedToolCallGuard;
199
+ //# sourceMappingURL=loop-guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop-guard.d.ts","sourceRoot":"","sources":["../src/loop-guard.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,+FAAyD;AACzD,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACb;AAED,gGAA0D;AAC1D,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,OAAO;IACzC,IAAI,EAAE,QAAQ,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,GAAG,CAAC,WAAW,GAAG,YAAY,CAAC,EAAE,CAAC;IACjD,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,CAAC,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,+FAAmE;AACnE,MAAM,WAAW,QAAQ;IACxB,IAAI,EAAE,UAAU,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,sGAA0E;AAC1E,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,YAAY,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,CAAC,WAAW,GAAG,YAAY,CAAC,EAAE,CAAC;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,0BAA0B;IAC1C,qDAAqD;IACrD,OAAO,EAAE;QAAE,OAAO,EAAE,SAAS,CAAC,QAAQ,GAAG;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC,EAAE,CAAA;KAAE,CAAC;IAC/D,qEAAqE;IACrE,WAAW,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC1C,kFAAkF;IAClF,OAAO,EAAE,OAAO,CAAC;IACjB,uEAAuE;IACvE,WAAW,EAAE,aAAa,EAAE,CAAC;CAC7B;AAED,iGAAuC;AACvC,eAAO,MAAM,8BAA8B,IAAI,CAAC;AAChD,4HAA8C;AAC9C,eAAO,MAAM,iCAAiC,IAAI,CAAC;AACnD,gHAA0C;AAC1C,eAAO,MAAM,iCAAiC,IAAI,CAAC;AACnD,mGAA2D;AAC3D,eAAO,MAAM,mCAAmC,oBAAoB,CAAC;AACrE,6HAA+D;AAC/D,eAAO,MAAM,mCAAmC,oBAAoB,CAAC;AACrE,mHAA2C;AAC3C,eAAO,MAAM,wCAAwC,MAAM,CAAC;AAE5D,kHAAsE;AACtE,MAAM,WAAW,iCAAiC;IACjD,4EAAwD;IACxD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oGAAkE;IAClE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iJAAiF;IACjF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,wBAAwB,KAAK,IAAI,CAAC;IAClD;;;;OAIG;IACH,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,wBAAwB,KAAK,IAAI,CAAC;IAClD;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;IAC9C;;;;;OAKG;IACH,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;CAChD;AAED,+FAAqE;AACrE,MAAM,WAAW,wBAAwB;IACxC,8CAAoB;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,8GAA0E;IAC1E,WAAW,EAAE,MAAM,CAAC;IACpB,2CAAmB;IACnB,aAAa,EAAE,MAAM,CAAC;CACtB;AAED,+FAAqE;AACrE,MAAM,WAAW,wBAAwB;IACxC,8CAAoB;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,8GAA0E;IAC1E,WAAW,EAAE,MAAM,CAAC;IACpB,2CAAmB;IACnB,aAAa,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,GAAE,OAAO,CAAC,MAAM,CAAiB,GAAG,MAAM,CAiClG;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,iBAAiB,GAAG,SAAS,GAAG,MAAM,CAQ5E;AAED,kFAAoC;AACpC,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAErG;AASD,0IAA4E;AAC5E,wBAAgB,gCAAgC,CAC/C,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,GACnB,aAAa,CASf;AAED;;;;;GAKG;AACH,wBAAgB,gCAAgC,CAC/C,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,GACnB,aAAa,CASf;AAED;;;;;GAKG;AACH,wBAAgB,kCAAkC,CAAC,aAAa,EAAE,MAAM,GAAG,aAAa,CAQvF;AAED,qHAAuE;AACvE,MAAM,WAAW,qBAAqB;IACrC;;OAEG;IACH,mBAAmB,EAAE,CAAC,OAAO,EAAE,0BAA0B,KAAK,OAAO,CAAC;IACtE;;;OAGG;IACH,gBAAgB,EAAE,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,SAAS,OAAO,EAAE,GAAG,SAAS,CAAC,CAAC;CAClH;AAED;;;;;GAKG;AACH,wBAAgB,gCAAgC,CAC/C,OAAO,GAAE,iCAAsC,GAC7C,qBAAqB,CAgFvB","sourcesContent":["import { createHash } from \"node:crypto\";\n\n/**\n * 默认重复工具调用护栏(主对话循环护栏,两级响应)。逐字迁移自宿主内嵌\n * `bootstrap-agent-loop.ts` 的护栏切片(D-082 批 3:迁出为\n * `agent-forge.plugin.agent-loop-policy` 插件包,算法、阈值与消息文本保持不变)。\n *\n * 每个完成的回合从 assistant 消息中按序取出工具调用,签名(工具名 + 键序参数\n * + 本轮结果哈希,结果按 toolCallId 对应)追加进滑动窗口并裁剪到 windowSize;\n * 然后按窗口尾部连续相同签名段(含同一回合内多次相同调用)做两级响应:\n *\n * - 第一级(达到 warnThreshold,缺省 3):不停机,改为提醒——内部标记\n * pendingWarn,由 {@link createRepeatedToolCallStopPolicy} 返回的\n * transformContext 链路在下一轮请求前把提醒消息追加到请求视图尾部;同时把\n * 用户可见提醒经 deliverWarn 投递、事实经 onWarn 记日志。同一连续重复段只\n * 提醒一次(warnedForRun 闩);连续段断开(模型改变行为)即复位。\n * - 第二级(达到 stopThreshold,缺省 5):请求停机——先向 stop 上下文的\n * newMessages 追加一条用户可见的停机消息并交给 deliverNotice(禁止静默停\n * 机),再经 onStop 记日志。判据不可能完美,因此不可逆停机不是第一响应。\n *\n * 同参不同果(合法轮询,如等待外部状态就绪)不计重复:结果要素是全量哈希,\n * 任何字节差异(包括 >200 字符长结果仅尾部变化)都产生不同签名;无文本结果\n * 退化为两要素(见 {@link toolResultHash} 局限声明)。无工具调用或结果缺席的\n * 轮次不进窗口。\n */\n\n/** 结构化镜像 `@agent-forge/ai` 的 TextContent(内核类型不跨入插件面)。 */\nexport interface TextContent {\n\ttype: \"text\";\n\ttext: string;\n}\n\n/** 结构化镜像 `@agent-forge/ai` 的 ImageContent(内核类型不跨入插件面)。 */\nexport interface ImageContent {\n\ttype: \"image\";\n\tdata: string;\n\tmimeType: string;\n}\n\n/**\n * 结构化镜像宿主 `core/messages.ts` 的 CustomMessage(D-082 批 3):护栏的三种\n * 通知消息与宿主自定义消息同形,经 `SessionAPI.sendMessage` 投递后由宿主按\n * role:\"custom\" 持久化与渲染。字段与宿主逐字一致,漂移由宿主 e2e(通知持久化\n * 与渲染事件断言)拦截。\n */\nexport interface CustomMessage<T = unknown> {\n\trole: \"custom\";\n\tcustomType: string;\n\tcontent: string | (TextContent | ImageContent)[];\n\tdisplay: boolean;\n\tdetails?: T;\n\ttimestamp: number;\n}\n\n/** 结构化镜像 `@agent-forge/ai` 的 ToolCall(护栏只消费 id/name/arguments)。 */\nexport interface ToolCall {\n\ttype: \"toolCall\";\n\tid: string;\n\tname: string;\n\targuments: Record<string, unknown>;\n}\n\n/** 结构化镜像 `@agent-forge/ai` 的 ToolResultMessage(护栏只消费 content/isError)。 */\nexport interface ToolResultMessage {\n\trole: \"toolResult\";\n\ttoolCallId: string;\n\ttoolName: string;\n\tcontent: (TextContent | ImageContent)[];\n\tisError: boolean;\n\ttimestamp: number;\n}\n\n/**\n * 结构化镜像 `@agent-forge/agent-core` 的 ShouldStopAfterTurnContext(内核类型\n * 不跨入 plugin-sdk,D-075 S2;插件只消费 message/toolResults/newMessages)。\n * 宿主把同一个运行时对象交给内核回调与本插件链路,字段读取语义不变。\n */\nexport interface ShouldStopAfterTurnContext {\n\t/** The assistant message that completed the turn. */\n\tmessage: { content: readonly (ToolCall | { type: string })[] };\n\t/** Tool result messages passed to the preceding `turn_end` event. */\n\ttoolResults: readonly ToolResultMessage[];\n\t/** Current agent context after the turn (consumed by the host, not the guard). */\n\tcontext: unknown;\n\t/** Messages this loop invocation returns if it exits at this point. */\n\tnewMessages: CustomMessage[];\n}\n\n/** 滑动窗口大小:护栏只回看最近 N 个工具调用签名(跨回合累计)。 */\nexport const REPEATED_TOOL_CALL_WINDOW_SIZE = 6;\n/** 提醒阈值:窗口尾部连续相同签名达到该次数时提醒模型(不停机,两级响应第一级)。 */\nexport const REPEATED_TOOL_CALL_WARN_THRESHOLD = 3;\n/** 停机阈值:提醒后仍连续相同达到该次数才请求停机(两级响应第二级兜底)。 */\nexport const REPEATED_TOOL_CALL_STOP_THRESHOLD = 5;\n/** 停机提示消息的 customType(用户可见面,随 agent_end 的 messages 带出)。 */\nexport const REPEATED_TOOL_CALL_STOP_CUSTOM_TYPE = \"loop_guard_stop\";\n/** 提醒消息的 customType(用户可见面经 sendMessage 持久化+渲染;模型面注入复用同一标记)。 */\nexport const REPEATED_TOOL_CALL_WARN_CUSTOM_TYPE = \"loop_guard_warn\";\n/** 提示消息中参数串的最大长度,超出截断(只影响提示文本,不影响检测签名)。 */\nexport const REPEATED_TOOL_CALL_NOTICE_MAX_ARGS_CHARS = 200;\n\n/** {@link createRepeatedToolCallStopPolicy} 的窗口与两级阈值参数(缺省用上方命名常量)。 */\nexport interface RepeatedToolCallStopPolicyOptions {\n\t/** 滑动窗口大小,缺省 {@link REPEATED_TOOL_CALL_WINDOW_SIZE}。 */\n\twindowSize?: number;\n\t/** 提醒阈值(第一级,不停机),缺省 {@link REPEATED_TOOL_CALL_WARN_THRESHOLD}。 */\n\twarnThreshold?: number;\n\t/** 停机阈值(第二级兜底),缺省 {@link REPEATED_TOOL_CALL_STOP_THRESHOLD}。显式设为不大于提醒阈值时停机优先。 */\n\tstopThreshold?: number;\n\t/**\n\t * 提醒时的日志面回调(与 {@link onStop} 同纪律:info 只携带脱敏后的事实——\n\t * 工具名、截断参数摘要、提醒阈值,不含完整工具参数)。只在第一级实际提醒的\n\t * 回合调用一次;缺省不接 = 行为不变。\n\t */\n\tonWarn?: (info: RepeatedToolCallWarnInfo) => void;\n\t/**\n\t * 停机时的日志面回调(D-072 治理纪律 6(a):用户可见 + 日志可见双通道)。\n\t * 只在策略实际请求停机的回合调用一次;缺省不接 = 行为不变。info 只携带\n\t * 脱敏后的事实(工具名、截断参数摘要、阈值),不含完整工具参数。\n\t */\n\tonStop?: (info: RepeatedToolCallStopInfo) => void;\n\t/**\n\t * 提醒通知投递缝:策略把提醒消息交给宿主选定的公共面。默认安装把它接到\n\t * `SessionAPI.sendMessage`(持久化 + message_start 实时渲染);缺席时提醒\n\t * 仍经 transformContext 注入模型请求(模型面不依赖该缝)。\n\t */\n\tdeliverWarn?: (notice: CustomMessage) => void;\n\t/**\n\t * 停机通知投递缝:策略把停机提示消息交给宿主选定的公共面。默认安装把它接到\n\t * `SessionAPI.sendMessage`(运行中排队、run 收尾 flush 落为 custom_message\n\t * 条目——持久化 + message_start 实时渲染);缺席时停机事实仅随 agent_end 的\n\t * newMessages 带出(行为不变)。\n\t */\n\tdeliverNotice?: (notice: CustomMessage) => void;\n}\n\n/** 提醒事实(脱敏):{@link RepeatedToolCallStopPolicyOptions.onWarn} 的载荷。 */\nexport interface RepeatedToolCallWarnInfo {\n\t/** 触发提醒的最后一个工具名。 */\n\ttoolName: string;\n\t/** 截断后的参数稳定序列化摘要(复用 {@link REPEATED_TOOL_CALL_NOTICE_MAX_ARGS_CHARS})。 */\n\targsSummary: string;\n\t/** 达到的连续重复提醒阈值。 */\n\twarnThreshold: number;\n}\n\n/** 停机事实(脱敏):{@link RepeatedToolCallStopPolicyOptions.onStop} 的载荷。 */\nexport interface RepeatedToolCallStopInfo {\n\t/** 触发停机的最后一个工具名。 */\n\ttoolName: string;\n\t/** 截断后的参数稳定序列化摘要(复用 {@link REPEATED_TOOL_CALL_NOTICE_MAX_ARGS_CHARS})。 */\n\targsSummary: string;\n\t/** 达到的连续重复停机阈值。 */\n\tstopThreshold: number;\n}\n\n/**\n * 参数稳定字符串化:对象键递归排序后逐层拼接(数组保持顺序),循环引用输出\n * 固定占位。只用于签名比较与提示文本,不是通用 JSON 序列化器。\n */\nexport function stableSerializeValue(value: unknown, seen: WeakSet<object> = new WeakSet()): string {\n\tif (value === null) return \"null\";\n\tswitch (typeof value) {\n\t\tcase \"string\":\n\t\t\treturn JSON.stringify(value);\n\t\tcase \"number\":\n\t\t\treturn String(value);\n\t\tcase \"boolean\":\n\t\t\treturn String(value);\n\t\tcase \"undefined\":\n\t\t\treturn \"undefined\";\n\t\tcase \"bigint\":\n\t\t\treturn `bigint:${String(value)}`;\n\t\tcase \"function\":\n\t\t\treturn \"function\";\n\t\tcase \"symbol\":\n\t\t\treturn \"symbol\";\n\t\tcase \"object\":\n\t\t\tbreak;\n\t\tdefault:\n\t\t\treturn \"unknown\";\n\t}\n\tif (seen.has(value)) return '\"[cycle]\"';\n\tseen.add(value);\n\tconst serialized = Array.isArray(value)\n\t\t? `[${value.map((item) => stableSerializeValue(item, seen)).join(\",\")}]`\n\t\t: (() => {\n\t\t\t\tconst record = value as Record<string, unknown>;\n\t\t\t\tconst keys = Object.keys(record).sort();\n\t\t\t\treturn `{${keys.map((key) => `${JSON.stringify(key)}:${stableSerializeValue(record[key], seen)}`).join(\",\")}}`;\n\t\t\t})();\n\tseen.delete(value);\n\treturn serialized;\n}\n\n/**\n * 工具结果哈希(签名第三要素):拼接结果的 text 内容后做全量 SHA-256(十六进制),\n * isError 一并纳入(同参同果且同错误状态才计重复)。任何字节差异都产生不同哈希,\n * 因此长结果(前缀稳定、尾部变化)的合法轮询不会被误判成\"同果\"——签名不受任何\n * 截断影响。无文本结果(纯图像等)与结果缺席都返回空串占位:签名退化为两要素\n * (工具名 + 参数),这是已知局限——无文本的同参结果彼此不可区分。\n * 调用与结果按 toolCallId 对应,正常流程中每个调用都有结果;无结果返回空串。\n */\nexport function toolResultHash(result: ToolResultMessage | undefined): string {\n\tif (!result) return \"\";\n\tconst text = result.content\n\t\t.filter((block): block is TextContent => block.type === \"text\")\n\t\t.map((block) => block.text)\n\t\t.join(\"\\n\");\n\tif (text === \"\") return \"\";\n\treturn `${result.isError ? \"error\" : \"ok\"}:${createHash(\"sha256\").update(text).digest(\"hex\")}`;\n}\n\n/** 工具调用签名:工具名 + 参数稳定字符串化 + 结果哈希。 */\nexport function repeatedToolCallSignature(toolName: string, args: unknown, resultHash: string): string {\n\treturn `${JSON.stringify(toolName)}:${stableSerializeValue(args)}:${resultHash}`;\n}\n\n/** 参数摘要截断:超出 {@link REPEATED_TOOL_CALL_NOTICE_MAX_ARGS_CHARS} 打截断标记(用户可见消息与日志通道共用)。 */\nfunction truncateNoticeArgs(argsText: string): string {\n\treturn argsText.length > REPEATED_TOOL_CALL_NOTICE_MAX_ARGS_CHARS\n\t\t? `${argsText.slice(0, REPEATED_TOOL_CALL_NOTICE_MAX_ARGS_CHARS)}...(truncated)`\n\t\t: argsText;\n}\n\n/** 停机提示消息:随停机回合的 newMessages 带出(agent_end 可见),并经 deliverNotice 投递到宿主公共面。 */\nexport function createRepeatedToolCallStopNotice(\n\ttoolName: string,\n\targsText: string,\n\tstopThreshold: number,\n): CustomMessage {\n\tconst truncated = truncateNoticeArgs(argsText);\n\treturn {\n\t\trole: \"custom\",\n\t\tcustomType: REPEATED_TOOL_CALL_STOP_CUSTOM_TYPE,\n\t\tcontent: `Loop guard: stopped after the same tool call (${toolName}) was repeated ${stopThreshold} times in a row. Args: ${truncated}`,\n\t\tdisplay: true,\n\t\ttimestamp: Date.now(),\n\t};\n}\n\n/**\n * 提醒通知消息(用户可见面,loop_guard_warn):经 deliverWarn 投递(默认安装接\n * `SessionAPI.sendMessage`,持久化 + 实时渲染),与停机通知(loop_guard_stop)\n * 的 customType 区分。提醒不进入 newMessages——模型面提醒由 transformContext\n * 注入承担,用户面提醒由本消息的持久化+渲染承担。\n */\nexport function createRepeatedToolCallWarnNotice(\n\ttoolName: string,\n\targsText: string,\n\twarnThreshold: number,\n): CustomMessage {\n\tconst truncated = truncateNoticeArgs(argsText);\n\treturn {\n\t\trole: \"custom\",\n\t\tcustomType: REPEATED_TOOL_CALL_WARN_CUSTOM_TYPE,\n\t\tcontent: `Loop guard: the same tool call (${toolName}) was repeated ${warnThreshold} times in a row with the same result. Args: ${truncated}`,\n\t\tdisplay: true,\n\t\ttimestamp: Date.now(),\n\t};\n}\n\n/**\n * 模型面提醒消息(transformContext 注入用):display:false 的 custom 消息,\n * 经宿主 convertToLlm 转为 user 文本进入下一次模型请求。只存在于该次请求视图\n * (不写 context.messages、不进 newMessages,故不持久化);customType 复用\n * loop_guard_warn 标记来源。\n */\nexport function createRepeatedToolCallWarnReminder(warnThreshold: number): CustomMessage {\n\treturn {\n\t\trole: \"custom\",\n\t\tcustomType: REPEATED_TOOL_CALL_WARN_CUSTOM_TYPE,\n\t\tcontent: `You have repeated the identical tool call with an identical result ${warnThreshold} times. If you are waiting for external state to change, change your approach instead of retrying the same call.`,\n\t\tdisplay: false,\n\t\ttimestamp: Date.now(),\n\t};\n}\n\n/** {@link createRepeatedToolCallStopPolicy} 返回的两条链路(共享同一滑动窗口与两级状态)。 */\nexport interface RepeatedToolCallGuard {\n\t/**\n\t * \"shouldStopAfterTurn\" 链路:两级判定的决策面(返回 true 即请求停机)。\n\t */\n\tshouldStopAfterTurn: (context: ShouldStopAfterTurnContext) => boolean;\n\t/**\n\t * \"transformContext\" 链路:提醒注入面。有待注入提醒时返回追加了提醒消息的\n\t * 新数组(进入下一次模型请求视图),否则返回 undefined(保留输入)。\n\t */\n\ttransformContext: (messages: readonly unknown[], signal?: AbortSignal) => Promise<readonly unknown[] | undefined>;\n}\n\n/**\n * 默认重复工具调用护栏工厂(两级响应)。算法与阈值逐字迁移自宿主内嵌实现的\n * 同名工厂;两条链路由 `entry.ts` 经公共扩展面 `api.registerLoopHook` 注册为\n * 默认链路(transformContext 注入链注册在默认上下文策略链之后,提醒落到最终\n * 请求视图尾部);`disabledPluginIds` 跳过本插件时均不注册,护栏随之关闭。\n */\nexport function createRepeatedToolCallStopPolicy(\n\toptions: RepeatedToolCallStopPolicyOptions = {},\n): RepeatedToolCallGuard {\n\tconst windowSize = options.windowSize ?? REPEATED_TOOL_CALL_WINDOW_SIZE;\n\tconst warnThreshold = options.warnThreshold ?? REPEATED_TOOL_CALL_WARN_THRESHOLD;\n\tconst stopThreshold = options.stopThreshold ?? REPEATED_TOOL_CALL_STOP_THRESHOLD;\n\tconst window: string[] = [];\n\tlet lastToolName = \"\";\n\tlet lastArgsText = \"\";\n\t/** 待注入的提醒事实:warn 时置位,transformContext 消费即清除(只注入一次)。 */\n\tlet pendingWarn: RepeatedToolCallWarnInfo | undefined;\n\t/** 当前连续重复段已提醒闩:同段不重复提醒;段断开(尾部连续段短于提醒阈值)时复位。 */\n\tlet warnedForRun = false;\n\n\t/** 窗口尾部连续相同签名的段长。 */\n\tconst trailingRunLength = (): number => {\n\t\tconst last = window[window.length - 1];\n\t\tif (last === undefined) return 0;\n\t\tlet run = 0;\n\t\tfor (let i = window.length - 1; i >= 0 && window[i] === last; i -= 1) run += 1;\n\t\treturn run;\n\t};\n\n\tconst shouldStopAfterTurn = (context: ShouldStopAfterTurnContext): boolean => {\n\t\tconst toolCalls = context.message.content.filter((block): block is ToolCall => block.type === \"toolCall\");\n\t\t// 三要素签名需要本轮工具结果:结果缺席时无法判定\"同果\",该轮不进窗口,\n\t\t// 避免把合法轮询误判成重复。\n\t\tif (toolCalls.length > 0 && context.toolResults.length > 0) {\n\t\t\tconst resultById = new Map(context.toolResults.map((result) => [result.toolCallId, result]));\n\t\t\tfor (const call of toolCalls) {\n\t\t\t\twindow.push(repeatedToolCallSignature(call.name, call.arguments, toolResultHash(resultById.get(call.id))));\n\t\t\t\tlastToolName = call.name;\n\t\t\t\tlastArgsText = stableSerializeValue(call.arguments);\n\t\t\t}\n\t\t}\n\t\tif (window.length > windowSize) {\n\t\t\twindow.splice(0, window.length - windowSize);\n\t\t}\n\t\tconst run = trailingRunLength();\n\t\tif (run >= stopThreshold) {\n\t\t\t// 第二级兜底:硬停,走停机全通道(newMessages + deliverNotice + onStop)。\n\t\t\t// 先于提醒判定:stopThreshold 被显式覆盖到不大于 warnThreshold 时停机优先。\n\t\t\tpendingWarn = undefined;\n\t\t\tconst notice = createRepeatedToolCallStopNotice(lastToolName, lastArgsText, stopThreshold);\n\t\t\tcontext.newMessages.push(notice);\n\t\t\toptions.deliverNotice?.(notice);\n\t\t\t// 日志可见通道(D-072 6(a)):与用户可见提示成对发出;onStop 属宿主接线,\n\t\t\t// 策略本身不知道任何具体日志实现。\n\t\t\toptions.onStop?.({ toolName: lastToolName, argsSummary: truncateNoticeArgs(lastArgsText), stopThreshold });\n\t\t\treturn true;\n\t\t}\n\t\tif (run < warnThreshold) {\n\t\t\t// 连续段断开:模型改变行为。复位已提醒闩并丢弃未消费的待注入提醒\n\t\t\t// (正常流程中它已在下一轮请求前被消费;此处只兜底运行中断的残留)。\n\t\t\twarnedForRun = false;\n\t\t\tpendingWarn = undefined;\n\t\t\treturn false;\n\t\t}\n\t\t// 第一级:提醒不停机。标记待注入(transformContext 链路消费),经\n\t\t// deliverWarn/onWarn 双通道可见;同一连续段只提醒一次。\n\t\tif (!warnedForRun) {\n\t\t\twarnedForRun = true;\n\t\t\tpendingWarn = { toolName: lastToolName, argsSummary: truncateNoticeArgs(lastArgsText), warnThreshold };\n\t\t\toptions.deliverWarn?.(createRepeatedToolCallWarnNotice(lastToolName, lastArgsText, warnThreshold));\n\t\t\toptions.onWarn?.(pendingWarn);\n\t\t}\n\t\treturn false;\n\t};\n\n\tconst transformContext = async (\n\t\tmessages: readonly unknown[],\n\t\t_signal?: AbortSignal,\n\t): Promise<readonly unknown[] | undefined> => {\n\t\tconst info = pendingWarn;\n\t\tif (!info) return undefined;\n\t\t// 消费即清除:提醒只注入一次;重复继续发生不重复注入。非变异地追加到\n\t\t// 请求视图尾部(不写 context.messages,故不持久化、不进 newMessages)。\n\t\tpendingWarn = undefined;\n\t\treturn [...messages, createRepeatedToolCallWarnReminder(info.warnThreshold)];\n\t};\n\n\treturn { shouldStopAfterTurn, transformContext };\n}\n"]}