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

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 (460) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +1 -1
  3. package/bundled-plugins/agent-loop-policy/agent-forge.json +1 -1
  4. package/bundled-plugins/agent-loop-policy/plugin.json +1 -1
  5. package/bundled-plugins/coding-tools/agent-forge.json +1 -1
  6. package/bundled-plugins/coding-tools/plugin.json +1 -1
  7. package/bundled-plugins/compaction-policy/agent-forge.json +1 -1
  8. package/bundled-plugins/compaction-policy/plugin.json +1 -1
  9. package/bundled-plugins/overflow-policy/agent-forge.json +1 -1
  10. package/bundled-plugins/overflow-policy/plugin.json +1 -1
  11. package/bundled-plugins/provider-failover/agent-forge.json +1 -1
  12. package/bundled-plugins/provider-failover/plugin.json +1 -1
  13. package/bundled-plugins/retry-policy/agent-forge.json +1 -1
  14. package/bundled-plugins/retry-policy/plugin.json +1 -1
  15. package/dist/artifacts/paged-read.d.ts +6 -1
  16. package/dist/artifacts/paged-read.d.ts.map +1 -1
  17. package/dist/artifacts/paged-read.js.map +1 -1
  18. package/dist/bundle/.build-manifest.json +244 -234
  19. package/dist/bundle/chunks/{anthropic-messages-PLAKXR73.js → anthropic-messages-3FJHRAJL.js} +2 -2
  20. package/dist/bundle/chunks/anthropic.js +1 -1
  21. package/dist/bundle/chunks/{azure-openai-responses-OUWQ2AZD.js → azure-openai-responses-GCL47IDS.js} +1 -1
  22. package/dist/bundle/chunks/bedrock-converse-stream.js +1 -1
  23. package/dist/bundle/chunks/{chunk-6F5JWGKE.js → chunk-32YDZI4J.js} +1 -1
  24. package/dist/bundle/chunks/{chunk-LSP24WNH.js → chunk-755VNWIF.js} +12 -12
  25. package/dist/bundle/chunks/{chunk-DRQDKNXA.js → chunk-BVVSHK6W.js} +1 -1
  26. package/dist/bundle/chunks/{chunk-HTC5K5SM.js → chunk-HEL6TAWE.js} +95 -90
  27. package/dist/bundle/chunks/{chunk-6R7UI4IY.js → chunk-QDLOMKF6.js} +1 -1
  28. package/dist/bundle/chunks/{chunk-44I47ACN.js → chunk-V3ACW7VD.js} +1 -1
  29. package/dist/bundle/chunks/{google-generative-ai-DLII6DAT.js → google-generative-ai-6BMXWA44.js} +1 -1
  30. package/dist/bundle/chunks/{google-vertex-G7BZL7GM.js → google-vertex-6H7NLRTK.js} +1 -1
  31. package/dist/bundle/chunks/image-resize-worker.js +1 -1
  32. package/dist/bundle/chunks/{mistral-conversations-JXUK24ID.js → mistral-conversations-IXUHSFSJ.js} +1 -1
  33. package/dist/bundle/chunks/{openai-codex-responses-5GSGFIPG.js → openai-codex-responses-YHUAEVCM.js} +1 -1
  34. package/dist/bundle/chunks/openai-codex.js +1 -1
  35. package/dist/bundle/chunks/{openai-completions-EI2I6DTG.js → openai-completions-ULQCFC72.js} +1 -1
  36. package/dist/bundle/chunks/openai-responses-NLLAJDPS.js +2 -0
  37. package/dist/bundle/chunks/{openrouter-images-G4GQRUSG.js → openrouter-images-GZZQZXMS.js} +1 -1
  38. package/dist/bundle/chunks/openrouter.js +1 -1
  39. package/dist/bundle/chunks/{pi-messages-PWU2VJMR.js → pi-messages-EJTI2EJ3.js} +1 -1
  40. package/dist/bundle/chunks/virtual-modules-TQWEGNNZ.js +5 -0
  41. package/dist/bundle/cli.js +1 -1
  42. package/dist/bundle/client.js +1 -1
  43. package/dist/bundle/index.js +1 -1
  44. package/dist/bundle/rpc-entry.js +1 -1
  45. package/dist/cli/args.d.ts +0 -1
  46. package/dist/cli/args.d.ts.map +1 -1
  47. package/dist/cli/args.js +1 -4
  48. package/dist/cli/args.js.map +1 -1
  49. package/dist/cli/config-selector.d.ts.map +1 -1
  50. package/dist/cli/config-selector.js +1 -1
  51. package/dist/cli/config-selector.js.map +1 -1
  52. package/dist/cli/experimental/cli.d.ts +3 -3
  53. package/dist/cli/experimental/cli.d.ts.map +1 -1
  54. package/dist/cli/experimental/cli.js +2 -2
  55. package/dist/cli/experimental/cli.js.map +1 -1
  56. package/dist/cli/experimental/commands/agent-forge.d.ts +15 -0
  57. package/dist/cli/experimental/commands/agent-forge.d.ts.map +1 -0
  58. package/dist/cli/experimental/commands/{pi.js → agent-forge.js} +4 -4
  59. package/dist/cli/experimental/commands/agent-forge.js.map +1 -0
  60. package/dist/cli/startup-ui.d.ts.map +1 -1
  61. package/dist/cli/startup-ui.js +1 -1
  62. package/dist/cli/startup-ui.js.map +1 -1
  63. package/dist/config.d.ts +4 -4
  64. package/dist/config.d.ts.map +1 -1
  65. package/dist/config.js +7 -7
  66. package/dist/config.js.map +1 -1
  67. package/dist/core/agent-forge-manifest.d.ts +7 -0
  68. package/dist/core/agent-forge-manifest.d.ts.map +1 -0
  69. package/dist/core/{pi-manifest.js → agent-forge-manifest.js} +4 -4
  70. package/dist/core/agent-forge-manifest.js.map +1 -0
  71. package/dist/core/agent-session-compaction.d.ts +1 -1
  72. package/dist/core/agent-session-compaction.d.ts.map +1 -1
  73. package/dist/core/agent-session-compaction.js +3 -3
  74. package/dist/core/agent-session-compaction.js.map +1 -1
  75. package/dist/core/agent-session-lifecycle.d.ts.map +1 -1
  76. package/dist/core/agent-session-lifecycle.js +12 -1
  77. package/dist/core/agent-session-lifecycle.js.map +1 -1
  78. package/dist/core/agent-session-projection.d.ts.map +1 -1
  79. package/dist/core/agent-session-projection.js +3 -3
  80. package/dist/core/agent-session-projection.js.map +1 -1
  81. package/dist/core/agent-session-services.d.ts +1 -1
  82. package/dist/core/agent-session-services.d.ts.map +1 -1
  83. package/dist/core/agent-session-services.js +1 -1
  84. package/dist/core/agent-session-services.js.map +1 -1
  85. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  86. package/dist/core/compaction/branch-summarization.js +1 -1
  87. package/dist/core/compaction/branch-summarization.js.map +1 -1
  88. package/dist/core/experimental.d.ts.map +1 -1
  89. package/dist/core/experimental.js +1 -3
  90. package/dist/core/experimental.js.map +1 -1
  91. package/dist/core/extensions/capability-plugin.d.ts.map +1 -1
  92. package/dist/core/extensions/capability-plugin.js +15 -8
  93. package/dist/core/extensions/capability-plugin.js.map +1 -1
  94. package/dist/core/extensions/capability-runtime-store.d.ts +20 -1
  95. package/dist/core/extensions/capability-runtime-store.d.ts.map +1 -1
  96. package/dist/core/extensions/capability-runtime-store.js +67 -0
  97. package/dist/core/extensions/capability-runtime-store.js.map +1 -1
  98. package/dist/core/extensions/capability-runtime-types.d.ts +14 -0
  99. package/dist/core/extensions/capability-runtime-types.d.ts.map +1 -1
  100. package/dist/core/extensions/capability-runtime-types.js +7 -1
  101. package/dist/core/extensions/capability-runtime-types.js.map +1 -1
  102. package/dist/core/extensions/capability-runtime.d.ts.map +1 -1
  103. package/dist/core/extensions/capability-runtime.js +144 -42
  104. package/dist/core/extensions/capability-runtime.js.map +1 -1
  105. package/dist/core/extensions/virtual-modules.d.ts.map +1 -1
  106. package/dist/core/extensions/virtual-modules.js +12 -4
  107. package/dist/core/extensions/virtual-modules.js.map +1 -1
  108. package/dist/core/facade/coding-agent-facade.d.ts +1 -1
  109. package/dist/core/facade/coding-agent-facade.d.ts.map +1 -1
  110. package/dist/core/facade/coding-agent-facade.js +1 -1
  111. package/dist/core/facade/coding-agent-facade.js.map +1 -1
  112. package/dist/core/i18n/locales/zh-cn/core-contract-final.d.ts +1 -1
  113. package/dist/core/i18n/locales/zh-cn/core-contract-final.d.ts.map +1 -1
  114. package/dist/core/i18n/locales/zh-cn/core-contract-final.js +3 -3
  115. package/dist/core/i18n/locales/zh-cn/core-contract-final.js.map +1 -1
  116. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.d.ts.map +1 -1
  117. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.js +1 -1
  118. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.js.map +1 -1
  119. package/dist/core/i18n/locales/zh-cn/core-errors.d.ts.map +1 -1
  120. package/dist/core/i18n/locales/zh-cn/core-errors.js +1 -1
  121. package/dist/core/i18n/locales/zh-cn/core-errors.js.map +1 -1
  122. package/dist/core/i18n/locales/zh-cn/tui-components-misc.d.ts.map +1 -1
  123. package/dist/core/i18n/locales/zh-cn/tui-components-misc.js +2 -0
  124. package/dist/core/i18n/locales/zh-cn/tui-components-misc.js.map +1 -1
  125. package/dist/core/model-resolver.d.ts +2 -0
  126. package/dist/core/model-resolver.d.ts.map +1 -1
  127. package/dist/core/model-resolver.js +4 -1
  128. package/dist/core/model-resolver.js.map +1 -1
  129. package/dist/core/package-resource-collection.d.ts.map +1 -1
  130. package/dist/core/package-resource-collection.js +5 -5
  131. package/dist/core/package-resource-collection.js.map +1 -1
  132. package/dist/core/provider-composer.d.ts.map +1 -1
  133. package/dist/core/provider-composer.js +3 -3
  134. package/dist/core/provider-composer.js.map +1 -1
  135. package/dist/core/resource-loader.d.ts.map +1 -1
  136. package/dist/core/resource-loader.js +1 -1
  137. package/dist/core/resource-loader.js.map +1 -1
  138. package/dist/core/sdk.d.ts +1 -1
  139. package/dist/core/sdk.d.ts.map +1 -1
  140. package/dist/core/sdk.js +6 -7
  141. package/dist/core/sdk.js.map +1 -1
  142. package/dist/core/session-manager.d.ts.map +1 -1
  143. package/dist/core/session-manager.js +4 -4
  144. package/dist/core/session-manager.js.map +1 -1
  145. package/dist/core/settings-manager.d.ts.map +1 -1
  146. package/dist/core/settings-manager.js +5 -10
  147. package/dist/core/settings-manager.js.map +1 -1
  148. package/dist/core/timings.d.ts.map +1 -1
  149. package/dist/core/timings.js +1 -3
  150. package/dist/core/timings.js.map +1 -1
  151. package/dist/core/tools/render-utils.d.ts +1 -1
  152. package/dist/core/tools/render-utils.d.ts.map +1 -1
  153. package/dist/core/tools/render-utils.js.map +1 -1
  154. package/dist/core/tools/tool-definition.d.ts +1 -1
  155. package/dist/core/tools/tool-definition.d.ts.map +1 -1
  156. package/dist/core/tools/tool-definition.js.map +1 -1
  157. package/dist/core/trace-retention.d.ts +16 -1
  158. package/dist/core/trace-retention.d.ts.map +1 -1
  159. package/dist/core/trace-retention.js +43 -20
  160. package/dist/core/trace-retention.js.map +1 -1
  161. package/dist/export-html/ansi-to-html.d.ts.map +1 -0
  162. package/dist/export-html/ansi-to-html.js.map +1 -0
  163. package/dist/{core/export-html → export-html}/index.d.ts +1 -1
  164. package/dist/export-html/index.d.ts.map +1 -0
  165. package/dist/{core/export-html → export-html}/index.js +5 -5
  166. package/dist/export-html/index.js.map +1 -0
  167. package/dist/{core/export-html → export-html}/tool-renderer.d.ts +2 -2
  168. package/dist/export-html/tool-renderer.d.ts.map +1 -0
  169. package/dist/export-html/tool-renderer.js.map +1 -0
  170. package/dist/{modes/interactive → host}/model-catalog-refresh.d.ts +1 -1
  171. package/dist/host/model-catalog-refresh.d.ts.map +1 -0
  172. package/dist/{modes/interactive → host}/model-catalog-refresh.js +1 -1
  173. package/dist/host/model-catalog-refresh.js.map +1 -0
  174. package/dist/index.d.ts +5 -5
  175. package/dist/index.d.ts.map +1 -1
  176. package/dist/index.js +12 -12
  177. package/dist/index.js.map +1 -1
  178. package/dist/main.d.ts.map +1 -1
  179. package/dist/main.js +25 -14
  180. package/dist/main.js.map +1 -1
  181. package/dist/modes/interactive/components/agents-view.d.ts.map +1 -1
  182. package/dist/modes/interactive/components/agents-view.js +1 -1
  183. package/dist/modes/interactive/components/agents-view.js.map +1 -1
  184. package/dist/modes/interactive/components/armin.d.ts.map +1 -1
  185. package/dist/modes/interactive/components/armin.js +1 -1
  186. package/dist/modes/interactive/components/armin.js.map +1 -1
  187. package/dist/modes/interactive/components/assistant-message.d.ts +3 -0
  188. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  189. package/dist/modes/interactive/components/assistant-message.js +83 -24
  190. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  191. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  192. package/dist/modes/interactive/components/bash-execution.js +1 -1
  193. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  194. package/dist/modes/interactive/components/bordered-loader.d.ts +1 -1
  195. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  196. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  197. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  198. package/dist/modes/interactive/components/branch-summary-message.js +1 -1
  199. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  200. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  201. package/dist/modes/interactive/components/compaction-summary-message.js +1 -1
  202. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  203. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  204. package/dist/modes/interactive/components/config-selector.js +1 -1
  205. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  206. package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -1
  207. package/dist/modes/interactive/components/custom-entry.js +1 -1
  208. package/dist/modes/interactive/components/custom-entry.js.map +1 -1
  209. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  210. package/dist/modes/interactive/components/custom-message.js +1 -1
  211. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  212. package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
  213. package/dist/modes/interactive/components/daxnuts.js +1 -1
  214. package/dist/modes/interactive/components/daxnuts.js.map +1 -1
  215. package/dist/modes/interactive/components/dialog-editor.d.ts.map +1 -1
  216. package/dist/modes/interactive/components/dialog-editor.js +1 -1
  217. package/dist/modes/interactive/components/dialog-editor.js.map +1 -1
  218. package/dist/modes/interactive/components/dialog-input.d.ts.map +1 -1
  219. package/dist/modes/interactive/components/dialog-input.js +1 -1
  220. package/dist/modes/interactive/components/dialog-input.js.map +1 -1
  221. package/dist/modes/interactive/components/dialog-selector.d.ts.map +1 -1
  222. package/dist/modes/interactive/components/dialog-selector.js +1 -1
  223. package/dist/modes/interactive/components/dialog-selector.js.map +1 -1
  224. package/dist/modes/interactive/components/diff.d.ts.map +1 -1
  225. package/dist/modes/interactive/components/diff.js +1 -1
  226. package/dist/modes/interactive/components/diff.js.map +1 -1
  227. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  228. package/dist/modes/interactive/components/dynamic-border.js +1 -1
  229. package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  230. package/dist/modes/interactive/components/first-time-setup.d.ts +1 -1
  231. package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
  232. package/dist/modes/interactive/components/first-time-setup.js +1 -1
  233. package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
  234. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  235. package/dist/modes/interactive/components/footer.js +1 -1
  236. package/dist/modes/interactive/components/footer.js.map +1 -1
  237. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  238. package/dist/modes/interactive/components/keybinding-hints.js +1 -1
  239. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  240. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  241. package/dist/modes/interactive/components/login-dialog.js +1 -1
  242. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  243. package/dist/modes/interactive/components/mermaid.d.ts +1 -1
  244. package/dist/modes/interactive/components/mermaid.d.ts.map +1 -1
  245. package/dist/modes/interactive/components/mermaid.js.map +1 -1
  246. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  247. package/dist/modes/interactive/components/model-selector.js +2 -2
  248. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  249. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  250. package/dist/modes/interactive/components/oauth-selector.js +1 -1
  251. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  252. package/dist/modes/interactive/components/plugin-manager-entry.d.ts.map +1 -1
  253. package/dist/modes/interactive/components/plugin-manager-entry.js +1 -1
  254. package/dist/modes/interactive/components/plugin-manager-entry.js.map +1 -1
  255. package/dist/modes/interactive/components/plugin-selection-entry.d.ts.map +1 -1
  256. package/dist/modes/interactive/components/plugin-selection-entry.js +1 -1
  257. package/dist/modes/interactive/components/plugin-selection-entry.js.map +1 -1
  258. package/dist/modes/interactive/components/queue-manager-selector.d.ts.map +1 -1
  259. package/dist/modes/interactive/components/queue-manager-selector.js +1 -1
  260. package/dist/modes/interactive/components/queue-manager-selector.js.map +1 -1
  261. package/dist/modes/interactive/components/render-types.d.ts +1 -1
  262. package/dist/modes/interactive/components/render-types.d.ts.map +1 -1
  263. package/dist/modes/interactive/components/render-types.js.map +1 -1
  264. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  265. package/dist/modes/interactive/components/scoped-models-selector.js +1 -1
  266. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  267. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  268. package/dist/modes/interactive/components/session-selector.js +2 -2
  269. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  270. package/dist/modes/interactive/components/settings-selector.d.ts +1 -1
  271. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  272. package/dist/modes/interactive/components/settings-selector.js +1 -1
  273. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  274. package/dist/modes/interactive/components/settings-submenu.d.ts.map +1 -1
  275. package/dist/modes/interactive/components/settings-submenu.js +1 -1
  276. package/dist/modes/interactive/components/settings-submenu.js.map +1 -1
  277. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
  278. package/dist/modes/interactive/components/show-images-selector.js +1 -1
  279. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  280. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  281. package/dist/modes/interactive/components/skill-invocation-message.js +1 -1
  282. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  283. package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
  284. package/dist/modes/interactive/components/status-indicator.js +1 -1
  285. package/dist/modes/interactive/components/status-indicator.js.map +1 -1
  286. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
  287. package/dist/modes/interactive/components/theme-selector.js +1 -1
  288. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  289. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  290. package/dist/modes/interactive/components/thinking-selector.js +1 -1
  291. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  292. package/dist/modes/interactive/components/tool-execution.d.ts +2 -0
  293. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  294. package/dist/modes/interactive/components/tool-execution.js +96 -4
  295. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  296. package/dist/modes/interactive/components/tool-run-group.d.ts.map +1 -1
  297. package/dist/modes/interactive/components/tool-run-group.js +1 -1
  298. package/dist/modes/interactive/components/tool-run-group.js.map +1 -1
  299. package/dist/modes/interactive/components/tree-list.d.ts.map +1 -1
  300. package/dist/modes/interactive/components/tree-list.js +1 -1
  301. package/dist/modes/interactive/components/tree-list.js.map +1 -1
  302. package/dist/modes/interactive/components/tree-render.d.ts.map +1 -1
  303. package/dist/modes/interactive/components/tree-render.js +1 -1
  304. package/dist/modes/interactive/components/tree-render.js.map +1 -1
  305. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  306. package/dist/modes/interactive/components/tree-selector.js +1 -1
  307. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  308. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  309. package/dist/modes/interactive/components/user-message-selector.js +1 -1
  310. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  311. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  312. package/dist/modes/interactive/components/user-message.js +1 -1
  313. package/dist/modes/interactive/components/user-message.js.map +1 -1
  314. package/dist/modes/interactive/components/workflow-view.d.ts.map +1 -1
  315. package/dist/modes/interactive/components/workflow-view.js +1 -1
  316. package/dist/modes/interactive/components/workflow-view.js.map +1 -1
  317. package/dist/modes/interactive/interactive-auth.d.ts +1 -1
  318. package/dist/modes/interactive/interactive-auth.d.ts.map +1 -1
  319. package/dist/modes/interactive/interactive-auth.js +1 -1
  320. package/dist/modes/interactive/interactive-auth.js.map +1 -1
  321. package/dist/modes/interactive/interactive-commands.d.ts +123 -6
  322. package/dist/modes/interactive/interactive-commands.d.ts.map +1 -1
  323. package/dist/modes/interactive/interactive-commands.js +691 -4
  324. package/dist/modes/interactive/interactive-commands.js.map +1 -1
  325. package/dist/modes/interactive/interactive-events.d.ts +174 -0
  326. package/dist/modes/interactive/interactive-events.d.ts.map +1 -0
  327. package/dist/modes/interactive/interactive-events.js +704 -0
  328. package/dist/modes/interactive/interactive-events.js.map +1 -0
  329. package/dist/modes/interactive/interactive-format.d.ts.map +1 -1
  330. package/dist/modes/interactive/interactive-format.js +1 -1
  331. package/dist/modes/interactive/interactive-format.js.map +1 -1
  332. package/dist/modes/interactive/interactive-lifecycle.d.ts +94 -0
  333. package/dist/modes/interactive/interactive-lifecycle.d.ts.map +1 -0
  334. package/dist/modes/interactive/interactive-lifecycle.js +177 -0
  335. package/dist/modes/interactive/interactive-lifecycle.js.map +1 -0
  336. package/dist/modes/interactive/interactive-mode.d.ts +240 -133
  337. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  338. package/dist/modes/interactive/interactive-mode.js +251 -2159
  339. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  340. package/dist/modes/interactive/interactive-queues.d.ts +96 -0
  341. package/dist/modes/interactive/interactive-queues.d.ts.map +1 -0
  342. package/dist/modes/interactive/interactive-queues.js +183 -0
  343. package/dist/modes/interactive/interactive-queues.js.map +1 -0
  344. package/dist/modes/interactive/interactive-selectors.d.ts +95 -5
  345. package/dist/modes/interactive/interactive-selectors.d.ts.map +1 -1
  346. package/dist/modes/interactive/interactive-selectors.js +517 -6
  347. package/dist/modes/interactive/interactive-selectors.js.map +1 -1
  348. package/dist/modes/interactive/startup-services.d.ts +31 -0
  349. package/dist/modes/interactive/startup-services.d.ts.map +1 -0
  350. package/dist/modes/interactive/startup-services.js +123 -0
  351. package/dist/modes/interactive/startup-services.js.map +1 -0
  352. package/dist/modes/memory-preheat.d.ts +11 -0
  353. package/dist/modes/memory-preheat.d.ts.map +1 -0
  354. package/dist/modes/memory-preheat.js +20 -0
  355. package/dist/modes/memory-preheat.js.map +1 -0
  356. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  357. package/dist/modes/rpc/rpc-mode.js +3 -1
  358. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  359. package/dist/plugins/ecosystem/node-package-install-host.d.ts +9 -1
  360. package/dist/plugins/ecosystem/node-package-install-host.d.ts.map +1 -1
  361. package/dist/plugins/ecosystem/node-package-install-host.js +79 -0
  362. package/dist/plugins/ecosystem/node-package-install-host.js.map +1 -1
  363. package/dist/remote/server-assembly.d.ts.map +1 -1
  364. package/dist/remote/server-assembly.js +7 -2
  365. package/dist/remote/server-assembly.js.map +1 -1
  366. package/dist/suites/builtin-suites.d.ts.map +1 -0
  367. package/dist/suites/builtin-suites.js.map +1 -0
  368. package/dist/suites/resolved-agent-profile.d.ts.map +1 -0
  369. package/dist/suites/resolved-agent-profile.js.map +1 -0
  370. package/dist/suites/suite-lifecycle.d.ts.map +1 -0
  371. package/dist/suites/suite-lifecycle.js.map +1 -0
  372. package/dist/suites/suite-loader.d.ts.map +1 -0
  373. package/dist/suites/suite-loader.js.map +1 -0
  374. package/dist/{modes/interactive/theme → theme}/dark.json +1 -1
  375. package/dist/{modes/interactive/theme → theme}/light.json +1 -1
  376. package/dist/{modes/interactive/theme → theme}/theme-controller.d.ts +1 -1
  377. package/dist/theme/theme-controller.d.ts.map +1 -0
  378. package/dist/{modes/interactive/theme → theme}/theme-controller.js +1 -1
  379. package/dist/theme/theme-controller.js.map +1 -0
  380. package/dist/{modes/interactive/theme → theme}/theme.d.ts +1 -1
  381. package/dist/theme/theme.d.ts.map +1 -0
  382. package/dist/{modes/interactive/theme → theme}/theme.js +5 -5
  383. package/dist/theme/theme.js.map +1 -0
  384. package/docs/compaction.md +7 -7
  385. package/docs/environment-variables.md +10 -4
  386. package/docs/keybindings.md +3 -3
  387. package/docs/models.md +17 -17
  388. package/docs/packages.md +1 -1
  389. package/docs/prompt-templates.md +1 -1
  390. package/docs/rpc.md +2 -2
  391. package/docs/sdk.md +5 -5
  392. package/docs/session-format.md +3 -3
  393. package/docs/settings.md +15 -1
  394. package/docs/shell-aliases.md +1 -1
  395. package/docs/skills.md +1 -1
  396. package/docs/terminal-setup.md +17 -17
  397. package/docs/themes.md +5 -5
  398. package/docs/tmux.md +4 -4
  399. package/docs/tui.md +1 -1
  400. package/docs/usage.md +292 -292
  401. package/docs/windows.md +1 -1
  402. package/examples/extensions/bash-spawn-hook/index.ts +1 -1
  403. package/examples/extensions/dynamic-resources/dynamic.json +1 -1
  404. package/examples/extensions/mcp-stdio/index.d.ts +64 -0
  405. package/examples/extensions/mcp-stdio/index.d.ts.map +1 -0
  406. package/examples/extensions/mcp-stdio/index.js +292 -0
  407. package/examples/extensions/mcp-stdio/index.js.map +1 -0
  408. package/examples/extensions/with-deps/package-lock.json +2 -2
  409. package/examples/extensions/with-deps/package.json +1 -6
  410. package/examples/extensions/with-deps/plugin.json +1 -1
  411. package/package.json +2 -2
  412. package/dist/bundle/chunks/openai-responses-AUJQ3NWT.js +0 -2
  413. package/dist/bundle/chunks/virtual-modules-MRXD3RWG.js +0 -5
  414. package/dist/cli/experimental/commands/pi.d.ts +0 -15
  415. package/dist/cli/experimental/commands/pi.d.ts.map +0 -1
  416. package/dist/cli/experimental/commands/pi.js.map +0 -1
  417. package/dist/core/export-html/ansi-to-html.d.ts.map +0 -1
  418. package/dist/core/export-html/ansi-to-html.js.map +0 -1
  419. package/dist/core/export-html/index.d.ts.map +0 -1
  420. package/dist/core/export-html/index.js.map +0 -1
  421. package/dist/core/export-html/tool-renderer.d.ts.map +0 -1
  422. package/dist/core/export-html/tool-renderer.js.map +0 -1
  423. package/dist/core/pi-manifest.d.ts +0 -7
  424. package/dist/core/pi-manifest.d.ts.map +0 -1
  425. package/dist/core/pi-manifest.js.map +0 -1
  426. package/dist/modes/interactive/model-catalog-refresh.d.ts.map +0 -1
  427. package/dist/modes/interactive/model-catalog-refresh.js.map +0 -1
  428. package/dist/modes/interactive/theme/theme-controller.d.ts.map +0 -1
  429. package/dist/modes/interactive/theme/theme-controller.js.map +0 -1
  430. package/dist/modes/interactive/theme/theme.d.ts.map +0 -1
  431. package/dist/modes/interactive/theme/theme.js.map +0 -1
  432. package/dist/profiles/builtin-suites.d.ts.map +0 -1
  433. package/dist/profiles/builtin-suites.js.map +0 -1
  434. package/dist/profiles/resolved-agent-profile.d.ts.map +0 -1
  435. package/dist/profiles/resolved-agent-profile.js.map +0 -1
  436. package/dist/profiles/suite-lifecycle.d.ts.map +0 -1
  437. package/dist/profiles/suite-lifecycle.js.map +0 -1
  438. package/dist/profiles/suite-loader.d.ts.map +0 -1
  439. package/dist/profiles/suite-loader.js.map +0 -1
  440. package/dist/utils/deprecation.d.ts +0 -4
  441. package/dist/utils/deprecation.d.ts.map +0 -1
  442. package/dist/utils/deprecation.js +0 -13
  443. package/dist/utils/deprecation.js.map +0 -1
  444. /package/dist/{core/export-html → export-html}/ansi-to-html.d.ts +0 -0
  445. /package/dist/{core/export-html → export-html}/ansi-to-html.js +0 -0
  446. /package/dist/{core/export-html → export-html}/template.css +0 -0
  447. /package/dist/{core/export-html → export-html}/template.html +0 -0
  448. /package/dist/{core/export-html → export-html}/template.js +0 -0
  449. /package/dist/{core/export-html → export-html}/tool-renderer.js +0 -0
  450. /package/dist/{core/export-html → export-html}/vendor/highlight.min.js +0 -0
  451. /package/dist/{core/export-html → export-html}/vendor/marked.min.js +0 -0
  452. /package/dist/{profiles → suites}/builtin-suites.d.ts +0 -0
  453. /package/dist/{profiles → suites}/builtin-suites.js +0 -0
  454. /package/dist/{profiles → suites}/resolved-agent-profile.d.ts +0 -0
  455. /package/dist/{profiles → suites}/resolved-agent-profile.js +0 -0
  456. /package/dist/{profiles → suites}/suite-lifecycle.d.ts +0 -0
  457. /package/dist/{profiles → suites}/suite-lifecycle.js +0 -0
  458. /package/dist/{profiles → suites}/suite-loader.d.ts +0 -0
  459. /package/dist/{profiles → suites}/suite-loader.js +0 -0
  460. /package/dist/{modes/interactive/theme → theme}/theme-schema.json +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../../src/core/sdk.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readdirSync, realpathSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n\tAgent,\n\ttype AgentMessage,\n\ttype StreamFn,\n\tsetDefaultStreamFn,\n\ttype ThinkingLevel,\n} from \"@agent-forge/agent-core\";\nimport type { CredentialStore } from \"@agent-forge/ai\";\nimport {\n\ttype Api,\n\ttype AssistantMessageEventStream,\n\ttype Context,\n\tclampThinkingLevel,\n\ttype Message,\n\ttype Model,\n\ttype SimpleStreamOptions,\n\tstreamSimple,\n} from \"@agent-forge/ai/compat\";\nimport type { MemoryModeV1, MemoryStorageComponentsV1 } from \"@agent-forge/plugin-sdk\";\nimport { createSubagentMailbox, type SubagentMailboxV1 } from \"@agent-forge/protocol/subagent\";\nimport { satisfies } from \"semver\";\nimport { BUILTIN_CAPABILITY_PACKAGE_IDS } from \"../capabilities/builtin.ts\";\nimport { isValidThinkingLevel } from \"../cli/args.ts\";\nimport { CONFIG_DIR_NAME, getAgentDir, VERSION } from \"../config.ts\";\nimport type { DurableServiceV1 } from \"../durable/durable-service.ts\";\nimport type { HostFactsV1 } from \"../plugins/ecosystem/types.ts\";\nimport type {\n\tObservabilityHostAdapterV1,\n\tObservabilityPluginFacadeV1,\n\tTraceSinkOptionsV1,\n} from \"../plugins/observability-types.ts\";\nimport { profileIdentitiesCompatible } from \"../profile/identity.ts\";\nimport type {\n\tBuiltinPluginManifestOverridesV1,\n\tBuiltinPluginProfileIdV1,\n\tBuiltinPluginProfileResolutionV1,\n} from \"../profile/plugin-profiles.ts\";\nimport type { VerifiedToolPluginV1 } from \"../profile/profile-assembly.ts\";\nimport { buildResolvedAgentProfileV1, type ResolvedAgentProfileV1 } from \"../profiles/resolved-agent-profile.ts\";\nimport {\n\tcreateSuiteAssembly,\n\tdecideSuiteCapabilityPlugin,\n\tfilterSuiteSkills,\n\treadSessionSuiteBinding,\n\tresolveSuiteId,\n\tSUITE_ENV_VAR,\n\tSUITE_SESSION_ENTRY_TYPE,\n\tSuiteRebindError,\n\tsuiteDanglingPluginAssociations,\n} from \"../profiles/suite-loader.ts\";\nimport { resolvePath } from \"../utils/paths.ts\";\nimport { AgentSession } from \"./agent-session.ts\";\nimport { type CreateAgentSessionRuntimeFactory, createAgentSessionRuntime } from \"./agent-session-runtime.ts\";\nimport { listAgentSessions, readAgentSession } from \"./agent-session-store.ts\";\nimport { formatNoModelsAvailableMessage } from \"./auth-guidance.ts\";\nimport { DEFAULT_THINKING_LEVEL } from \"./defaults.ts\";\nimport type { AgentTaskSettledEventDataV1 } from \"./extensions/bootstrap-lifecycle.ts\";\nimport { discoverCapabilityPluginManifests, parseCapabilityPluginManifest } from \"./extensions/capability-plugin.ts\";\nimport { resolvePluginCapabilityOrder } from \"./extensions/capability-runtime.ts\";\nimport { isPluginConfigValue } from \"./extensions/capability-runtime-manifest.ts\";\nimport type { TraceServiceV1 } from \"./extensions/capability-runtime-types.ts\";\nimport type {\n\tAgentCompositionAPI,\n\tAgentTaskAdapter,\n\tAgentTaskSessionSummaryV1,\n\tInteractionHostV1,\n\tLoggerRecord,\n\tPluginConfig,\n\tPluginManifest,\n\tPluginRejection,\n\tSessionAPI,\n} from \"./extensions/index.ts\";\nimport type { SubagentCommunicationWiringV1 } from \"./extensions/public-api.ts\";\nimport { type CodingAgentFacadeV1, createCodingAgentFacade } from \"./facade/coding-agent-facade.ts\";\nimport {\n\ttype CodingAgentRuntimeFacadeV1,\n\tcreateCodingAgentRuntimeFacade,\n} from \"./facade/coding-agent-runtime-facade.ts\";\nimport { t } from \"./i18n/index.ts\";\nimport type { HostLogger } from \"./logger.ts\";\nimport { convertToLlm } from \"./messages.ts\";\nimport { findExactModelReferenceMatch, findInitialModel } from \"./model-resolver.ts\";\nimport { ModelRuntime } from \"./model-runtime.ts\";\nimport type { ResourceLoader } from \"./resource-loader.ts\";\nimport { DefaultResourceLoader } from \"./resource-loader.ts\";\nimport { getDefaultSessionDir, getTraceFilePathForSession, SessionManager } from \"./session-manager.ts\";\nimport type { SessionStartMetadata } from \"./session-start.ts\";\nimport { SettingsManager } from \"./settings-manager.ts\";\nimport type { Skill } from \"./skills.ts\";\nimport { time } from \"./timings.ts\";\nimport type { ToolName } from \"./tools/index.ts\";\nimport type { ToolDefinition } from \"./tools/tool-definition.ts\";\n\n// Preserve the pre-0.81 fallback for extensions that construct Agent instances\n// or invoke low-level agent loops without supplying streamFn. Agent core remains\n// provider-agnostic and does not import pi-ai/compat itself.\nsetDefaultStreamFn(streamSimple);\n\n/**\n * One background-delegation settlement line as written by the delegate's\n * settlement observer (subagent-delegate.ts): bounded JSON whose `sessionId`\n * is the CHILD session id — the parent session id is supplied by the dispatch\n * side (AgentSession), so the line field maps to the event's `taskSessionId`.\n */\ninterface AgentTaskSettledDigestFactsV1 {\n\ttaskId: string;\n\ttaskSessionId: string;\n\tstatus: AgentTaskSettledEventDataV1[\"status\"];\n\treasonCode?: string;\n}\n\nconst AGENT_TASK_SETTLED_STATUSES: ReadonlySet<string> = new Set([\n\t\"queued\",\n\t\"admitted\",\n\t\"running\",\n\t\"succeeded\",\n\t\"failed\",\n\t\"cancelled\",\n\t\"timed_out\",\n\t\"drain_timeout\",\n\t\"runner_lost\",\n]);\n\n/** Parses one settlement line; undefined for any shape outside the contract. */\nfunction parseAgentTaskSettledDigestLine(line: string): AgentTaskSettledDigestFactsV1 | undefined {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(line);\n\t} catch {\n\t\treturn undefined;\n\t}\n\tif (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) return undefined;\n\tconst record = parsed as Record<string, unknown>;\n\tif (typeof record.taskId !== \"string\" || record.taskId === \"\") return undefined;\n\tif (typeof record.sessionId !== \"string\" || record.sessionId === \"\") return undefined;\n\tif (typeof record.status !== \"string\" || !AGENT_TASK_SETTLED_STATUSES.has(record.status)) return undefined;\n\tif (record.reasonCode !== undefined && (typeof record.reasonCode !== \"string\" || record.reasonCode === \"\")) {\n\t\treturn undefined;\n\t}\n\treturn {\n\t\ttaskId: record.taskId,\n\t\t// 行内 sessionId 是子会话 id(复审 M1):映射为事件 data 的 taskSessionId。\n\t\ttaskSessionId: record.sessionId,\n\t\tstatus: record.status as AgentTaskSettledEventDataV1[\"status\"],\n\t\t...(record.reasonCode === undefined ? {} : { reasonCode: record.reasonCode }),\n\t};\n}\n\n/**\n * 后台委派结算行 → agent.task.settled@1 派发(第 4 期轨迹闭合),并返回解析出的\n * facts 供调用方复用(结算回注构造,D-060 裁决 12——同一行不再二次 parse)。行解析\n * 失败或 status 不属九值枚举时降级为仅 hostLogger warn 并返回 undefined。\n * 会话缺席(agentSessionRef.current 在会话创建前为 undefined)或已 dispose(旧 runtime revokeState →\n * hasLifecycleEvent false → 派发助手 no-op)时安全跳过(facts 仍返回,调用方自行守卫)。\n */\nexport function deliverAgentTaskSettledDigestLine(\n\tsession: Pick<AgentSession, \"dispatchAgentTaskSettled\"> | undefined,\n\tline: string,\n\thostLogger?: HostLogger,\n): AgentTaskSettledDigestFactsV1 | undefined {\n\tconst facts = parseAgentTaskSettledDigestLine(line);\n\tif (facts === undefined) {\n\t\thostLogger?.warn(\"sdk\", \"background delegation settlement line is not a valid agent.task.settled source\", {\n\t\t\tcause: line,\n\t\t});\n\t\treturn undefined;\n\t}\n\tsession?.dispatchAgentTaskSettled(facts);\n\treturn facts;\n}\n\n/** One verified active installation participating in installed-code-loading (D-075 S2). */\nexport interface InstalledCapabilityPluginV1 {\n\treadonly pluginId: string;\n\treadonly manifestPath: string;\n}\n\n/**\n * Plugin id of the standalone observability package (D-075 S4 second batch).\n * When `traceEnabled` is not `false`, the assembler adds it to the installed\n * plugin membership set so the installed package joins the session through\n * the same loading path as every other plugin package.\n */\nconst OBSERVABILITY_PACKAGE_ID = \"agent-forge.plugin.observability\";\n\n/**\n * Plugin id of the standalone subagent-delegate package (D-075 S4 third\n * batch). When `subagentPoolFromSelfInvocation` is true (the real CLI\n * assembly declaring its own process entry trustworthy), the assembler\n * overrides the plugin's manifest config with `runnerEntryAuto: true` at load\n * — the config key the package's auto-pooling path consumes (the former host\n * `selfInvocationPool` option is retired). The agent-dir config file still\n * merges over it inside the plugin entry, so users keep the final say.\n */\nconst SUBAGENT_DELEGATE_PACKAGE_ID = \"agent-forge.plugin.subagent-delegate\";\n\n/**\n * Plugin id of the standalone memory package (D-075 S4 fourth batch). When the\n * suite declares `builtin.memory` and the resolved memory mode is light/full,\n * the assembler adds the package to the installed-plugin membership set and\n * overrides its manifest config with `memoryMode`/`memorySettingsMode` at load\n * — the config keys the package's entry resolves with the exact precedence\n * the embedded capability used to have (explicit host option → env →\n * settings.json → legacy alias → off). Mode off keeps the package out of the\n * membership set entirely (禁用 = 不装配, plus one startup diagnostic).\n */\nconst MEMORY_PACKAGE_ID = \"agent-forge.plugin.memory\";\n\n/**\n * Plugin id of the standalone image-generation package (供应商能力槽位设计\n * §3.3 装配注入): at load the assembler overrides its manifest config with the\n * settings slot (`capabilities.imageGeneration`, validated fail-closed by\n * `SettingsManager.getCapabilitiesSettings()`) plus the models.json image-model\n * catalog snapshot (`imageModelCatalog`, projected by\n * `ModelRuntime.getImageModelCatalog()`) — the exact config keys the package's\n * capability reads (`api.config.imageGeneration` / `api.config.imageModelCatalog`).\n * The agent-dir config file still merges over it inside the plugin entry, so\n * users keep the final say.\n */\nconst IMAGE_GENERATION_PACKAGE_ID = \"agent-forge.plugin.image-generation\";\n\n/**\n * Plugin id of the standalone coding-tools package (D-082 批 1, S6 工具批):\n * the default coding tools (read/write/edit/bash/powershell/grep/find/ls) live\n * in the `plugins/coding-tools` package and assemble through the bundled\n * distribution channel (§4.9) instead of the retired embedded\n * bootstrap-tools install. At load the assembler merges the\n * session facts the embedded install used to receive as direct options — the\n * working directory plus the settings-resolved read/bash options — into the\n * manifest config (`{version: 1, cwd, read, bash}`), the exact shape the\n * package's `CodingToolsPluginConfigV1` consumes. The agent-dir config file\n * still merges over it inside the plugin entry, so users keep the final say.\n */\nconst CODING_TOOLS_PACKAGE_ID = \"agent-forge.plugin.coding-tools\";\n\n/**\n * Plugin id of the provider-failover package (D-082 批 3b): the primary/backup\n * provider failover (设计 供应商能力槽位与主备切换 §4) lives in the\n * `plugins/provider-failover` package and assembles through the bundled\n * distribution channel (§4.9) instead of the retired embedded install. Unlike\n * the bundled default face it is NOT a default policy: settings `failover`\n * 节存在时宿主经 configOverride 通道注入 `{version: 1, failover: <节点原样>}`\n * (节点不存在则不注入,插件工厂自守卫 no-op)——\"配置存在即装配\"是内嵌时代\n * 语义,因此它不受 suite capabilities 声明门控(见装配豁免集合)。failover\n * wrapper 以 priority -100 注册(契约 A),无论装载顺序都在链最外层。\n */\nconst PROVIDER_FAILOVER_PACKAGE_ID = \"agent-forge.plugin.provider-failover\";\n\n/**\n * Bundled 默认面插件 id 集合(D-082 批 3):随发行物 bundled 分发、不受 suite\n * capabilities 声明门控的第一方默认插件——内嵌时代的默认工具面(coding-tools,\n * 批 1)与四个默认策略插件(agent-loop-policy / retry-policy / overflow-policy /\n * compaction-policy,批 3 退役的内嵌 installBootstrap* 安装)。disabledPluginIds\n * 仍可逐个禁用其中任何一个。\n */\nconst BUNDLED_DEFAULT_PLUGIN_IDS: ReadonlySet<string> = new Set([\n\tCODING_TOOLS_PACKAGE_ID,\n\t\"agent-forge.plugin.agent-loop-policy\",\n\t\"agent-forge.plugin.retry-policy\",\n\t\"agent-forge.plugin.overflow-policy\",\n\t\"agent-forge.plugin.compaction-policy\",\n]);\n\n/**\n * Bundled 装配豁免集合(D-082 批 3b):bundled 候选中不受 suite capabilities\n * 声明门控的插件 id——默认面({@link BUNDLED_DEFAULT_PLUGIN_IDS},五 id)加上\n * config 门控可选能力 provider-failover(第六 id,config 门控豁免而非默认策略:\n * settings `failover` 节存在即装配,与内嵌装配同语义;节点不存在时插件工厂\n * 自守卫 no-op)。disabledPluginIds 仍可禁用其中任何一个。\n */\nconst BUNDLED_WIRING_EXEMPT_PLUGIN_IDS: ReadonlySet<string> = new Set([\n\t...BUNDLED_DEFAULT_PLUGIN_IDS,\n\tPROVIDER_FAILOVER_PACKAGE_ID,\n]);\n\n/**\n * Bundled 默认策略包的目录名(plugins/ 工作副本与发行物 bundled-plugins/ 快照\n * 同名)。与 {@link BUNDLED_DEFAULT_PLUGIN_IDS} 的四个策略 id 一一对应。\n */\nconst BUNDLED_DEFAULT_POLICY_PACKAGES = [\n\t\"agent-loop-policy\",\n\t\"retry-policy\",\n\t\"overflow-policy\",\n\t\"compaction-policy\",\n] as const;\n\n/**\n * Bundled distribution roots (D-082 §4.9 bundled 分发通道):按工具面与策略面\n * 分组的插件目录,其 plugin.json 清单加入候选池。两组各自探测两种布局,目录\n * 不存在即跳过:\n *\n * - Released form: the build copies built plugin packages to\n * `<packageRoot>/bundled-plugins/<name>/` (data files, not npm deps).\n * - Dev repository form: the repo-root working copies of the packages this\n * batch migrated (`<repoRoot>/plugins/coding-tools` — 批 1;四个策略包 — 批 3;\n * provider-failover — 批 3b).\n * Sibling first-party packages keep their install-store assembly (D-075\n * S4/S5 semantics, pinned by the ecosystem assembly tests) until their own\n * migration batch (S7-S9) widens this root.\n *\n * 工具面(coding-tools)受 noTools 整层跳过(对照内嵌工具装配的跳过语义);\n * 策略面不受 noTools 门控——内嵌 installBootstrap* 时代它们随会话无条件安装。\n *\n * The package root is derived from this module's URL: src runs sit at\n * `src/core/`, unbundled dist runs at `dist/core/` (both two levels up), and\n * the Node bundle runs at `dist/bundle/` (three levels up). Depth candidates\n * are tried in order and the first ancestor carrying a `package.json` wins.\n */\nfunction bundledCapabilityPluginRoots(): { toolRoots: string[]; policyRoots: string[] } {\n\tconst moduleDir = fileURLToPath(new URL(\".\", import.meta.url));\n\tlet packageRoot: string | undefined;\n\tfor (const depth of [2, 3]) {\n\t\tlet candidate = moduleDir;\n\t\tfor (let index = 0; index < depth; index++) candidate = dirname(candidate);\n\t\tif (existsSync(join(candidate, \"package.json\"))) {\n\t\t\tpackageRoot = candidate;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (packageRoot === undefined) return { toolRoots: [], policyRoots: [] };\n\tconst toolRoots: string[] = [];\n\tconst policyRoots: string[] = [];\n\t// Dev repository layout first: the repo-root plugins/ working copies (two\n\t// levels above the package root; exist only inside a source checkout).\n\t// When both roots exist the fresh working copy must win — the bundled copy\n\t// is a build-time snapshot that lags plugin src until the next root build,\n\t// and letting it shadow the working copy would silently run stale tool\n\t// code in dev (review finding, D-082 批 1). check:plugin-dist-fresh pins\n\t// the two copies content-identical so a stale bundled snapshot fails the\n\t// gate instead of passing unnoticed.\n\tconst devPluginsRoot = join(packageRoot, \"..\", \"..\", \"plugins\");\n\ttoolRoots.push(join(devPluginsRoot, \"coding-tools\"));\n\tfor (const name of BUNDLED_DEFAULT_POLICY_PACKAGES) policyRoots.push(join(devPluginsRoot, name));\n\t// provider-failover(D-082 批 3b):config 门控可选能力,随策略面根分发\n\t// (不受 noTools 门控,与内嵌装配同语义)。\n\tpolicyRoots.push(join(devPluginsRoot, \"provider-failover\"));\n\tconst bundledRoot = join(packageRoot, \"bundled-plugins\");\n\ttoolRoots.push(join(bundledRoot, \"coding-tools\"));\n\tfor (const name of BUNDLED_DEFAULT_POLICY_PACKAGES) policyRoots.push(join(bundledRoot, name));\n\tpolicyRoots.push(join(bundledRoot, \"provider-failover\"));\n\treturn { toolRoots, policyRoots };\n}\n\n/**\n * memory.mode 解析(2.4d6 S1,D-075 S4 第四批宿主收口后 sdk 内联): 显式值 →\n * env `AGENT_FORGE_MEMORY_MODE` → settings.json `memory.mode`(settingsMode 携\n * 带)→ 旧别名 `AGENT_FORGE_MEMORY_VECTOR`(兼容期)→ off。与包内\n * `resolveMemoryMode`(plugin-sdk/插件包面)语义逐点一致;宿主不依赖插件包源,\n * 非法值 fail-closed 回 off 并携带原值供一次性诊断。诊断文案由 builtin 时代\n * 逐字迁移(capabilities-builtin.test.ts / memory-mode-gating.test.ts pin)。\n */\ninterface SdkMemoryModeResolution {\n\treadonly mode: MemoryModeV1;\n\treadonly invalidEnvValue?: string;\n\treadonly invalidSettingsValue?: string;\n}\n\nconst isMemoryModeV1 = (value: string): value is MemoryModeV1 =>\n\tvalue === \"off\" || value === \"light\" || value === \"full\";\n\nfunction resolveSdkMemoryMode(\n\texplicitMode: string | undefined,\n\tenv: Readonly<Record<string, string | undefined>>,\n\tsettingsMode?: string,\n): SdkMemoryModeResolution {\n\tif (explicitMode !== undefined) {\n\t\tif (isMemoryModeV1(explicitMode)) return { mode: explicitMode };\n\t\treturn { mode: \"off\", invalidEnvValue: explicitMode };\n\t}\n\tconst configured = env.AGENT_FORGE_MEMORY_MODE?.trim().toLowerCase();\n\tif (configured !== undefined && configured !== \"\") {\n\t\tif (isMemoryModeV1(configured)) return { mode: configured };\n\t\treturn { mode: \"off\", invalidEnvValue: configured };\n\t}\n\tconst fromSettings = settingsMode?.trim().toLowerCase();\n\tif (fromSettings !== undefined && fromSettings !== \"\") {\n\t\tif (isMemoryModeV1(fromSettings)) return { mode: fromSettings };\n\t\treturn { mode: \"off\", invalidSettingsValue: fromSettings };\n\t}\n\tconst legacy = env.AGENT_FORGE_MEMORY_VECTOR?.trim().toLowerCase();\n\tif (legacy !== undefined && legacy !== \"\") {\n\t\tif (isMemoryModeV1(legacy)) return { mode: legacy };\n\t\treturn { mode: \"off\", invalidEnvValue: legacy };\n\t}\n\treturn { mode: \"off\" };\n}\n\nexport interface CreateAgentSessionOptions {\n\t/** Working directory for project-local discovery. Default: process.cwd() */\n\tcwd?: string;\n\t/** Global config directory. Default: ~/.agent-forge/agent */\n\tagentDir?: string;\n\t/**\n\t * Explicit suite/profile migration on resume (CRM seat finding F1/F2):\n\t * adopt the currently resolved suite + profile identity even when the\n\t * session's recorded binding no longer matches (e.g. a plugin was\n\t * installed after the conversation started), rewrite the binding entry,\n\t * and continue. Without it the drift guard keeps rejecting the resume.\n\t */\n\tallowSuiteRebind?: boolean;\n\n\t/** Canonical model/auth runtime. Defaults to a runtime using agentDir/auth.json and models.json. */\n\tmodelRuntime?: ModelRuntime;\n\t/**\n\t * Credential storage used by the default model runtime (D-067 phase 1):\n\t * forwarded to `ModelRuntime.create` when `modelRuntime` is omitted.\n\t * Ignored when an explicit `modelRuntime` is supplied. Defaults to the\n\t * file at `<agentDir>/auth.json`.\n\t */\n\tcredentials?: CredentialStore;\n\t/** Explicit model stream function for deterministic hosts and mock providers. */\n\tstreamFn?: StreamFn;\n\n\t/** Model to use. Default: from settings, else first available */\n\tmodel?: Model<Api>;\n\t/** Thinking level. Default: from settings, else 'medium' (clamped to model capabilities) */\n\tthinkingLevel?: ThinkingLevel;\n\t/** Models available for cycling (Ctrl+P in interactive mode) */\n\tscopedModels?: Array<{ model: Model<Api>; thinkingLevel?: ThinkingLevel }>;\n\n\t/**\n\t * Optional default tool suppression mode when no explicit allowlist is provided.\n\t *\n\t * - \"all\": start with no tools enabled\n\t * - \"builtin\": disable the default built-in tools (read, bash, edit, write)\n\t * but keep extension/custom tools enabled\n\t */\n\tnoTools?: \"all\" | \"builtin\";\n\t/**\n\t * Optional allowlist of tool names.\n\t *\n\t * When omitted (and `noTools` is not set) in the default full-control mode,\n\t * the active suite's declared `tools` are the initial selection (设计 §5);\n\t * readonly mode starts from the read-only base face, where the\n\t * `defaultTools` setting still applies when configured. When provided, only\n\t * the listed tool names are enabled.\n\t */\n\ttools?: string[];\n\t/** Optional denylist of tool names to disable. Applies after `tools` when both are provided. */\n\texcludeTools?: string[];\n\t/**\n\t * Plugin ids whose tools register normally but stay out of the default\n\t * active (prompt-visible) set; the built-in tool_search tool discovers and\n\t * activates them on demand. createAgentSessionFromServices forwards the\n\t * MCP pool's `deferredTools: true` server ids here. Explicit activation\n\t * (allowlist or setActiveTools) overrides the deferral.\n\t */\n\tdeferredToolPluginIds?: readonly string[];\n\t/** Custom tools to register (in addition to built-in tools). */\n\tcustomTools?: ToolDefinition[];\n\n\t/** Resource loader. When omitted, DefaultResourceLoader is used. */\n\tresourceLoader?: ResourceLoader;\n\n\t/** Session manager. Default: SessionManager.create(cwd) */\n\tsessionManager?: SessionManager;\n\n\t/** Settings manager. Default: SettingsManager.create(cwd, agentDir) */\n\tsettingsManager?: SettingsManager;\n\t/** Session start metadata dispatched to the capability lifecycle on session start. */\n\tsessionStartEvent?: SessionStartMetadata;\n\t/** Core capability mode. Defaults to \"full-control\". */\n\tcapabilityMode?: \"readonly\" | \"full-control\";\n\t/**\n\t * Discover plugin manifests recursively below `<agentDir>/plugins` and\n\t * `<cwd>/.agent-forge/plugins`. Defaults to true.\n\t */\n\tdiscoverCapabilityPlugins?: boolean;\n\t/**\n\t * Additional capability plugin manifest paths. They load after discovered\n\t * manifests; duplicate plugin IDs are an explicit startup error. Explicit\n\t * paths are caller intent: they bypass the suite's `associations.plugins`\n\t * filtering (方案系统 M3) and load regardless of the active suite.\n\t */\n\tcapabilityPluginPaths?: string[];\n\t/**\n\t * Installed capability plugins from the host's active-install store\n\t * (D-075 S2 installed-code-loading): each entry pairs a verified active\n\t * plugin id with its installation directory's plugin.json path. Only\n\t * entries whose plugin id is a member of the resolved plugin profile\n\t * (selected and not disabled) enter the candidate pool, as explicit\n\t * candidates like `capabilityPluginPaths`; non-members stay unloaded with\n\t * one suite diagnostic.\n\t */\n\tinstalledCapabilityPlugins?: readonly InstalledCapabilityPluginV1[];\n\t/**\n\t * Per-plugin manifest config overrides keyed by plugin id (D-082 批 1):\n\t * when the assembler loads a manifest whose id has an entry here, the value\n\t * merges into that plugin's `configOverride` — host-injected assembly facts\n\t * first, these values win per top-level key, and the plugin-side agent-dir\n\t * config file still merges above everything inside the plugin entry.\n\t */\n\tcapabilityPluginConfigs?: Record<string, PluginConfig>;\n\t/** Optional host-owned AgentDefinition/AgentInstance composition facade. */\n\tagentComposition?: AgentCompositionAPI;\n\t/** Optional host adapter for cancellable interaction tasks (interaction capability). */\n\tinteractionHost?: InteractionHostV1;\n\t/**\n\t * Suite (方案) id for workspace and context assembly. When omitted, resolved\n\t * via AGENT_FORGE_SUITE, then project settings `suite`, then global settings\n\t * `suite`, then the builtin default \"coding\".\n\t */\n\tsuite?: string;\n\t/** Optional context strategy supplied by a capability plugin. */\n\tcontextStrategyName?: string;\n\t/** Optional retry policy supplied by a capability plugin. */\n\tretryPolicyName?: string;\n\t/** Optional automatic compaction policy supplied by a capability plugin. */\n\tcompactionPolicyName?: string;\n\t/** Optional provider overflow policy supplied by a capability plugin. */\n\toverflowPolicyName?: string;\n\tbranchSummaryPolicyName?: string;\n\t/** Optional post-run continuation strategy supplied by a capability plugin. */\n\trunLoopStrategyName?: string;\n\t/**\n\t * 关闭本会话的委派/回读面(agents 能力整体缺席):`subagent_run` 等工具不注册,\n\t * reader/lister 也不注入。默认开启;委派承载由 `agentTaskAdapter`(宿主自带)或\n\t * `subagentPoolFromSelfInvocation`(CLI 自动池化)决定,二者都不在时委派面不注册。\n\t */\n\tenableAgentTasks?: boolean;\n\t/**\n\t * Host-injected adapter(承载退役后唯一的手工承载入口):池化 runner adapter 或\n\t * 宿主自定义实现。装配域自身不再提供默认子任务 creator(shared 递归装配已随\n\t * 承载退役删除);嵌套委派由 runner 叶子的自动池化承载,递归边界在 delegate\n\t * 的深度/总量硬限。`enableAgentTasks` 为 false 时忽略。\n\t */\n\tagentTaskAdapter?: AgentTaskAdapter;\n\t/**\n\t * 承载退役切片 1(生产 CLI 默认 pooled):宿主声明\"本进程的自身入口可信\"。\n\t * 仅真实 CLI 装配传 true——delegate 在未显式配置池且 self-invocation 可解析时\n\t * 自动池化。SDK 嵌入方与测试不传,行为不变。\n\t */\n\tsubagentPoolFromSelfInvocation?: boolean;\n\t/**\n\t * Subagent communication wiring (D-060 S4): host-bound mailbox closures for the\n\t * subagent-delegate capability. The parent assembly builds its own drain wiring\n\t * internally; child assemblies receive the post/drainInbox wiring with the child\n\t * identity bound by the parent scope. Absent = the communication tools never\n\t * register (the config flags are necessary but the wiring is the channel).\n\t */\n\tsubagentCommunicationWiring?: SubagentCommunicationWiringV1;\n\t/**\n\t * Durable replay channel for agent task terminal outcomes (agent-result-replay-v1).\n\t * Requires the agents capability (only pass it when `enableAgentTasks` is not\n\t * false); the runtime guard pair rejects a replay option without the feature.\n\t * Serve hosts inject `{ store, writerId }` here; child sessions never\n\t * inherit it.\n\t */\n\tagentTaskResults?: {\n\t\treadonly store: DurableServiceV1;\n\t\treadonly writerId: string;\n\t};\n\t/**\n\t * Wire the suite's capability surface (方案系统 M3): the `capabilities`\n\t * whitelist loads the embedded builtin plugins, the external plugin pool\n\t * is filtered by `associations.plugins`, and the legacy plugin skill face\n\t * is filtered by `associations.skills`. Default: on when this call builds\n\t * its own resource loader, off when the caller brings one (the M1a/M1b\n\t * assembly boundary); callers with their own loader can opt in explicitly.\n\t */\n\tsuiteCapabilityWiring?: boolean;\n\t/** Optional domain plugin profile selected for the active suite. */\n\tpluginProfileId?: BuiltinPluginProfileIdV1;\n\t/** Optional subset of plugins from the selected builtin Profile. */\n\tselectedPluginIds?: readonly string[];\n\t/** Optional plugin IDs disabled within the selected builtin Profile. */\n\tdisabledPluginIds?: readonly string[];\n\tpluginHost?: HostFactsV1;\n\tverifiedPlugins?: readonly VerifiedToolPluginV1[];\n\t/** Explicit host-owned active installed manifests; never discovered implicitly. */\n\tmanifestOverrides?: BuiltinPluginManifestOverridesV1;\n\tpluginProfile?: BuiltinPluginProfileResolutionV1;\n\t/**\n\t * Session trace collection (设计 §4.4/§6). When not `false`, the assembler\n\t * registers the first-party `agent-forge.observability` plugin so every\n\t * session carries a `.trace.jsonl` file next to its session file. Default:\n\t * `true`; `--no-trace` maps to `false` on the CLI.\n\t */\n\ttraceEnabled?: boolean;\n\t/**\n\t * Trace-sink budget overrides (设计 §6 控制面):forwarded to the first-party\n\t * observability plugin's snapshot serializer. Defaults when omitted:\n\t * 16 000 chars per string, 384 KiB per serialized snapshot\n\t * (TraceSinkOptionsV1). Consumed by the trace sink registered through\n\t * `traceEnabled`; only meaningful while tracing is on.\n\t */\n\ttraceOptions?: TraceSinkOptionsV1;\n\t/**\n\t * Host-process logger for runtime diagnostics (设计 §5). Absent = the SDK\n\t * embedder opted out of process logging; this is an explicit contract, not\n\t * a default — every instrumentation point behind it is a no-op then.\n\t */\n\thostLogger?: HostLogger;\n\t/**\n\t * 记忆全局档位与底层组件注入(2.4d6 S1 / 扩展位盘点 A1/A2,D-075 S4 第四批\n\t * 拆包后形态):显式定档最优先,缺省走解析链(env `AGENT_FORGE_MEMORY_MODE`\n\t * → settings.json `memory.mode` → 旧别名 → off);off 时 memory 插件包不进\n\t * 装配成员资格(零工具零命令零事件),启动诊断带一行声明。`storage`(store/\n\t * ledger 工厂与向量组件公共契约)经公共 HostCapabilities\n\t * (`api.host.memoryStorage`) 注入安装店的 memory 插件包;缺省成员 = 包内默认\n\t * 实现。测试专用向量注入面经 `storage.vectorComponents` 携带(原顶层\n\t * `vectorComponents` 字段随内嵌装配退役)。\n\t */\n\tmemoryCapability?: {\n\t\treadonly mode?: MemoryModeV1;\n\t\t/**\n\t\t * 记忆底层组件注入(扩展位盘点 A1/A2):store/ledger 工厂与向量组件公共\n\t\t * 契约,经 HostCapabilities.memoryStorage 原样透传给 memory 插件包;缺省\n\t\t * 任一成员 = 包内默认实现,默认行为零变化。\n\t\t */\n\t\treadonly storage?: MemoryStorageComponentsV1;\n\t};\n}\n\n/**\n * 子代理 headless 交互宿主(D-044 §5.5):child 会话无宿主 UI,interaction 请求\n * 落回冻结 InteractionOutcomeV1 语义——prompt 返回 \"unavailable\"(宿主无 UI),\n * signal 已中止返回 \"cancelled\";notify 为 fire-and-forget 空操作(语义 delivered)。\n */\nexport const HEADLESS_INTERACTION_HOST: InteractionHostV1 = {\n\tnotify: () => {},\n\tprompt: async (_request, context) => {\n\t\tif (context.signal.aborted) return { status: \"cancelled\" };\n\t\treturn { status: \"unavailable\" };\n\t},\n};\n\n/** Result from createAgentSession */\nexport interface CreateAgentSessionResult {\n\t/** The created session */\n\tsession: AgentSession;\n\t/** Warning if session was restored with a different model than saved */\n\tmodelFallbackMessage?: string;\n\t/**\n\t * Capability plugins rejected during startup without blocking the session\n\t * (D-028). Empty when every discovered/explicit plugin loaded. Combination-level\n\t * conflicts (duplicate capability identity, dependency cycles) still fail\n\t * session creation outright.\n\t */\n\tpluginRejections: readonly PluginRejection[];\n\t/**\n\t * Suite assembly diagnostics (suite.json corruption fallbacks, blocked\n\t * system agents.md layer hints, association counts). Empty when suite\n\t * assembly found nothing to report.\n\t */\n\tsuiteDiagnostics: readonly string[];\n\t/** Optional domain plugin profile resolution for UI and diagnostics. */\n\tpluginProfile?: BuiltinPluginProfileResolutionV1;\n\t/**\n\t * The immutable per-session aggregate view over the resolved suite profile\n\t * (D-047 S4a): identity, lock verification, plugin profile summary, and\n\t * workspace path projection — a deep-frozen view of the existing\n\t * authoritative sources, not a new generation mechanism. AgentSession stays\n\t * suite-unaware: the aggregate rides this creation result only, never\n\t * AgentSessionConfig.\n\t */\n\tresolvedAgentProfile?: ResolvedAgentProfileV1;\n}\n\n// Re-exports\n\nexport * from \"./agent-session-runtime.ts\";\nexport type { PluginRejection } from \"./extensions/index.ts\";\nexport type { PromptTemplate } from \"./prompt-templates.ts\";\nexport type { Skill } from \"./skills.ts\";\nexport type { SlashCommandInfo, SlashCommandSource } from \"./slash-commands.ts\";\nexport type { Tool } from \"./tools/index.ts\";\nexport { withFileMutationQueue } from \"./tools/index.ts\";\nexport type { ToolDefinition, ToolInfo, ToolRenderContext, ToolRenderResultOptions } from \"./tools/tool-definition.ts\";\n\n// Helper Functions\n\nfunction getDefaultAgentDir(): string {\n\treturn getAgentDir();\n}\n\nasync function readCapabilityPluginManifestForOrdering(manifestPath: string): Promise<PluginManifest> {\n\tlet raw: unknown;\n\ttry {\n\t\traw = JSON.parse(await readFile(manifestPath, \"utf8\"));\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\tt(\"Failed to read capability plugin manifest {path}: {reason}\", {\n\t\t\t\tpath: manifestPath,\n\t\t\t\treason: error instanceof Error ? error.message : String(error),\n\t\t\t}),\n\t\t);\n\t}\n\treturn parseCapabilityPluginManifest(raw, manifestPath);\n}\n\n/**\n * Create an AgentSession with the specified options.\n *\n * @example\n * ```typescript\n * // Minimal - uses defaults\n * const { session } = await createAgentSession();\n *\n * // With explicit model\n * import { getModel } from '@agent-forge/ai';\n * const { session } = await createAgentSession({\n * model: getModel('anthropic', 'claude-opus-4-5'),\n * thinkingLevel: 'high',\n * });\n *\n * // Continue previous session\n * const { session, modelFallbackMessage } = await createAgentSession({\n * continueSession: true,\n * });\n *\n * // Full control\n * const loader = new DefaultResourceLoader({\n * cwd: process.cwd(),\n * agentDir: getAgentDir(),\n * settingsManager: SettingsManager.create(),\n * });\n * await loader.reload();\n * const { session } = await createAgentSession({\n * model: myModel,\n * tools: [\"read\", \"bash\"],\n * resourceLoader: loader,\n * sessionManager: SessionManager.inMemory(),\n * });\n * ```\n */\nexport async function createAgentSession(options: CreateAgentSessionOptions = {}): Promise<CreateAgentSessionResult> {\n\tconst cwd = resolvePath(options.cwd ?? options.sessionManager?.getCwd() ?? process.cwd());\n\tconst agentDir = options.agentDir ? resolvePath(options.agentDir) : getDefaultAgentDir();\n\tlet resourceLoader = options.resourceLoader;\n\n\tconst authPath = options.agentDir ? join(agentDir, \"auth.json\") : undefined;\n\tconst modelsPath = options.agentDir ? join(agentDir, \"models.json\") : undefined;\n\tconst modelRuntime =\n\t\toptions.modelRuntime ?? (await ModelRuntime.create({ authPath, modelsPath, credentials: options.credentials }));\n\n\tconst settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n\n\t// Suite assembly (方案系统 M1a/M2): resolve the active suite and build the\n\t// shared assembly (workspace + loader overrides + diagnostics channel).\n\t// The inherit switch also gates the global agentDir SYSTEM.md/\n\t// APPEND_SYSTEM.md prompt channel (设计 §8: it governs the whole system\n\t// layer). Unknown ids fail here with a structured error listing the\n\t// available suites. The loader overrides below are applied only when this\n\t// call builds its own DefaultResourceLoader; callers that bring their own\n\t// resourceLoader keep the M1a bypass boundary (unchanged).\n\tconst suiteId = resolveSuiteId({\n\t\texplicit: options.suite,\n\t\tenvSuite: process.env[SUITE_ENV_VAR],\n\t\tsettings: settingsManager,\n\t\tagentDir,\n\t});\n\tconst suiteAssembly = createSuiteAssembly({\n\t\tcwd,\n\t\tagentDir,\n\t\tsuiteId,\n\t\tpluginProfileId: options.pluginProfileId,\n\t\tselectedPluginIds: options.selectedPluginIds,\n\t\tdisabledPluginIds: options.disabledPluginIds,\n\t\tpluginHost: options.pluginHost,\n\t\tverifiedPlugins: options.verifiedPlugins,\n\t\tmanifestOverrides: options.manifestOverrides,\n\t\tpluginProfile: options.pluginProfile,\n\t});\n\tconst suiteWorkspace = suiteAssembly.workspace;\n\n\t// ResolvedAgentProfile (D-047 S4a): one deep-frozen aggregate view over the\n\t// resolved suite per session, built once at the existing single resolution\n\t// point right after suite assembly. Pure projection of the authoritative\n\t// sources above (identity, lock verification, plugin profile, workspace\n\t// paths) — no new generation mechanism; AgentSession stays suite-unaware.\n\tconst resolvedAgentProfile = buildResolvedAgentProfileV1({\n\t\tsuiteId,\n\t\tworkspace: suiteWorkspace,\n\t\t...(suiteAssembly.pluginProfile === undefined ? {} : { pluginProfile: suiteAssembly.pluginProfile }),\n\t});\n\n\t// Capability wiring (方案系统 M3): resolve the suite's `capabilities`\n\t// short ids onto the builtin family mapping (every short id assembles from\n\t// its independent plugin package; unknown ids surface as dangling\n\t// diagnostics, never as errors — 决策记录 §8) and prepare the external\n\t// pool / legacy skill association filters. Follows the M1a/M1b assembly\n\t// boundary: wiring is on when this call builds its own loader and off for\n\t// callers that bring one unless they opt in explicitly.\n\tconst capabilityWiring = options.suiteCapabilityWiring ?? !options.resourceLoader;\n\tconst capabilityDiagnostics: string[] = [];\n\t// Suite preference diagnostics (统一修复轮 B): unresolvable suite.model /\n\t// suite.thinking declarations surface here instead of failing startup.\n\tconst suitePreferenceDiagnostics: string[] = [];\n\tlet capabilitySkillsFilter: ((skills: Skill[]) => Skill[]) | undefined;\n\t// 子代理通信面(D-060 S4/S5):每个装配域自持**一个**信箱(本会话的子代理们向它\n\t// post escalation/兄弟消息,本会话的 delegate drain)。嵌套委派时,子装配域的信箱\n\t// 由父侧 creator 构造并经 `subagentMailbox` 注入,保证 post 目标与 drain 来源同一\n\t// 实例;post-up(向自己的父)接线经 `subagentCommunicationWiring` 注入,两者合并。\n\tlet communicationMailbox: SubagentMailboxV1 | undefined;\n\tconst selfMailbox = (): SubagentMailboxV1 => {\n\t\tcommunicationMailbox ??= createSubagentMailbox({\n\t\t\tagentDir,\n\t\t\townerParentSessionId: () => agentSessionRef.current?.sessionId,\n\t\t});\n\t\treturn communicationMailbox;\n\t};\n\tconst communicationWiring: SubagentCommunicationWiringV1 | undefined =\n\t\toptions.enableAgentTasks === false && options.subagentCommunicationWiring === undefined\n\t\t\t? undefined\n\t\t\t: {\n\t\t\t\t\tdrainEscalations: (sessionId: string) => selfMailbox().drainEscalations(sessionId),\n\t\t\t\t\t// 父侧只读的兄弟流量摘录(D-060 裁决 14 父可见性):随验收信封对父可见。\n\t\t\t\t\treadSiblingTraffic: (sessionId: string, limit: number) =>\n\t\t\t\t\t\tselfMailbox().readSiblingTraffic(sessionId, limit),\n\t\t\t\t\t...(options.subagentCommunicationWiring ?? {}),\n\t\t\t\t};\n\t// 记忆档位解析(2.4d6 S1;D-075 S4 第四批):SDK 显式选项最优先,settings.json\n\t// 档位作为 env 之下的持久来源进入解析链(显式 > env > settings > 旧别名 env >\n\t// off);两者皆缺省时同样走 env/别名/off 解析(off = memory 插件包不装配)。\n\t// 门控诊断与成员资格判定在下方 capabilityWiring 块产出。\n\tconst settingsMemoryMode = settingsManager.getMemoryModeSetting();\n\tconst memoryModeOption = options.memoryCapability?.mode;\n\tconst memoryModeResolution = resolveSdkMemoryMode(memoryModeOption, process.env, settingsMemoryMode);\n\tif (capabilityWiring) {\n\t\t// 非 builtin 的 capabilities 条目按安装店插件包 id 直通(成员资格与\n\t\t// dangling 诊断都在下方装配块统一处理),这里不再产出旧的 unknown 短 id\n\t\t// 诊断——同一批条目报两条且会误报已安装插件。\n\t\t// 记忆全局门控诊断(2.4d6 S1, D-075 S4 第四批自 builtin 通道迁入):套件确实\n\t\t// 声明了 builtin.memory 时才输出(抑制发生了才声明;未声明的场合由白名单语\n\t\t// 义覆盖,不加噪音)。文案由 builtin 时代逐字迁移(memory-mode-gating 等 pin)。\n\t\tif (suiteWorkspace.suite.capabilities.includes(\"builtin.memory\")) {\n\t\t\tif (memoryModeResolution.invalidEnvValue !== undefined) {\n\t\t\t\tcapabilityDiagnostics.push(\n\t\t\t\t\t`invalid AGENT_FORGE_MEMORY_MODE value \"${memoryModeResolution.invalidEnvValue}\"; memory stays off (fail-closed)`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (memoryModeResolution.invalidSettingsValue !== undefined) {\n\t\t\t\tcapabilityDiagnostics.push(\n\t\t\t\t\t`invalid memory.mode setting \"${memoryModeResolution.invalidSettingsValue}\"; memory stays off (fail-closed)`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (memoryModeResolution.mode === \"off\") {\n\t\t\t\tcapabilityDiagnostics.push(\n\t\t\t\t\t\"memory disabled (mode=off) — set memory.mode (light|full) in settings.json to enable\",\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\t// Legacy plugin skill face: the bootstrap-skills contribution face is\n\t\t// already filtered loader-side (M1b); only runtime.listSkills() entries\n\t\t// pass through this hook. Association dangling is reported by the\n\t\t// loader-side skills filter; this hook only narrows the plugin face.\n\t\t// The suite-local skill layer (统一修复轮 B) passes by path there.\n\t\tconst suiteDefinition = suiteWorkspace.suite;\n\t\tconst suiteLocalSkillsDir = suiteAssembly.localSkillsDir;\n\t\tcapabilitySkillsFilter = (skills: Skill[]) =>\n\t\t\tfilterSuiteSkills(suiteDefinition, skills, { localSkillsDir: suiteLocalSkillsDir }).kept;\n\t}\n\n\tconst sessionManager = options.sessionManager ?? SessionManager.create(cwd, getDefaultSessionDir(cwd, agentDir));\n\n\t// 打点通道(设计 §5.2):streamFn 闭包的 options 参数会遮蔽装配 options,统一\n\t// 捕获为局部常量;未注入时全部打点为 no-op。\n\tconst hostLogger = options.hostLogger;\n\t// 轨迹快照预算(设计 §6 控制面,第 2 期外露):随 trace 服务注入安装店\n\t// observability 插件;缺省 = 插件内默认(16000 字符/串、384KiB/快照)。\n\tconst traceOptions = options.traceOptions;\n\n\t// 轨迹收集默认装配(设计 §4.4/§6,D-065;S4 拆包改造,D-075 第二批):\n\t// `traceEnabled` 缺省开启时,安装店 `agent-forge.plugin.observability` 包\n\t// 随装配链加载(成员资格并入 installed 插件集合,可经 disabledPluginIds\n\t// 显式禁用;第三方可经同一公共 lifecycle 订阅面替换)。宿主适配器闭包只\n\t// 依赖装配域内既有事实:会话文件路径(惰性解析,经既有 getSessionFile()\n\t// 读面加 §4.1 配对纯函数)、进程日志(options.hostLogger,未注入为 no-op)、\n\t// payload 捕获(onPayload 读取;无隐藏全局)。适配器经新 `api.trace` 服务\n\t// 面注入插件;插件 entry 经适配器可选 `registerFacade` 通道把门面写回\n\t// 下方三个装配域 ref(payload 捕获 / plugin.log 镜像 / /metrics 数据源),\n\t// dispose 时置空——与内嵌工厂时代的 ref 语义逐点一致。\n\tconst observabilityCapture: { current?: ObservabilityPluginFacadeV1[\"captureProviderPayload\"] } = {};\n\t// 插件日志镜像共享 ref(会话轨迹 plugin.log,设计 §7.2):插件门面\n\t// mirrorPluginLog 注册时写入,dispose 时置空;AgentSession 的 runtime\n\t// 日志 sink 经 AgentSessionConfig.logRecordMirrorRef 读它。\n\tconst observabilityLogMirror: { current?: (record: LoggerRecord) => void } = {};\n\t// /metrics 命令的数据源(observability 门面直通):插件门面 getMetrics\n\t// 注册时写入,dispose 时置空;宿主(TUI/RPC)在装配完成后读取并接进命令\n\t// options。\n\tconst observabilityGetMetrics: { current?: ObservabilityPluginFacadeV1[\"getMetrics\"] } = {};\n\tlet traceService: TraceServiceV1 | undefined;\n\tif (options.traceEnabled !== false) {\n\t\tconst adapter: ObservabilityHostAdapterV1 = {\n\t\t\tgetTraceFilePath: () => {\n\t\t\t\tconst sessionFilePath = sessionManager.getSessionFile();\n\t\t\t\treturn sessionFilePath === undefined ? null : getTraceFilePathForSession(sessionFilePath);\n\t\t\t},\n\t\t\tcaptureProviderPayload: (payload, model) => {\n\t\t\t\tobservabilityCapture.current?.(payload, model);\n\t\t\t},\n\t\t\tonSinkFailure: (error) => {\n\t\t\t\thostLogger?.error(\"observability\", \"trace sink failure\", { cause: error });\n\t\t\t},\n\t\t\tgetTurnCorrelationId: () => agentSessionRef.current?.getTurnCorrelationId(),\n\t\t\tgetParentAgentSessionId: () => sessionManager.getHeader()?.parentAgentSession,\n\t\t\tgetParentTraceId: () => sessionManager.getHeader()?.parentTraceId,\n\t\t\tregisterFacade: (facade) => {\n\t\t\t\tobservabilityCapture.current = facade?.captureProviderPayload;\n\t\t\t\tobservabilityLogMirror.current = facade?.mirrorPluginLog;\n\t\t\t\tobservabilityGetMetrics.current = facade?.getMetrics;\n\t\t\t},\n\t\t};\n\t\ttraceService = { adapter, ...(traceOptions === undefined ? {} : { options: traceOptions }) };\n\t}\n\n\tif (!resourceLoader) {\n\t\t// Suite association filtering (方案系统 M1b, 设计 §3/§4): the default\n\t\t// loader's skills are filtered down to the suite's\n\t\t// associations here, at the assembler layer; project-scope entries\n\t\t// (cwd/.agent-forge) always pass. Dangling associations surface through\n\t\t// suiteDiagnostics, never as errors.\n\t\tresourceLoader = new DefaultResourceLoader({\n\t\t\tcwd,\n\t\t\tagentDir,\n\t\t\tsettingsManager,\n\t\t\t...suiteAssembly.loaderOverrides,\n\t\t\t// Suite-local skill layer (统一修复轮 B): <suiteDir>/skills rides the\n\t\t\t// loader's skill paths when the suite is active. The filterSuiteSkills\n\t\t\t// suite-local exemption keeps these entries; user-level and other\n\t\t\t// unassociated layers stay filtered. Undefined (absent directory)\n\t\t\t// injects nothing, so empty and missing directories are both silent.\n\t\t\t...(suiteAssembly.localSkillsDir === undefined\n\t\t\t\t? {}\n\t\t\t\t: { additionalSkillPaths: [suiteAssembly.localSkillsDir] }),\n\t\t});\n\t\tawait resourceLoader.reload();\n\t\ttime(\"resourceLoader.reload\");\n\t}\n\n\t// Check if session has existing data to restore\n\tconst existingSession = sessionManager.buildSessionContext();\n\tconst hasExistingSession = existingSession.messages.length > 0;\n\tconst branchEntries = sessionManager.getBranch();\n\tconst sessionSuiteBinding = readSessionSuiteBinding(branchEntries);\n\t// 绑定护栏保护的是有对话上下文的会话:会话创建先于插件装载,装载失败(profile\n\t// drift 等)会留下只有初始化 entry 与绑定的残留——这些 message entries 会让\n\t// hasExistingSession 为真,若按它门控,用户用同一 session id 重试会永远撞墙\n\t// (dogfood 2026-09-25 实测)。真实用户输入(user entry)才算对话开始。\n\tconst hasConversation = branchEntries.some(\n\t\t(entry) => entry.type === \"message\" && (entry as { message?: { role?: string } }).message?.role === \"user\",\n\t);\n\tif (hasConversation && sessionSuiteBinding !== undefined && !options.allowSuiteRebind) {\n\t\tif (sessionSuiteBinding.suiteId !== suiteId) {\n\t\t\tthrow new SuiteRebindError(\n\t\t\t\tt(\n\t\t\t\t\t'Session is bound to suite \"{boundSuiteId}\" and cannot resume with \"{suiteId}\"; rerun with --rebind-suite to adopt the new suite, or create a new session',\n\t\t\t\t\t{ boundSuiteId: sessionSuiteBinding.suiteId, suiteId },\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\tif (\n\t\t\tsessionSuiteBinding.profileIdentity !== undefined &&\n\t\t\t!profileIdentitiesCompatible(sessionSuiteBinding.profileIdentity, suiteWorkspace.identity)\n\t\t) {\n\t\t\tthrow new SuiteRebindError(\n\t\t\t\tt(\n\t\t\t\t\t\"Session Profile identity drift detected (the active plugin set changed since the conversation started); rerun with --rebind-suite to adopt the new plugin set, or create a new session\",\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n\tconst hasThinkingEntry = sessionManager.getBranch().some((entry) => entry.type === \"thinking_level_change\");\n\n\tlet model = options.model;\n\tlet modelFallbackMessage: string | undefined;\n\n\t// If session has data, try to restore model from it\n\tif (!model && hasExistingSession && existingSession.model) {\n\t\tconst restoredModel = modelRuntime.getModel(existingSession.model.provider, existingSession.model.modelId);\n\t\tif (restoredModel && modelRuntime.hasConfiguredAuth(restoredModel.provider)) {\n\t\t\tmodel = restoredModel;\n\t\t}\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = `Could not restore model ${existingSession.model.provider}/${existingSession.model.modelId}`;\n\t\t}\n\t}\n\n\t// Suite model preference (统一修复轮 B): sits below the CLI/explicit option\n\t// and the restored session model, above the settings default that\n\t// findInitialModel resolves below. A suite model that matches no\n\t// authenticated model falls through to the next tier with a diagnostic —\n\t// never a failure (设计 §9: suite content never blocks startup). Factory\n\t// builtin suites declare null, so their resolution is unchanged.\n\tconst suiteModelPreference = suiteWorkspace.suite.model;\n\tif (!model && suiteModelPreference !== null) {\n\t\tconst suiteModel = findExactModelReferenceMatch(suiteModelPreference, [...modelRuntime.getModels()]);\n\t\tif (suiteModel && modelRuntime.hasConfiguredAuth(suiteModel.provider)) {\n\t\t\tmodel = suiteModel;\n\t\t} else {\n\t\t\tsuitePreferenceDiagnostics.push(\n\t\t\t\t`Suite \"${suiteId}\" model \"${suiteModelPreference}\" does not resolve to an authenticated model; using the normal model resolution instead.`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// If still no model, use findInitialModel (checks settings default, then provider defaults)\n\tif (!model) {\n\t\tconst result = await findInitialModel({\n\t\t\tscopedModels: [],\n\t\t\tisContinuing: hasExistingSession,\n\t\t\tdefaultProvider: settingsManager.getDefaultProvider(),\n\t\t\tdefaultModelId: settingsManager.getDefaultModel(),\n\t\t\tdefaultThinkingLevel: settingsManager.getDefaultThinkingLevel(),\n\t\t\tmodelThinkingLevels: settingsManager.getAllModelThinkingLevels(),\n\t\t\tmodelRuntime,\n\t\t});\n\t\tmodel = result.model;\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = formatNoModelsAvailableMessage();\n\t\t} else if (modelFallbackMessage) {\n\t\t\tmodelFallbackMessage += `. Using ${model.provider}/${model.id}`;\n\t\t}\n\t}\n\n\tlet thinkingLevel = options.thinkingLevel;\n\n\t// If session has data, restore thinking level from it\n\tif (thinkingLevel === undefined && hasExistingSession && hasThinkingEntry) {\n\t\tthinkingLevel = existingSession.thinkingLevel as ThinkingLevel;\n\t}\n\n\t// Suite thinking preference (统一修复轮 B): below the session's persisted\n\t// thinking entry, above the settings-derived tiers. An invalid value falls\n\t// through with a diagnostic; factory builtin suites declare null, so their\n\t// resolution is unchanged.\n\tconst suiteThinkingPreference = suiteWorkspace.suite.thinking;\n\tif (thinkingLevel === undefined && suiteThinkingPreference !== null) {\n\t\tif (isValidThinkingLevel(suiteThinkingPreference)) {\n\t\t\tthinkingLevel = suiteThinkingPreference;\n\t\t} else {\n\t\t\tsuitePreferenceDiagnostics.push(\n\t\t\t\t`Suite \"${suiteId}\" thinking \"${suiteThinkingPreference}\" is not a valid thinking level; using the normal thinking resolution instead.`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// If session has data without a persisted thinking entry, the settings\n\t// default applies (same tier as before the suite preference was inserted).\n\tif (thinkingLevel === undefined && hasExistingSession) {\n\t\tthinkingLevel = settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;\n\t}\n\n\t// Fall back to per-model override, then global default\n\tif (thinkingLevel === undefined && model) {\n\t\tconst perModel = settingsManager.getModelThinkingLevel(model.provider, model.id);\n\t\tif (perModel) {\n\t\t\tthinkingLevel = perModel;\n\t\t}\n\t}\n\tif (thinkingLevel === undefined) {\n\t\tthinkingLevel = settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;\n\t}\n\n\t// Clamp to model capabilities\n\tif (!model) {\n\t\tthinkingLevel = \"off\";\n\t} else {\n\t\tthinkingLevel = clampThinkingLevel(model, thinkingLevel) as ThinkingLevel;\n\t}\n\n\tconst defaultActiveToolNames: ToolName[] =\n\t\toptions.capabilityMode === \"readonly\" ? [\"read\", \"grep\", \"find\", \"ls\"] : [\"read\", \"bash\", \"edit\", \"write\"];\n\tconst configuredDefaultToolNames = settingsManager.getDefaultTools();\n\tconst allowedToolNames = options.tools ?? (options.noTools === \"all\" ? [] : undefined);\n\tconst excludedToolNames = options.excludeTools;\n\tconst excludedToolNameSet = excludedToolNames ? new Set(excludedToolNames) : undefined;\n\t// Suite tool surface (设计 §5/§6): the resolved suite's declared tools\n\t// override the default allowlist when the caller passed neither tools nor\n\t// noTools. Both builtin suites share the same unrestricted 8-tool\n\t// declaration (设计 §5: \"两方案同一全集、无任何限制\"), so whichever suite\n\t// is default activates it too — the historical DEFAULT_SUITE_ID exemption\n\t// that pinned assistant to the 4-tool base was removed in the 统一修复轮\n\t// (2026-09-08, per 方案设计 §5 and the user decision \"不需要限制这么死\").\n\t// capabilityMode stays a separate, orthogonal axis (设计 §5 权限段):\n\t// readonly narrows BOTH suites' faces a second time, so the suite\n\t// declaration never defeats the readonly base face.\n\tconst suiteToolOverride =\n\t\toptions.tools === undefined && options.noTools === undefined && options.capabilityMode !== \"readonly\"\n\t\t\t? [...suiteWorkspace.suite.tools]\n\t\t\t: undefined;\n\tconst initialActiveToolNames = (\n\t\tsuiteToolOverride ??\n\t\toptions.tools ??\n\t\t(options.noTools ? [] : (configuredDefaultToolNames ?? defaultActiveToolNames))\n\t).filter((name) => !excludedToolNameSet?.has(name));\n\n\tlet agent: Agent;\n\n\t// Create convertToLlm wrapper that filters images if blockImages is enabled (defense-in-depth)\n\tconst convertToLlmWithBlockImages = (messages: AgentMessage[]): Message[] => {\n\t\tconst converted = convertToLlm(messages);\n\t\t// Check setting dynamically so mid-session changes take effect\n\t\tif (!settingsManager.getBlockImages()) {\n\t\t\treturn converted;\n\t\t}\n\t\t// Filter out ImageContent from all messages, replacing with text placeholder\n\t\treturn converted.map((msg) => {\n\t\t\tif (msg.role === \"user\" || msg.role === \"toolResult\") {\n\t\t\t\tconst content = msg.content;\n\t\t\t\tif (Array.isArray(content)) {\n\t\t\t\t\tconst hasImages = content.some((c) => c.type === \"image\");\n\t\t\t\t\tif (hasImages) {\n\t\t\t\t\t\tconst filteredContent = content\n\t\t\t\t\t\t\t.map((c) =>\n\t\t\t\t\t\t\t\tc.type === \"image\" ? { type: \"text\" as const, text: \"Image reading is disabled.\" } : c,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.filter(\n\t\t\t\t\t\t\t\t(c, i, arr) =>\n\t\t\t\t\t\t\t\t\t// Dedupe consecutive \"Image reading is disabled.\" texts\n\t\t\t\t\t\t\t\t\t!(\n\t\t\t\t\t\t\t\t\t\tc.type === \"text\" &&\n\t\t\t\t\t\t\t\t\t\tc.text === \"Image reading is disabled.\" &&\n\t\t\t\t\t\t\t\t\t\ti > 0 &&\n\t\t\t\t\t\t\t\t\t\tarr[i - 1].type === \"text\" &&\n\t\t\t\t\t\t\t\t\t\t(arr[i - 1] as { type: \"text\"; text: string }).text === \"Image reading is disabled.\"\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\treturn { ...msg, content: filteredContent };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn msg;\n\t\t});\n\t};\n\n\tconst agentSessionRef: { current?: AgentSession } = {};\n\tconst customStreamFn = options.streamFn;\n\tagent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt: \"\",\n\t\t\tmodel,\n\t\t\tthinkingLevel,\n\t\t\ttools: [],\n\t\t},\n\t\tconvertToLlm: convertToLlmWithBlockImages,\n\t\tstreamFn: customStreamFn\n\t\t\t? (model, context, streamOptions) => customStreamFn(model, context, streamOptions)\n\t\t\t: async (model, context, options) => {\n\t\t\t\t\tconst providerRetrySettings = settingsManager.getProviderRetrySettings();\n\t\t\t\t\tconst httpIdleTimeoutMs = settingsManager.getHttpIdleTimeoutMs();\n\t\t\t\t\t// SDKs treat timeout=0 as 0ms (immediate timeout), not \"no timeout\".\n\t\t\t\t\t// Use max int32 to effectively disable the timeout.\n\t\t\t\t\tconst effectiveTimeoutMs = httpIdleTimeoutMs === 0 ? 2147483647 : httpIdleTimeoutMs;\n\t\t\t\t\tconst timeoutMs = options?.timeoutMs ?? providerRetrySettings.timeoutMs ?? effectiveTimeoutMs;\n\t\t\t\t\tconst websocketConnectTimeoutMs =\n\t\t\t\t\t\toptions?.websocketConnectTimeoutMs ?? settingsManager.getWebSocketConnectTimeoutMs();\n\t\t\t\t\t// 默认闭包:底层 streamSimple 调用(请求预算/超时按本次调用捕获;header\n\t\t\t\t\t// 变换闭包绑定请求模型参数,使换道重放后的备用模型也走各自变换)。\n\t\t\t\t\tconst baseStreamFn = (\n\t\t\t\t\t\trequestModel: Model<Api>,\n\t\t\t\t\t\trequestContext: Context,\n\t\t\t\t\t\trequestOptions?: SimpleStreamOptions,\n\t\t\t\t\t): AssistantMessageEventStream => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\treturn modelRuntime.streamSimple(requestModel, requestContext, {\n\t\t\t\t\t\t\t\t...requestOptions,\n\t\t\t\t\t\t\t\ttimeoutMs,\n\t\t\t\t\t\t\t\twebsocketConnectTimeoutMs,\n\t\t\t\t\t\t\t\tmaxRetries: requestOptions?.maxRetries ?? providerRetrySettings.maxRetries,\n\t\t\t\t\t\t\t\tmaxRetryDelayMs: requestOptions?.maxRetryDelayMs ?? providerRetrySettings.maxRetryDelayMs,\n\t\t\t\t\t\t\t\ttransformHeaders: async (requestHeaders) => {\n\t\t\t\t\t\t\t\t\tconst session = agentSessionRef.current;\n\t\t\t\t\t\t\t\t\t// v8 ignore next -- 流式请求仅在会话初始化后发生,session 恒已赋值\n\t\t\t\t\t\t\t\t\tif (!session)\n\t\t\t\t\t\t\t\t\t\tthrow new Error(t(\"Capability runtime is not initialized for provider request\"));\n\t\t\t\t\t\t\t\t\treturn session.getCapabilityRuntime().transformProviderHeaders({\n\t\t\t\t\t\t\t\t\t\tmodel: requestModel,\n\t\t\t\t\t\t\t\t\t\t...(requestOptions?.sessionId === undefined\n\t\t\t\t\t\t\t\t\t\t\t? {}\n\t\t\t\t\t\t\t\t\t\t\t: { sessionId: requestOptions.sessionId }),\n\t\t\t\t\t\t\t\t\t\theaders: requestHeaders,\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t// streamFn 错误路径打点(设计 §5.2):保留原始错误向上传播。\n\t\t\t\t\t\t\thostLogger?.error(\"sdk\", \"provider stream failed\", { cause: error });\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t\t// streamFn wrapper 链(provider-failover 家族注册面,设计 供应商能力槽位\n\t\t\t\t\t// 与主备切换 §4.8):getStreamFnWrappers 已按 (priority 升序, 注册序升序)\n\t\t\t\t\t// 稳定排序(D-082 批 3b 契约 A,低值更外层);从数组末尾向前包裹,首位\n\t\t\t\t\t// wrapper 即最外层,其 next 覆盖其余 wrapper 直至底层默认调用。每次请求\n\t\t\t\t\t// 时从会话 capability runtime 读取,使 bundled failover 插件(随 manifest\n\t\t\t\t\t// 链装载)与第三方 wrapper 都进入链中——failover 以 priority -100 注册,\n\t\t\t\t\t// 无论装载顺序都在最外层。调用方显式传 options.streamFn 的会话整体绕过\n\t\t\t\t\t// 本装配(含 wrapper),不参与 failover——已知边界。\n\t\t\t\t\tconst wrappers = agentSessionRef.current?.getCapabilityRuntime().getStreamFnWrappers() ?? [];\n\t\t\t\t\ttype ChainStreamFn = (\n\t\t\t\t\t\trequestModel: Model<Api>,\n\t\t\t\t\t\trequestContext: Context,\n\t\t\t\t\t\trequestOptions?: SimpleStreamOptions,\n\t\t\t\t\t) => AssistantMessageEventStream;\n\t\t\t\t\tlet chain: ChainStreamFn = baseStreamFn;\n\t\t\t\t\tfor (let index = wrappers.length - 1; index >= 0; index -= 1) {\n\t\t\t\t\t\tconst wrapper = wrappers[index];\n\t\t\t\t\t\tconst inner = chain;\n\t\t\t\t\t\tchain = (requestModel, requestContext, requestOptions) =>\n\t\t\t\t\t\t\twrapper(\n\t\t\t\t\t\t\t\trequestModel,\n\t\t\t\t\t\t\t\trequestContext,\n\t\t\t\t\t\t\t\trequestOptions,\n\t\t\t\t\t\t\t\t(nextModel, nextContext, nextOptions) =>\n\t\t\t\t\t\t\t\t\tinner(\n\t\t\t\t\t\t\t\t\t\tnextModel as Model<Api>,\n\t\t\t\t\t\t\t\t\t\tnextContext as Context,\n\t\t\t\t\t\t\t\t\t\tnextOptions as SimpleStreamOptions | undefined,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tresolveModel: (provider, modelId) => modelRuntime.getModel(provider, modelId),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t) as AssistantMessageEventStream;\n\t\t\t\t\t}\n\t\t\t\t\treturn chain(model, context, options);\n\t\t\t\t},\n\t\tonPayload: async (payload, model) => {\n\t\t\t// 轨迹快照(设计 §4.2 llm.request):最终 payload 转发给装配域收集器;\n\t\t\t// 转发自身失败只记日志,绝不影响请求。\n\t\t\ttry {\n\t\t\t\ttraceService?.adapter.captureProviderPayload(payload, model?.id);\n\t\t\t} catch (error) {\n\t\t\t\thostLogger?.warn(\"sdk\", \"trace payload capture failed\", { cause: error });\n\t\t\t}\n\t\t},\n\t\tsessionId: sessionManager.getSessionId(),\n\t\ttransformContext: async (messages) => {\n\t\t\t// (B1 记忆自动注入已迁至 builtin memory 能力插件的 transformContext 链\n\t\t\t// 环节,D-071;后台委派结算回注迁至 sink 侧 sendCustomMessage,D-060\n\t\t\t// 裁决 12——本装配域自身不再做请求时注入。)\n\t\t\treturn messages;\n\t\t},\n\t\tsteeringMode: settingsManager.getSteeringMode(),\n\t\tfollowUpMode: settingsManager.getFollowUpMode(),\n\t\ttransport: settingsManager.getTransport(),\n\t\tthinkingBudgets: settingsManager.getThinkingBudgets(),\n\t\tmaxRetryDelayMs: settingsManager.getProviderRetrySettings().maxRetryDelayMs,\n\t});\n\n\t// Restore messages if session has existing data\n\tif (hasExistingSession) {\n\t\tagent.state.messages = existingSession.messages;\n\t\tif (!hasThinkingEntry) {\n\t\t\tsessionManager.appendThinkingLevelChange(thinkingLevel);\n\t\t}\n\t} else {\n\t\t// Save initial model and thinking level for new sessions so they can be restored on resume\n\t\tif (model) {\n\t\t\tsessionManager.appendModelChange(model.provider, model.id);\n\t\t}\n\t\tsessionManager.appendThinkingLevelChange(thinkingLevel);\n\t}\n\n\t// Assistant preference card (统一修复轮 A 交付3, H2 接线) migrated into the\n\t// memory plugin package with the S4 fourth batch: the plugin's\n\t// transformContext loop hook reads the ledger-backed card and injects it on\n\t// assistant-oriented sessions itself. The sdk no longer loads or injects\n\t// the card.\n\n\tconst session = new AgentSession({\n\t\tagent,\n\t\tsessionManager,\n\t\tsettingsManager,\n\t\tcwd,\n\t\tscopedModels: options.scopedModels,\n\t\tresourceLoader,\n\t\tcustomTools: options.customTools,\n\t\tmodelRuntime,\n\t\tinitialActiveToolNames,\n\t\tallowedToolNames,\n\t\texcludedToolNames,\n\t\t// 延迟工具(MCP `deferredTools: true`):services 装配域解析出的插件 id 集\n\t\t// 合在此过线;AgentSession 据此注册 tool_search 并把对应插件的新工具排除出\n\t\t// 默认激活集(agent-session-tools 的默认激活分支)。\n\t\t...(options.deferredToolPluginIds === undefined ? {} : { deferredToolPluginIds: options.deferredToolPluginIds }),\n\t\tsessionStartEvent: options.sessionStartEvent,\n\t\tcapabilityMode: options.capabilityMode,\n\t\tcontextStrategyName: options.contextStrategyName,\n\t\tretryPolicyName: options.retryPolicyName,\n\t\tcompactionPolicyName: options.compactionPolicyName,\n\t\toverflowPolicyName: options.overflowPolicyName,\n\t\tbranchSummaryPolicyName: options.branchSummaryPolicyName,\n\t\trunLoopStrategyName: options.runLoopStrategyName,\n\t\t// 承载退役切片 2:装配域无默认 creator——委派承载 = 宿主 adapter 或 CLI 自动池化。\n\t\tagentTaskAdapter: options.enableAgentTasks === false ? undefined : options.agentTaskAdapter,\n\t\t...(options.agentTaskResults === undefined ? {} : { agentTaskResults: options.agentTaskResults }),\n\t\t// 会话回读(D-060 S3):按 sessionId 读子会话 transcript,作用域在**宿主侧**强制——\n\t\t// 只放行本会话自己的子会话(文件头 parentAgentSession 必须等于本会话 id),\n\t\t// 越界与不存在同型返回 undefined。\n\t\t...(options.enableAgentTasks === false\n\t\t\t? {}\n\t\t\t: {\n\t\t\t\t\tagentSessionReader: async (sessionId: string) => {\n\t\t\t\t\t\tconst parentSession = agentSessionRef.current;\n\t\t\t\t\t\tif (parentSession === undefined) return undefined;\n\t\t\t\t\t\tconst read = readAgentSession({ agentDir, sessionId });\n\t\t\t\t\t\tif (read === undefined || read.parentAgentSession !== parentSession.sessionId) return undefined;\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tsessionId: read.sessionId,\n\t\t\t\t\t\t\t...(read.parentAgentSession === undefined ? {} : { parentAgentSession: read.parentAgentSession }),\n\t\t\t\t\t\t\t...(read.agentRole === undefined ? {} : { agentRole: read.agentRole }),\n\t\t\t\t\t\t\t...(read.createdAt === undefined ? {} : { createdAt: read.createdAt }),\n\t\t\t\t\t\t\tbytes: read.bytes,\n\t\t\t\t\t\t\tentryCount: read.entryCount,\n\t\t\t\t\t\t\ttruncated: read.truncated,\n\t\t\t\t\t\t\tentries: read.entries,\n\t\t\t\t\t\t};\n\t\t\t\t\t},\n\t\t\t\t\t// 子会话盘点(D-060 模型面):只列本会话自己的子会话摘要(store 默认\n\t\t\t\t\t// 最近活动倒序、上限 200),读落盘目录,跨进程重启仍可列出。\n\t\t\t\t\tagentSessionLister: async (): Promise<AgentTaskSessionSummaryV1[]> => {\n\t\t\t\t\t\tconst parentSession = agentSessionRef.current;\n\t\t\t\t\t\tif (parentSession === undefined) return [];\n\t\t\t\t\t\treturn listAgentSessions({ agentDir, parentAgentSession: parentSession.sessionId }).map(\n\t\t\t\t\t\t\t(summary) => ({\n\t\t\t\t\t\t\t\tsessionId: summary.sessionId,\n\t\t\t\t\t\t\t\t...(summary.agentRole === undefined ? {} : { agentRole: summary.agentRole }),\n\t\t\t\t\t\t\t\t...(summary.createdAt === undefined ? {} : { createdAt: summary.createdAt }),\n\t\t\t\t\t\t\t\tmodifiedAt: summary.modifiedAt,\n\t\t\t\t\t\t\t\tbytes: summary.bytes,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\tagentComposition: options.agentComposition,\n\t\tinteractionHost: options.interactionHost,\n\t\t// 打点通道下沉(设计 §5.2/§7.2):会话级进程日志打点(插件日志镜像、内建\n\t\t// 装载失败等)与 plugin.log 轨迹镜像共享 ref(插件门面注册时写入,空 = 无\n\t\t// 镜像)。\n\t\thostLogger: options.hostLogger,\n\t\tlogRecordMirrorRef: observabilityLogMirror,\n\t\tobservabilityGetMetricsRef: observabilityGetMetrics,\n\t\t// D-075 S4 第二批:宿主 agentDir 上公共 HostCapabilities(磁盘状态插件的\n\t\t// 配置通道),trace 服务随 traceEnabled 注入 installed observability 包。\n\t\tagentDir,\n\t\t// D-075 S4 第三批:subagent-delegate 宿主服务上公共 HostCapabilities——\n\t\t// communication(父侧 drain + 注入的叶子 post 接线合并)、turnContext\n\t\t// (后台结算摘要 sink + 回合 correlationId 捕获)、roleAssociations(当前\n\t\t// 方案关联角色;角色定义只在磁盘 <agentDir>/roles/,无编译内定义)。\n\t\t// 原内嵌 builtin 构造选项链退役;独立插件包 entry 从 api.host 组装同一形状。\n\t\t...(communicationWiring === undefined ? {} : { communication: communicationWiring }),\n\t\t...(options.enableAgentTasks === false\n\t\t\t? {}\n\t\t\t: {\n\t\t\t\t\tturnContext: {\n\t\t\t\t\t\tbackgroundDigestSink: (line: string) => {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tconst session = agentSessionRef.current;\n\t\t\t\t\t\t\t\t// 轨迹闭合(第 4 期):结算行同步投递为 agent.task.settled@1(解析\n\t\t\t\t\t\t\t\t// 失败/非法 status 降级为 hostLogger warn;dispose 后派发助手 no-op),\n\t\t\t\t\t\t\t\t// 返回的 facts 供回注复用(同一行不二次 parse)。\n\t\t\t\t\t\t\t\tconst facts = deliverAgentTaskSettledDigestLine(session, line, hostLogger);\n\t\t\t\t\t\t\t\t// 结算回注(D-060 裁决 12,用户裁决 2026-10-02):结算即时回注主\n\t\t\t\t\t\t\t\t// 会话为一条 agent-task-settled custom message——主在跑经 followUp\n\t\t\t\t\t\t\t\t// 入队(本轮 drain、不抢占当前回合),主空闲时同一调用原子触发验\n\t\t\t\t\t\t\t\t// 收回合(被动机制,主不需要主动找子)。会话未建、已 dispose(同\n\t\t\t\t\t\t\t\t// 步置 isDisposed,读取时点无竞态)或行解析失败时跳过,不产生孤儿\n\t\t\t\t\t\t\t\t// 回合;手动压缩进行中由会话层降级为 followUp 入队(不穿透压缩\n\t\t\t\t\t\t\t\t// revision 互斥)。\n\t\t\t\t\t\t\t\tif (facts === undefined || session === undefined || session.isDisposed) return;\n\t\t\t\t\t\t\t\tconst reasonSuffix = facts.reasonCode === undefined ? \"\" : ` (reason: ${facts.reasonCode})`;\n\t\t\t\t\t\t\t\tconst summary = `Background subagent task ${facts.taskId} settled: ${facts.status}${reasonSuffix}.`;\n\t\t\t\t\t\t\t\tvoid session\n\t\t\t\t\t\t\t\t\t.sendCustomMessage(\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tcustomType: \"agent-task-settled\",\n\t\t\t\t\t\t\t\t\t\t\t// 首行是用户可读摘要(TUI custom message 渲染 content 全文),\n\t\t\t\t\t\t\t\t\t\t\t// 第二行指引模型收割完整结果并验收(custom 投影为 user 消息,\n\t\t\t\t\t\t\t\t\t\t\t// content 全文模型可见)。\n\t\t\t\t\t\t\t\t\t\t\tcontent:\n\t\t\t\t\t\t\t\t\t\t\t\t`${summary}\\n` +\n\t\t\t\t\t\t\t\t\t\t\t\t\"The settled result can be read with subagent_result (optionally waiting); read it and review the outcome before continuing.\",\n\t\t\t\t\t\t\t\t\t\t\tdisplay: true,\n\t\t\t\t\t\t\t\t\t\t\tdetails: {\n\t\t\t\t\t\t\t\t\t\t\t\ttaskId: facts.taskId,\n\t\t\t\t\t\t\t\t\t\t\t\ttaskSessionId: facts.taskSessionId,\n\t\t\t\t\t\t\t\t\t\t\t\tstatus: facts.status,\n\t\t\t\t\t\t\t\t\t\t\t\t...(facts.reasonCode === undefined ? {} : { reasonCode: facts.reasonCode }),\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{ deliverAs: \"followUp\", triggerTurn: true },\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t.catch((error) => {\n\t\t\t\t\t\t\t\t\t\t// 回注失败不影响 delegate 任务本身(终态已在调度器落库,可经\n\t\t\t\t\t\t\t\t\t\t// subagent_result 收割)——与结算观察器的 catch 注释同风格。\n\t\t\t\t\t\t\t\t\t\thostLogger?.warn(\"sdk\", \"background delegation settlement delivery failed\", {\n\t\t\t\t\t\t\t\t\t\t\tcause: error,\n\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t\t// sink 是同步函数且挂在 promise 链上:守卫外异常只记日志,不外抛。\n\t\t\t\t\t\t\t\thostLogger?.warn(\"sdk\", \"background delegation settlement sink failed\", {\n\t\t\t\t\t\t\t\t\tcause: error,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t// 回合级血缘(第 3 期第二批):委派提交时刻捕获父回合 correlationId,\n\t\t\t\t\t\t// 随 subagent_run metadata 过线(仅 create 新建路径消费)。\n\t\t\t\t\t\tgetTurnCorrelationId: () => agentSessionRef.current?.getTurnCorrelationId(),\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t...(options.enableAgentTasks === false ? {} : { roleAssociations: suiteWorkspace.suite.associations.roles }),\n\t\t...(traceService === undefined ? {} : { traceService }),\n\t\t// D-075 S4 第四批:记忆底层组件注入上公共 HostCapabilities——\n\t\t// `api.host.memoryStorage`,安装店的 memory 插件包 entry 组装消费\n\t\t// (store/ledger 工厂与向量组件公共契约,缺省 = 包内默认实现)。\n\t\t...(options.memoryCapability?.storage === undefined ? {} : { memoryStorage: options.memoryCapability.storage }),\n\t\t// Orientation persona (设计 §6.2, M2): the resolved suite's orientation\n\t\t// text rides every system prompt rebuild on this session. A custom\n\t\t// orientation's persona text comes from the workspace persona.md,\n\t\t// already resolved by loadSuiteWorkspace (设计 §6.3). Capability tool\n\t\t// guides (memory / task management, D-071) ride the owning tools'\n\t\t// promptGuidelines instead.\n\t\torientationPrompt: suiteWorkspace.orientationPersona,\n\t\t// Capability wiring (方案系统 M3): undefined when the assembly boundary\n\t\t// disabled wiring, so the session keeps its default (unwired) identity.\n\t\t...(capabilitySkillsFilter === undefined ? {} : { capabilitySkillsFilter }),\n\t});\n\tagentSessionRef.current = session;\n\t// provider-failover 装配(设计 供应商能力槽位与主备切换 §4.8,D-082 批 3b):\n\t// 内嵌 installProviderFailoverPlugin 退役为 bundled 插件包\n\t// (plugins/provider-failover,id agent-forge.plugin.provider-failover),经\n\t// 下方 bundled 分发通道装载。配置注入见装载循环的 configOverride 分支\n\t// (settings `failover` 节存在时注入 `{version: 1, failover: <节点原样>}`,\n\t// 预检读面经 api.host.modelCatalog 契约 B 注入);wrapper 以 priority -100\n\t// 注册(契约 A),无论装载顺序都在链最外层——装配时序不再依赖 manifest 链。\n\t// Session-suite binding (设计 §10.1): record the suite as session protocol\n\t// data via the existing custom-entry extension point. New sessions only;\n\t// resumed sessions keep their original binding.\n\t// 新会话写入绑定;失败残留(有绑定但无对话)恢复时重写为当前装配——\n\t// readSessionSuiteBinding 取 latest,之后的绑定检查语义与实际装配一致。\n\t// 有对话的既有会话保持原绑定(护栏语义)。\n\tif (!hasExistingSession || (sessionSuiteBinding !== undefined && !hasConversation) || options.allowSuiteRebind) {\n\t\tsession.sessionManager.appendCustomEntry(SUITE_SESSION_ENTRY_TYPE, {\n\t\t\tsuiteId,\n\t\t\tprofileIdentity: suiteWorkspace.identity,\n\t\t});\n\t}\n\tconst pluginRejections: PluginRejection[] = [];\n\tconst recordRejection = async (\n\t\tcode: PluginRejection[\"code\"],\n\t\tmanifestPath: string,\n\t\tpluginId: string | undefined,\n\t\tmessage: string,\n\t): Promise<void> => {\n\t\tconst rejection: PluginRejection = Object.freeze({\n\t\t\tcode,\n\t\t\tmanifestPath,\n\t\t\t...(pluginId === undefined ? {} : { pluginId }),\n\t\t\tmessage,\n\t\t});\n\t\tpluginRejections.push(rejection);\n\t\t// 插件装载失败打点(设计 §5.2):结构化 rejection 之外的进程日志一行,\n\t\t// 让轨迹中断时可以凭日志定位。\n\t\thostLogger?.error(\"sdk\", `capability plugin rejected: ${message}`, {\n\t\t\tsessionId: session.sessionId,\n\t\t\tfields: { code: rejection.code, pluginId: rejection.pluginId, manifestPath: rejection.manifestPath },\n\t\t});\n\t\ttry {\n\t\t\tawait session.getCapabilityRuntime().recordPluginRejection(rejection);\n\t\t} catch {\n\t\t\t// Rejection visibility must never fail the remaining startup path.\n\t\t}\n\t};\n\tconst rejectionMessage = (error: unknown): string => (error instanceof Error ? error.message : String(error));\n\ttry {\n\t\tconst discoveredManifestPaths =\n\t\t\toptions.discoverCapabilityPlugins === false\n\t\t\t\t? []\n\t\t\t\t: discoverCapabilityPluginManifests([join(agentDir, \"plugins\"), join(cwd, CONFIG_DIR_NAME, \"plugins\")]);\n\t\t// Suite-local plugin layer (统一修复轮 B): manifests below\n\t\t// <suiteDir>/plugins load when the suite is active and the capability\n\t\t// surface is wired; suite activation is their association, so they bypass\n\t\t// associations.plugins filtering like explicit caller paths and win\n\t\t// duplicate-id resolution over the pools. The discovery switch gates them\n\t\t// too, so callers that disable plugin discovery (child sessions) keep\n\t\t// today's plugin-free face.\n\t\tconst suiteLocalManifestPaths =\n\t\t\tcapabilityWiring && options.discoverCapabilityPlugins !== false && suiteAssembly.localPluginsDir !== undefined\n\t\t\t\t? discoverCapabilityPluginManifests([suiteAssembly.localPluginsDir])\n\t\t\t\t: [];\n\t\t// Installed-code-loading (D-075 S2): verified active installations whose\n\t\t// plugin id is a member of the resolved plugin profile (selected, not\n\t\t// disabled) join the pool as explicit candidates; their code loads\n\t\t// through session.loadCapabilityPluginManifest exactly like\n\t\t// caller-supplied paths. Installed plugins that miss membership stay\n\t\t// unloaded — one diagnostic, no implicit third-party loading.\n\t\tconst disabledPluginIdSet = new Set(options.disabledPluginIds ?? []);\n\t\tconst profilePluginIds =\n\t\t\tsuiteAssembly.pluginProfile !== undefined && suiteAssembly.pluginProfile.status === \"resolved\"\n\t\t\t\t? new Set(\n\t\t\t\t\t\tsuiteAssembly.pluginProfile.profile.pluginIds.filter(\n\t\t\t\t\t\t\t(pluginId) => !disabledPluginIdSet.has(pluginId),\n\t\t\t\t\t\t),\n\t\t\t\t\t)\n\t\t\t\t: new Set<string>();\n\t\t// S4 拆包(D-075 §6 S4 第一批):suite.capabilities 声明的\n\t\t// builtin.goal/builtin.plan/builtin.todo-set 短 id 不再有内嵌注册,经\n\t\t// BUILTIN_CAPABILITY_PACKAGE_IDS 映射到独立插件包 id,并入 installed 插件的\n\t\t// 成员资格集合——已安装即随装配链加载(active-bindings 来源不变),未安装时\n\t\t// 静默缺席(不算 dangling);用户显式 disable 仍然生效。第二批:session-share\n\t\t// 短 id 同样经映射接管;observability 包 id 随 traceEnabled 直接并入(trace\n\t\t// 关闭时不并入 = 插件不加载,与内嵌时代\"不注册即禁用\"语义一致)。第四批:\n\t\t// builtin.memory 经映射接管,但 memory.mode 解析为 off 时不并入(禁用 = 不装\n\t\t// 配,与内嵌时代\"禁用 = 不注册\"同语义;上面已带一行启动声明)。\n\t\t// 直通语义(第三方分发链路修复):非 builtin 条目是安装店插件包 id,原样\n\t\t// 并入成员资格集合(与映射后的 agent-forge.plugin.* 同等:已安装即加载、\n\t\t// 用户显式 disable 仍生效)——不再静默丢弃,否则第三方插件经\n\t\t// plugin install 装入后任何套件都选不中它。\n\t\tconst passthroughCapabilityPluginIds: string[] = [];\n\t\tconst capabilityPackageIds = suiteWorkspace.suite.capabilities.flatMap((entry) => {\n\t\t\tconst mappedPluginId = (BUILTIN_CAPABILITY_PACKAGE_IDS as Readonly<Record<string, string>>)[entry];\n\t\t\tif (mappedPluginId !== undefined) return [mappedPluginId];\n\t\t\tpassthroughCapabilityPluginIds.push(entry);\n\t\t\treturn [entry];\n\t\t});\n\t\tif (options.traceEnabled !== false) capabilityPackageIds.push(OBSERVABILITY_PACKAGE_ID);\n\t\tif (memoryModeResolution.mode === \"off\") {\n\t\t\tconst memoryIndex = capabilityPackageIds.indexOf(MEMORY_PACKAGE_ID);\n\t\t\tif (memoryIndex >= 0) capabilityPackageIds.splice(memoryIndex, 1);\n\t\t}\n\t\tfor (const pluginId of capabilityPackageIds) {\n\t\t\tif (!disabledPluginIdSet.has(pluginId)) profilePluginIds.add(pluginId);\n\t\t}\n\t\t// 非 builtin 条目的 dangling 诊断(先例 associations.plugins,设计 §11.3):\n\t\t// 安装店无对应已装插件时恰一条;已装但被用户显式 disable 不诊断(主动\n\t\t// 行为);builtin 短 id 未安装保持静默缺席(上方映射注释)。门控跟随\n\t\t// capabilityWiring:自持 loader 的子装配域保持插件无关诊断面。\n\t\tif (capabilityWiring && passthroughCapabilityPluginIds.length > 0) {\n\t\t\tconst installedPluginIdSet = new Set(\n\t\t\t\t(options.installedCapabilityPlugins ?? []).map((plugin) => plugin.pluginId),\n\t\t\t);\n\t\t\t// Bundled-channel plugins (D-082 §4.9) ship with the host and load\n\t\t\t// without an install-store entry, so a suite declaration for one of\n\t\t\t// them is satisfiable even though it is absent from the installed\n\t\t\t// set (macCRM dogfood 2026-10-04: provider-failover worked while the\n\t\t\t// warning claimed it was missing).\n\t\t\tconst bundledDirNames = new Set(\n\t\t\t\tbundledCapabilityPluginRoots()\n\t\t\t\t\t.toolRoots.concat(bundledCapabilityPluginRoots().policyRoots)\n\t\t\t\t\t.flatMap((root) => (existsSync(root) ? readdirSync(root) : [])),\n\t\t\t);\n\t\t\tfor (const pluginId of passthroughCapabilityPluginIds) {\n\t\t\t\tif (installedPluginIdSet.has(pluginId)) continue;\n\t\t\t\tif (bundledDirNames.has(pluginId.split(\".\").pop() ?? \"\")) continue;\n\t\t\t\tcapabilityDiagnostics.push(\n\t\t\t\t\t`Suite \"${suiteId}\" capability \"${pluginId}\" has no installed active plugin; install it with agent-forge plugin install or remove the declaration`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tconst installedPluginManifestPaths: string[] = [];\n\t\tconst skippedInstalledPluginIds: string[] = [];\n\t\tfor (const plugin of options.installedCapabilityPlugins ?? []) {\n\t\t\tif (profilePluginIds.has(plugin.pluginId)) installedPluginManifestPaths.push(plugin.manifestPath);\n\t\t\telse skippedInstalledPluginIds.push(plugin.pluginId);\n\t\t}\n\t\tif (skippedInstalledPluginIds.length > 0) {\n\t\t\tcapabilityDiagnostics.push(\n\t\t\t\t`Installed capability plugins stay unloaded because the active profile did not select them: ${skippedInstalledPluginIds.sort().join(\", \")}`,\n\t\t\t);\n\t\t}\n\t\t// Bundled 分发通道(D-082 §4.9,批 1 工具批 / 批 3 策略批):发行物附带的第一方\n\t\t// 插件包作为数据文件随宿主分发,经与安装店完全相同的 manifest/jiti 通道装载;\n\t\t// 优先级在 installed 之后、目录发现之前(安装店显式安装 > bundled >\n\t\t// 目录发现)。这不是用户插件发现通道:内嵌默认面不受\n\t\t// discoverCapabilityPlugins 与 suite capabilities 声明门控——工具面\n\t\t// (coding-tools)沿用内嵌装配的无条件下发语义;策略面(四个默认策略插件,\n\t\t// 内嵌 installBootstrap* 时代随会话无条件安装)同样无条件下发且不受\n\t\t// noTools 门控;其余 bundled 候选按套件成员资格过滤。noTools(\"all\"/\n\t\t// \"builtin\",对照内嵌工具装配的跳过语义)只跳过工具面。\n\t\tconst bundledRoots = bundledCapabilityPluginRoots();\n\t\tconst bundledToolManifestPaths =\n\t\t\toptions.noTools === undefined ? discoverCapabilityPluginManifests(bundledRoots.toolRoots) : [];\n\t\tconst bundledPolicyManifestPaths = discoverCapabilityPluginManifests(bundledRoots.policyRoots);\n\t\tconst bundledManifestPaths = [...bundledToolManifestPaths, ...bundledPolicyManifestPaths];\n\t\tconst bundledManifestPathSet = new Set(bundledManifestPaths);\n\t\tconst manifestPaths = [\n\t\t\t...suiteLocalManifestPaths,\n\t\t\t...installedPluginManifestPaths,\n\t\t\t...bundledManifestPaths,\n\t\t\t...discoveredManifestPaths,\n\t\t\t...(options.capabilityPluginPaths ?? []),\n\t\t];\n\t\tconst explicitCandidatePaths = new Set([\n\t\t\t...suiteLocalManifestPaths,\n\t\t\t...installedPluginManifestPaths,\n\t\t\t...bundledManifestPaths,\n\t\t\t...(options.capabilityPluginPaths ?? []),\n\t\t]);\n\t\tconst loadedManifestPaths = new Set<string>();\n\t\tconst explicitManifestPaths = new Set<string>();\n\t\tconst candidatePaths: string[] = [];\n\t\tfor (const manifestPath of manifestPaths) {\n\t\t\tconst resolvedManifestPath = resolve(cwd, manifestPath);\n\t\t\tconst manifestIdentity = existsSync(resolvedManifestPath)\n\t\t\t\t? realpathSync(resolvedManifestPath)\n\t\t\t\t: resolvedManifestPath;\n\t\t\tif (loadedManifestPaths.has(manifestIdentity)) continue;\n\t\t\tloadedManifestPaths.add(manifestIdentity);\n\t\t\tif (explicitCandidatePaths.has(manifestPath)) explicitManifestPaths.add(manifestIdentity);\n\t\t\tcandidatePaths.push(manifestIdentity);\n\t\t}\n\t\t// Single-plugin manifest failures reject that plugin only (D-028); the\n\t\t// session keeps loading the remaining candidates. The D-073 host-version\n\t\t// range gate is semantic (not a parse failure): a manifest whose\n\t\t// declared hostVersion range excludes the running VERSION is rejected\n\t\t// with its own reason code, and a manifest without hostVersion loads\n\t\t// but emits a one-line diagnostic.\n\t\tconst manifestEntries: Array<{ path: string; manifest: PluginManifest }> = [];\n\t\tfor (const manifestPath of candidatePaths) {\n\t\t\ttry {\n\t\t\t\tconst manifest = await readCapabilityPluginManifestForOrdering(manifestPath);\n\t\t\t\tif (manifest.hostVersion !== undefined) {\n\t\t\t\t\tif (!satisfies(VERSION, manifest.hostVersion)) {\n\t\t\t\t\t\tawait recordRejection(\n\t\t\t\t\t\t\t\"host_version_incompatible\",\n\t\t\t\t\t\t\tmanifestPath,\n\t\t\t\t\t\t\tmanifest.id,\n\t\t\t\t\t\t\t`Plugin ${manifest.id} declares host version range \"${manifest.hostVersion}\", but the host is ${VERSION}. Upgrade the host into the declared range, or install a plugin version that supports host ${VERSION}.`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tcapabilityDiagnostics.push(\n\t\t\t\t\t\t`Capability plugin ${manifest.id} (${manifestPath}) does not declare \"hostVersion\"; it loads, but published plugins must declare a host semver range (e.g. \">=${VERSION}\").`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tmanifestEntries.push({ path: manifestPath, manifest });\n\t\t\t} catch (error) {\n\t\t\t\tawait recordRejection(\"invalid_manifest\", manifestPath, undefined, rejectionMessage(error));\n\t\t\t}\n\t\t}\n\t\t// Duplicate plugin IDs keep the first candidate in discovery order and\n\t\t// reject the later duplicates. When suite capability wiring is on, the\n\t\t// external plugin pool is filtered by `associations.plugins` (方案系统\n\t\t// M3): the project-level pool (cwd/.agent-forge/plugins) is the third\n\t\t// layer and always passes; every other manifest must match an\n\t\t// association exactly. Explicit capabilityPluginPaths are caller intent\n\t\t// and bypass the filter; filtered plugins and dangling associations\n\t\t// surface as suite diagnostics, never as errors.\n\t\tconst poolFilter = capabilityWiring\n\t\t\t? {\n\t\t\t\t\tsuite: suiteWorkspace.suite,\n\t\t\t\t\tdecide: (manifestId: string, manifestPath: string) =>\n\t\t\t\t\t\tdecideSuiteCapabilityPlugin(suiteWorkspace.suite, { manifestId, manifestPath }, { cwd }),\n\t\t\t\t}\n\t\t\t: undefined;\n\t\tconst seenPluginIds = new Set<string>();\n\t\tconst uniqueEntries: Array<{ path: string; manifest: PluginManifest }> = [];\n\t\tconst discoveredPluginIds: string[] = [];\n\t\tfor (const entry of manifestEntries) {\n\t\t\tdiscoveredPluginIds.push(entry.manifest.id);\n\t\t\tconst bundledCandidate = bundledManifestPathSet.has(entry.path);\n\t\t\t// Bundled 层过滤:bundled 装配豁免集合(coding-tools 工具面 + 四个默认\n\t\t\t// 策略插件 + config 门控的 provider-failover,BUNDLED_WIRING_EXEMPT_\n\t\t\t// PLUGIN_IDS)不受 suite capabilities 声明门控,与内嵌装配同语义——\n\t\t\t// failover 的\"配置存在即装配\"不是套件声明可关闭的面(disabledPluginIds\n\t\t\t// 仍可显式禁用);其余 bundled 候选与 installed 层同法——\n\t\t\t// capabilityWiring 开启时插件 id 必须命中 capabilityPackageIds(套件\n\t\t\t// 未选中的包静默缺席),关闭(自持 loader 的宿主)全收,保底拿到产品\n\t\t\t// 默认面。disabledPluginIds(既有用户面)作用于全部 bundled 候选。\n\t\t\tif (bundledCandidate) {\n\t\t\t\tif (!BUNDLED_WIRING_EXEMPT_PLUGIN_IDS.has(entry.manifest.id) && capabilityWiring) {\n\t\t\t\t\tif (!capabilityPackageIds.includes(entry.manifest.id)) continue;\n\t\t\t\t}\n\t\t\t\tif (disabledPluginIdSet.has(entry.manifest.id)) continue;\n\t\t\t}\n\t\t\tif (poolFilter && !explicitManifestPaths.has(entry.path)) {\n\t\t\t\tconst decision = poolFilter.decide(entry.manifest.id, entry.path);\n\t\t\t\tif (!decision.keep) {\n\t\t\t\t\tif (decision.diagnostic) capabilityDiagnostics.push(decision.diagnostic);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (seenPluginIds.has(entry.manifest.id)) {\n\t\t\t\t// Bundled 候选与更高优先层(suiteLocal/installed/前一根 bundled)同 id\n\t\t\t\t// 时按发现优先级静默让位(安装店显式安装 > bundled;产品自带副本被\n\t\t\t\t// 遮蔽是设计内的优先级,不是冲突)。目录发现层的重复 id 保持既有\n\t\t\t\t// duplicate_plugin_id rejection(第三方同 id 冲突需要显形)。\n\t\t\t\tif (!bundledCandidate) {\n\t\t\t\t\tawait recordRejection(\n\t\t\t\t\t\t\"duplicate_plugin_id\",\n\t\t\t\t\t\tentry.path,\n\t\t\t\t\t\tentry.manifest.id,\n\t\t\t\t\t\t`Capability plugin is already loaded: ${entry.manifest.id}; the first manifest in discovery order wins`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tseenPluginIds.add(entry.manifest.id);\n\t\t\tuniqueEntries.push(entry);\n\t\t}\n\t\tif (poolFilter) {\n\t\t\tcapabilityDiagnostics.push(...suiteDanglingPluginAssociations(poolFilter.suite, discoveredPluginIds));\n\t\t}\n\t\t// Required-capability shortfalls reject the dependent plugin and, by\n\t\t// fixpoint, everything that (transitively) required it. Optional\n\t\t// requirements never reject. Combination-level failures that\n\t\t// resolvePluginCapabilityOrder still detects (duplicate capability\n\t\t// identity, dependency cycles) fail the whole startup explicitly.\n\t\tconst capabilityIdentity = (id: string, version: number): string => `${id}\\u0000${version}`;\n\t\tconst survivors = new Set(uniqueEntries);\n\t\tlet removedInLastPass = true;\n\t\twhile (removedInLastPass) {\n\t\t\tremovedInLastPass = false;\n\t\t\tconst providers = new Set<string>();\n\t\t\tfor (const entry of survivors) {\n\t\t\t\tfor (const declaration of entry.manifest.provides ?? []) {\n\t\t\t\t\tproviders.add(capabilityIdentity(declaration.id, declaration.version));\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const entry of [...survivors]) {\n\t\t\t\tconst missing = (entry.manifest.requires ?? []).filter(\n\t\t\t\t\t(requirement) =>\n\t\t\t\t\t\t!requirement.optional && !providers.has(capabilityIdentity(requirement.id, requirement.version)),\n\t\t\t\t);\n\t\t\t\tif (missing.length === 0) continue;\n\t\t\t\tawait recordRejection(\n\t\t\t\t\t\"missing_dependency\",\n\t\t\t\t\tentry.path,\n\t\t\t\t\tentry.manifest.id,\n\t\t\t\t\t`Plugin capability is required but unavailable: ${missing\n\t\t\t\t\t\t.map((requirement) => `${requirement.id}@${requirement.version}`)\n\t\t\t\t\t\t.join(\", \")} (${entry.manifest.id})`,\n\t\t\t\t);\n\t\t\t\tsurvivors.delete(entry);\n\t\t\t\tremovedInLastPass = true;\n\t\t\t}\n\t\t}\n\t\tconst pathByManifest = new Map([...survivors].map((entry) => [entry.manifest, entry.path] as const));\n\t\t// 按需挂载(插件按需挂载与能力手册设计 §4/§5):activation \"on-demand\"\n\t\t// 的幸存插件注册但不进初始激活集——卡片(一行描述)与手册路径在此定型并\n\t\t// 注册进会话,由 capability_mount 按插件粒度激活,unmount 仅摘 schema。\n\t\tconst deferredCapabilityCards = [...survivors]\n\t\t\t.filter((entry) => entry.manifest.activation === \"on-demand\")\n\t\t\t.map((entry) => ({\n\t\t\t\tpluginId: entry.manifest.id,\n\t\t\t\tdescription: entry.manifest.description,\n\t\t\t\tmanualPath:\n\t\t\t\t\tentry.manifest.manual === undefined ? undefined : resolve(dirname(entry.path), entry.manifest.manual),\n\t\t\t}));\n\t\tif (deferredCapabilityCards.length > 0) {\n\t\t\tsession.registerDeferredCapabilityCards(deferredCapabilityCards);\n\t\t}\n\t\t// 生图槽位注入供料(供应商能力槽位设计 §3.3):settings 槽位经 settings-manager\n\t\t// 校验后的读面取(非法形状已 fail-closed 丢弃并记 warning),目录快照经\n\t\t// ModelRuntime 投影 models.json 登记项(装配期静态数据)。\n\t\tconst imageGenerationSlot = settingsManager.getCapabilitiesSettings()?.imageGeneration;\n\t\tconst imageModelCatalog = modelRuntime.getImageModelCatalog();\n\t\tfor (const manifest of resolvePluginCapabilityOrder([...survivors].map((entry) => entry.manifest))) {\n\t\t\tconst manifestPath = pathByManifest.get(manifest);\n\t\t\t// v8 ignore next -- 顺序解析返回的 manifest 均来自同一 survivors 集合,路径恒存在\n\t\t\tif (!manifestPath)\n\t\t\t\tthrow new Error(t(\"Capability plugin manifest path is unavailable: {id}\", { id: manifest.id }));\n\t\t\t// 宿主装配事实注入(公共 configOverride 通道):各插件分支注释记载注入\n\t\t\t// 内容与取值链;caller 的 capabilityPluginConfigs[插件 id](D-082 批 1\n\t\t\t// 新增会话选项)按 configOverride 既有分层合并在宿主事实之上(顶层键\n\t\t\t// caller 赢),插件入口的 agent-dir 配置文件仍合并在其上,用户显式配置\n\t\t\t// 保持最终决定权。\n\t\t\tlet hostConfigOverride: PluginConfig | undefined;\n\t\t\t// CLI 自动池化(承载退役切片 1,D-075 S4 第三批收敛):宿主声明自身\n\t\t\t// 入口可信时改写插件 config 的 runnerEntryAuto(原 builtin 注入链的\n\t\t\t// selfInvocationPool 旗标退役);插件入口的 agent-dir 配置文件仍合并\n\t\t\t// 在其上,用户显式配置保持最终决定权。\n\t\t\tif (manifest.id === SUBAGENT_DELEGATE_PACKAGE_ID && options.subagentPoolFromSelfInvocation === true) {\n\t\t\t\thostConfigOverride = { runnerEntryAuto: true };\n\t\t\t}\n\t\t\t// 记忆档位注入(D-075 S4 第四批):显式定档与 settings.json 持久档位经\n\t\t\t// 公共 configOverride 通道合并进 memory 插件包 manifest config——包 entry\n\t\t\t// 按同一解析链定档(显式 > env > settings > 旧别名 > off);agent-dir\n\t\t\t// 配置文件(capabilities/builtin.memory.json)仍合并在其上,用户显式\n\t\t\t// 配置保持最终决定权。mode=off 的包已在上面的成员资格门控中排除,\n\t\t\t// 不会走到这里。\n\t\t\tif (manifest.id === MEMORY_PACKAGE_ID) {\n\t\t\t\thostConfigOverride = {\n\t\t\t\t\t...hostConfigOverride,\n\t\t\t\t\t...(memoryModeOption === undefined ? {} : { memoryMode: memoryModeOption }),\n\t\t\t\t\t...(settingsMemoryMode === undefined ? {} : { memorySettingsMode: settingsMemoryMode }),\n\t\t\t\t};\n\t\t\t}\n\t\t\t// 生图槽位注入(供应商能力槽位设计 §3.3):settings 槽位(provider/model,\n\t\t\t// model 可省)与 models.json 生图目录快照经公共 configOverride 通道注入\n\t\t\t// image-generation 插件包;插件按六层取值链消费(设计 §3.2)。槽位缺省时\n\t\t\t// 只注入快照——插件回落到 env/主推断/唯一候选推断。\n\t\t\tif (manifest.id === IMAGE_GENERATION_PACKAGE_ID) {\n\t\t\t\thostConfigOverride = {\n\t\t\t\t\t...hostConfigOverride,\n\t\t\t\t\t...(imageGenerationSlot === undefined\n\t\t\t\t\t\t? {}\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\timageGeneration: {\n\t\t\t\t\t\t\t\t\tprovider: imageGenerationSlot.provider,\n\t\t\t\t\t\t\t\t\t...(imageGenerationSlot.model === undefined ? {} : { model: imageGenerationSlot.model }),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}),\n\t\t\t\t\timageModelCatalog,\n\t\t\t\t};\n\t\t\t}\n\t\t\t// 默认编码工具会话事实注入(D-082 批 1):cwd 用会话 cwd,read/bash 选项\n\t\t\t// 取值来源对齐内嵌 installSessionBootstrapTools 时代的 settings 解析链\n\t\t\t// (SettingsManager.getImageAutoResize/getShellCommandPrefix/getShellPath),\n\t\t\t// 形状即插件包 CodingToolsPluginConfigV1;未定义的设置键省略(插件侧\n\t\t\t// 保持自身缺省值,与内嵌时代传 undefined 同语义)。\n\t\t\tif (manifest.id === CODING_TOOLS_PACKAGE_ID) {\n\t\t\t\tconst autoResizeImages = settingsManager.getImageAutoResize();\n\t\t\t\tconst shellCommandPrefix = settingsManager.getShellCommandPrefix();\n\t\t\t\tconst shellPath = settingsManager.getShellPath();\n\t\t\t\thostConfigOverride = {\n\t\t\t\t\t...hostConfigOverride,\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tcwd,\n\t\t\t\t\tread: { autoResizeImages },\n\t\t\t\t\tbash: {\n\t\t\t\t\t\t...(shellCommandPrefix === undefined ? {} : { commandPrefix: shellCommandPrefix }),\n\t\t\t\t\t\t...(shellPath === undefined ? {} : { shellPath }),\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\t// provider-failover 配置注入(D-082 批 3b):settings `failover` 节存在\n\t\t\t// 时经 configOverride 通道注入 `{version: 1, failover: <节点原样>}`(节点\n\t\t\t// 来源与内嵌装配时代同一读面:settingsManager.getFailoverSettings 原样\n\t\t\t// 透传合并层对象,解析与校验收在插件包内);节点不存在则不注入——插件\n\t\t\t// 工厂自守卫 no-op(不注册任何面)。caller 的 capabilityPluginConfigs\n\t\t\t// 仍按既有分层合并在其上(顶层键 caller 赢),agent-dir 配置文件保持\n\t\t\t// 用户最终决定权。\n\t\t\tif (manifest.id === PROVIDER_FAILOVER_PACKAGE_ID) {\n\t\t\t\tconst failoverSettings = settingsManager.getFailoverSettings();\n\t\t\t\t// settings 层合并对象是 JSON 数据,仅静态接口不带索引签名;经公共\n\t\t\t\t// 守卫收窄为 PluginConfigValue 后节点原样透传(真实 settings 数据\n\t\t\t\t// 恒为 JSON,守卫不构成行为分支),解析与校验收在插件包内。\n\t\t\t\tif (failoverSettings !== undefined && isPluginConfigValue(failoverSettings)) {\n\t\t\t\t\thostConfigOverride = { version: 1, failover: failoverSettings };\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst callerConfigOverride = options.capabilityPluginConfigs?.[manifest.id];\n\t\t\tconst configOverride =\n\t\t\t\thostConfigOverride === undefined\n\t\t\t\t\t? callerConfigOverride\n\t\t\t\t\t: { ...hostConfigOverride, ...(callerConfigOverride ?? {}) };\n\t\t\ttry {\n\t\t\t\tawait session.loadCapabilityPluginManifest(manifestPath, {\n\t\t\t\t\t...(configOverride === undefined ? {} : { configOverride }),\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tawait recordRejection(\"plugin_load_failed\", manifestPath, manifest.id, rejectionMessage(error));\n\t\t\t}\n\t\t}\n\t\t// Plugin-owned context restoration runs only after all manifests are loaded.\n\t\t// The persisted session remains the source of truth; request-time transforms\n\t\t// must never be written back into that history implicitly.\n\t\tif (hasExistingSession && options.contextStrategyName) {\n\t\t\tawait session.replaceContext(existingSession.messages);\n\t\t}\n\t} catch (error) {\n\t\tawait session.dispose();\n\t\tthrow error;\n\t}\n\t// 会话创建完成打点(设计 §5.2):创建/恢复路径在装配全部完成后落一行 info。\n\thostLogger?.info(\"sdk\", \"agent session created\", {\n\t\tsessionId: session.sessionId,\n\t\tfields: {\n\t\t\tsuite: suiteId,\n\t\t\t...(model === undefined ? {} : { model: `${model.provider}/${model.id}` }),\n\t\t\ttrace: options.traceEnabled !== false,\n\t\t},\n\t});\n\n\treturn {\n\t\tsession,\n\t\tmodelFallbackMessage,\n\t\tpluginRejections: Object.freeze(pluginRejections.slice()),\n\t\tsuiteDiagnostics: Object.freeze([\n\t\t\t...suiteAssembly.collectDiagnostics(),\n\t\t\t...capabilityDiagnostics,\n\t\t\t...suitePreferenceDiagnostics,\n\t\t]),\n\t\t...(suiteAssembly.pluginProfile === undefined ? {} : { pluginProfile: suiteAssembly.pluginProfile }),\n\t\tresolvedAgentProfile,\n\t};\n}\n\n/**\n * Result from createStableAgentSession (B-S2b③-S2).\n *\n * The stable root philosophy: new consumers program against the facade and\n * the SessionAPI projection, never against the bare AgentSession — the raw\n * session stays an internal adapter behind the stable surface, so no `session`\n * field is exposed here.\n */\nexport interface CreateStableAgentSessionResult {\n\t/** Stable session facade v1 over the created session (D-043 stable root runtime center). */\n\tfacade: CodingAgentFacadeV1;\n\t/** Public session mechanism projection (`AgentSession.getSessionAPI()`), the stable read/write face for host adapters and embedded consumers. */\n\tsessionAPI: SessionAPI;\n\t/**\n\t * Create-time model fallback diagnostic, mirroring\n\t * `CreateAgentSessionResult.modelFallbackMessage`: set when the session could\n\t * not be created with the model that was restored from persisted state (or\n\t * when no model at all was available) and the normal resolution ran instead.\n\t * `undefined` when no fallback happened. It describes the create step, not\n\t * the session, which is why it rides the create result instead of a facade\n\t * member (D-061).\n\t */\n\tmodelFallbackMessage?: string;\n}\n\n/**\n * Create a stable agent session: the same assembly as createAgentSession\n * (zero behavior difference), returned as the stable facade pair instead of\n * the raw session (B-S2b③-S2).\n *\n * @example\n * ```typescript\n * const { facade, sessionAPI } = await createStableAgentSession({\n * streamFn: mockStreamFn,\n * sessionManager: SessionManager.inMemory(),\n * });\n * await facade.prompt(\"hello\");\n * console.log(sessionAPI.getSessionId());\n * ```\n */\nexport async function createStableAgentSession(\n\toptions: CreateAgentSessionOptions = {},\n): Promise<CreateStableAgentSessionResult> {\n\tconst result = await createAgentSession(options);\n\treturn {\n\t\tfacade: createCodingAgentFacade(result.session),\n\t\tsessionAPI: result.session.getSessionAPI(),\n\t\t// Pure passthrough of the legacy result's create-time diagnostic (D-061):\n\t\t// same value, same assembly, no behavior change.\n\t\tmodelFallbackMessage: result.modelFallbackMessage,\n\t};\n}\n\n/**\n * Result from createStableAgentSessionRuntime (D-063).\n *\n * The stable root philosophy: a consumer that orchestrates session replacement\n * programs against the runtime facade, never against the bare\n * `AgentSessionRuntime`/`AgentSession` — both stay internal adapters behind the\n * stable surface, so no `runtime`/`session` field is exposed here. The current\n * session's v1 face is reachable through\n * `runtimeFacade.getSessionFacade()`.\n */\nexport interface CreateStableAgentSessionRuntimeResult {\n\t/** Stable runtime facade v1 over the created runtime (阶段 4 slice 3 runtime 面, §3.5). */\n\truntimeFacade: CodingAgentRuntimeFacadeV1;\n}\n\n/**\n * Create a stable agent session runtime: the same assembly as\n * createAgentSessionRuntime (zero behavior difference), returned as the stable\n * runtime facade instead of the raw runtime (D-063, 阶段 4 close-out).\n *\n * @example\n * ```typescript\n * const { runtimeFacade } = await createStableAgentSessionRuntime(createRuntime, {\n * cwd: process.cwd(),\n * agentDir: getAgentDir(),\n * sessionManager: SessionManager.create(process.cwd()),\n * });\n * await runtimeFacade.newSession();\n * // Re-read after a replacement: the accessor projects the current session.\n * const facade = runtimeFacade.getSessionFacade();\n * await facade.prompt(\"hello\");\n * ```\n */\nexport async function createStableAgentSessionRuntime(\n\tcreateRuntime: CreateAgentSessionRuntimeFactory,\n\toptions: {\n\t\tcwd: string;\n\t\tagentDir: string;\n\t\tsessionManager: SessionManager;\n\t\tsessionStartEvent?: SessionStartMetadata;\n\t},\n): Promise<CreateStableAgentSessionRuntimeResult> {\n\tconst runtime = await createAgentSessionRuntime(createRuntime, options);\n\treturn { runtimeFacade: createCodingAgentRuntimeFacade(runtime) };\n}\n"]}
1
+ {"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../../src/core/sdk.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readdirSync, realpathSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n\tAgent,\n\ttype AgentMessage,\n\ttype StreamFn,\n\tsetDefaultStreamFn,\n\ttype ThinkingLevel,\n} from \"@agent-forge/agent-core\";\nimport type { CredentialStore } from \"@agent-forge/ai\";\nimport {\n\ttype Api,\n\ttype AssistantMessageEventStream,\n\ttype Context,\n\tclampThinkingLevel,\n\ttype Message,\n\ttype Model,\n\ttype SimpleStreamOptions,\n\tstreamSimple,\n} from \"@agent-forge/ai/compat\";\nimport type { MemoryModeV1, MemoryStorageComponentsV1 } from \"@agent-forge/plugin-sdk\";\nimport { createSubagentMailbox, type SubagentMailboxV1 } from \"@agent-forge/protocol/subagent\";\nimport { satisfies } from \"semver\";\nimport { BUILTIN_CAPABILITY_PACKAGE_IDS } from \"../capabilities/builtin.ts\";\nimport { CONFIG_DIR_NAME, getAgentDir, VERSION } from \"../config.ts\";\nimport type { DurableServiceV1 } from \"../durable/durable-service.ts\";\nimport type { HostFactsV1 } from \"../plugins/ecosystem/types.ts\";\nimport type {\n\tObservabilityHostAdapterV1,\n\tObservabilityPluginFacadeV1,\n\tTraceSinkOptionsV1,\n} from \"../plugins/observability-types.ts\";\nimport { profileIdentitiesCompatible } from \"../profile/identity.ts\";\nimport type {\n\tBuiltinPluginManifestOverridesV1,\n\tBuiltinPluginProfileIdV1,\n\tBuiltinPluginProfileResolutionV1,\n} from \"../profile/plugin-profiles.ts\";\nimport type { VerifiedToolPluginV1 } from \"../profile/profile-assembly.ts\";\nimport { buildResolvedAgentProfileV1, type ResolvedAgentProfileV1 } from \"../suites/resolved-agent-profile.ts\";\nimport {\n\tcreateSuiteAssembly,\n\tdecideSuiteCapabilityPlugin,\n\tfilterSuiteSkills,\n\treadSessionSuiteBinding,\n\tresolveSuiteId,\n\tSUITE_ENV_VAR,\n\tSUITE_SESSION_ENTRY_TYPE,\n\tSuiteRebindError,\n\tsuiteDanglingPluginAssociations,\n} from \"../suites/suite-loader.ts\";\nimport { resolvePath } from \"../utils/paths.ts\";\nimport { AgentSession } from \"./agent-session.ts\";\nimport { type CreateAgentSessionRuntimeFactory, createAgentSessionRuntime } from \"./agent-session-runtime.ts\";\nimport { listAgentSessions, readAgentSession } from \"./agent-session-store.ts\";\nimport { formatNoModelsAvailableMessage } from \"./auth-guidance.ts\";\nimport { DEFAULT_THINKING_LEVEL } from \"./defaults.ts\";\nimport type { AgentTaskSettledEventDataV1 } from \"./extensions/bootstrap-lifecycle.ts\";\nimport { discoverCapabilityPluginManifests, parseCapabilityPluginManifest } from \"./extensions/capability-plugin.ts\";\nimport { resolvePluginCapabilityOrder } from \"./extensions/capability-runtime.ts\";\nimport { isPluginConfigValue } from \"./extensions/capability-runtime-manifest.ts\";\nimport type { TraceServiceV1 } from \"./extensions/capability-runtime-types.ts\";\nimport type {\n\tAgentCompositionAPI,\n\tAgentTaskAdapter,\n\tAgentTaskSessionSummaryV1,\n\tInteractionHostV1,\n\tLoggerRecord,\n\tPluginConfig,\n\tPluginManifest,\n\tPluginRejection,\n\tSessionAPI,\n} from \"./extensions/index.ts\";\nimport type { SubagentCommunicationWiringV1 } from \"./extensions/public-api.ts\";\nimport { type CodingAgentFacadeV1, createCodingAgentFacade } from \"./facade/coding-agent-facade.ts\";\nimport {\n\ttype CodingAgentRuntimeFacadeV1,\n\tcreateCodingAgentRuntimeFacade,\n} from \"./facade/coding-agent-runtime-facade.ts\";\nimport { t } from \"./i18n/index.ts\";\nimport type { HostLogger } from \"./logger.ts\";\nimport { convertToLlm } from \"./messages.ts\";\nimport { findExactModelReferenceMatch, findInitialModel, isValidThinkingLevel } from \"./model-resolver.ts\";\nimport { ModelRuntime } from \"./model-runtime.ts\";\nimport type { ResourceLoader } from \"./resource-loader.ts\";\nimport { DefaultResourceLoader } from \"./resource-loader.ts\";\nimport { getDefaultSessionDir, getTraceFilePathForSession, SessionManager } from \"./session-manager.ts\";\nimport type { SessionStartMetadata } from \"./session-start.ts\";\nimport { SettingsManager } from \"./settings-manager.ts\";\nimport type { Skill } from \"./skills.ts\";\nimport { time } from \"./timings.ts\";\nimport type { ToolName } from \"./tools/index.ts\";\nimport type { ToolDefinition } from \"./tools/tool-definition.ts\";\n\n// Preserve the pre-0.81 fallback for extensions that construct Agent instances\n// or invoke low-level agent loops without supplying streamFn. Agent core remains\n// provider-agnostic and does not import pi-ai/compat itself.\nsetDefaultStreamFn(streamSimple);\n\n/**\n * One background-delegation settlement line as written by the delegate's\n * settlement observer (subagent-delegate.ts): bounded JSON whose `sessionId`\n * is the CHILD session id — the parent session id is supplied by the dispatch\n * side (AgentSession), so the line field maps to the event's `taskSessionId`.\n */\ninterface AgentTaskSettledDigestFactsV1 {\n\ttaskId: string;\n\ttaskSessionId: string;\n\tstatus: AgentTaskSettledEventDataV1[\"status\"];\n\treasonCode?: string;\n}\n\nconst AGENT_TASK_SETTLED_STATUSES: ReadonlySet<string> = new Set([\n\t\"queued\",\n\t\"admitted\",\n\t\"running\",\n\t\"succeeded\",\n\t\"failed\",\n\t\"cancelled\",\n\t\"timed_out\",\n\t\"drain_timeout\",\n\t\"runner_lost\",\n]);\n\n/** Parses one settlement line; undefined for any shape outside the contract. */\nfunction parseAgentTaskSettledDigestLine(line: string): AgentTaskSettledDigestFactsV1 | undefined {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(line);\n\t} catch {\n\t\treturn undefined;\n\t}\n\tif (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) return undefined;\n\tconst record = parsed as Record<string, unknown>;\n\tif (typeof record.taskId !== \"string\" || record.taskId === \"\") return undefined;\n\tif (typeof record.sessionId !== \"string\" || record.sessionId === \"\") return undefined;\n\tif (typeof record.status !== \"string\" || !AGENT_TASK_SETTLED_STATUSES.has(record.status)) return undefined;\n\tif (record.reasonCode !== undefined && (typeof record.reasonCode !== \"string\" || record.reasonCode === \"\")) {\n\t\treturn undefined;\n\t}\n\treturn {\n\t\ttaskId: record.taskId,\n\t\t// 行内 sessionId 是子会话 id(复审 M1):映射为事件 data 的 taskSessionId。\n\t\ttaskSessionId: record.sessionId,\n\t\tstatus: record.status as AgentTaskSettledEventDataV1[\"status\"],\n\t\t...(record.reasonCode === undefined ? {} : { reasonCode: record.reasonCode }),\n\t};\n}\n\n/**\n * 后台委派结算行 → agent.task.settled@1 派发(第 4 期轨迹闭合),并返回解析出的\n * facts 供调用方复用(结算回注构造,D-060 裁决 12——同一行不再二次 parse)。行解析\n * 失败或 status 不属九值枚举时降级为仅 hostLogger warn 并返回 undefined。\n * 会话缺席(agentSessionRef.current 在会话创建前为 undefined)或已 dispose(旧 runtime revokeState →\n * hasLifecycleEvent false → 派发助手 no-op)时安全跳过(facts 仍返回,调用方自行守卫)。\n */\nexport function deliverAgentTaskSettledDigestLine(\n\tsession: Pick<AgentSession, \"dispatchAgentTaskSettled\"> | undefined,\n\tline: string,\n\thostLogger?: HostLogger,\n): AgentTaskSettledDigestFactsV1 | undefined {\n\tconst facts = parseAgentTaskSettledDigestLine(line);\n\tif (facts === undefined) {\n\t\thostLogger?.warn(\"sdk\", \"background delegation settlement line is not a valid agent.task.settled source\", {\n\t\t\tcause: line,\n\t\t});\n\t\treturn undefined;\n\t}\n\tsession?.dispatchAgentTaskSettled(facts);\n\treturn facts;\n}\n\n/** One verified active installation participating in installed-code-loading (D-075 S2). */\nexport interface InstalledCapabilityPluginV1 {\n\treadonly pluginId: string;\n\treadonly manifestPath: string;\n}\n\n/**\n * Plugin id of the standalone observability package (D-075 S4 second batch).\n * When `traceEnabled` is not `false`, the assembler adds it to the installed\n * plugin membership set so the installed package joins the session through\n * the same loading path as every other plugin package.\n */\nconst OBSERVABILITY_PACKAGE_ID = \"agent-forge.plugin.observability\";\n\n/**\n * Plugin id of the standalone subagent-delegate package (D-075 S4 third\n * batch). When `subagentPoolFromSelfInvocation` is true (the real CLI\n * assembly declaring its own process entry trustworthy), the assembler\n * overrides the plugin's manifest config with `runnerEntryAuto: true` at load\n * — the config key the package's auto-pooling path consumes (the former host\n * `selfInvocationPool` option is retired). The agent-dir config file still\n * merges over it inside the plugin entry, so users keep the final say.\n */\nconst SUBAGENT_DELEGATE_PACKAGE_ID = \"agent-forge.plugin.subagent-delegate\";\n\n/**\n * Plugin id of the standalone memory package (D-075 S4 fourth batch). When the\n * suite declares `builtin.memory` and the resolved memory mode is light/full,\n * the assembler adds the package to the installed-plugin membership set and\n * overrides its manifest config with `memoryMode`/`memorySettingsMode` at load\n * — the config keys the package's entry resolves with the exact precedence\n * the embedded capability used to have (explicit host option → env →\n * settings.json → legacy alias → off). Mode off keeps the package out of the\n * membership set entirely (禁用 = 不装配, plus one startup diagnostic).\n */\nconst MEMORY_PACKAGE_ID = \"agent-forge.plugin.memory\";\n\n/**\n * Plugin id of the standalone image-generation package (供应商能力槽位设计\n * §3.3 装配注入): at load the assembler overrides its manifest config with the\n * settings slot (`capabilities.imageGeneration`, validated fail-closed by\n * `SettingsManager.getCapabilitiesSettings()`) plus the models.json image-model\n * catalog snapshot (`imageModelCatalog`, projected by\n * `ModelRuntime.getImageModelCatalog()`) — the exact config keys the package's\n * capability reads (`api.config.imageGeneration` / `api.config.imageModelCatalog`).\n * The agent-dir config file still merges over it inside the plugin entry, so\n * users keep the final say.\n */\nconst IMAGE_GENERATION_PACKAGE_ID = \"agent-forge.plugin.image-generation\";\n\n/**\n * Plugin id of the standalone coding-tools package (D-082 批 1, S6 工具批):\n * the default coding tools (read/write/edit/bash/powershell/grep/find/ls) live\n * in the `plugins/coding-tools` package and assemble through the bundled\n * distribution channel (§4.9) instead of the retired embedded\n * bootstrap-tools install. At load the assembler merges the\n * session facts the embedded install used to receive as direct options — the\n * working directory plus the settings-resolved read/bash options — into the\n * manifest config (`{version: 1, cwd, read, bash}`), the exact shape the\n * package's `CodingToolsPluginConfigV1` consumes. The agent-dir config file\n * still merges over it inside the plugin entry, so users keep the final say.\n */\nconst CODING_TOOLS_PACKAGE_ID = \"agent-forge.plugin.coding-tools\";\n\n/**\n * Plugin id of the provider-failover package (D-082 批 3b): the primary/backup\n * provider failover (设计 供应商能力槽位与主备切换 §4) lives in the\n * `plugins/provider-failover` package and assembles through the bundled\n * distribution channel (§4.9) instead of the retired embedded install. Unlike\n * the bundled default face it is NOT a default policy: settings `failover`\n * 节存在时宿主经 configOverride 通道注入 `{version: 1, failover: <节点原样>}`\n * (节点不存在则不注入,插件工厂自守卫 no-op)——\"配置存在即装配\"是内嵌时代\n * 语义,因此它不受 suite capabilities 声明门控(见装配豁免集合)。failover\n * wrapper 以 priority -100 注册(契约 A),无论装载顺序都在链最外层。\n */\nconst PROVIDER_FAILOVER_PACKAGE_ID = \"agent-forge.plugin.provider-failover\";\n\n/**\n * Bundled 默认面插件 id 集合(D-082 批 3):随发行物 bundled 分发、不受 suite\n * capabilities 声明门控的第一方默认插件——内嵌时代的默认工具面(coding-tools,\n * 批 1)与四个默认策略插件(agent-loop-policy / retry-policy / overflow-policy /\n * compaction-policy,批 3 退役的内嵌 installBootstrap* 安装)。disabledPluginIds\n * 仍可逐个禁用其中任何一个。\n */\nconst BUNDLED_DEFAULT_PLUGIN_IDS: ReadonlySet<string> = new Set([\n\tCODING_TOOLS_PACKAGE_ID,\n\t\"agent-forge.plugin.agent-loop-policy\",\n\t\"agent-forge.plugin.retry-policy\",\n\t\"agent-forge.plugin.overflow-policy\",\n\t\"agent-forge.plugin.compaction-policy\",\n]);\n\n/**\n * Bundled 装配豁免集合(D-082 批 3b):bundled 候选中不受 suite capabilities\n * 声明门控的插件 id——默认面({@link BUNDLED_DEFAULT_PLUGIN_IDS},五 id)加上\n * config 门控可选能力 provider-failover(第六 id,config 门控豁免而非默认策略:\n * settings `failover` 节存在即装配,与内嵌装配同语义;节点不存在时插件工厂\n * 自守卫 no-op)。disabledPluginIds 仍可禁用其中任何一个。\n */\nconst BUNDLED_WIRING_EXEMPT_PLUGIN_IDS: ReadonlySet<string> = new Set([\n\t...BUNDLED_DEFAULT_PLUGIN_IDS,\n\tPROVIDER_FAILOVER_PACKAGE_ID,\n]);\n\n/**\n * Bundled 默认策略包的目录名(plugins/ 工作副本与发行物 bundled-plugins/ 快照\n * 同名)。与 {@link BUNDLED_DEFAULT_PLUGIN_IDS} 的四个策略 id 一一对应。\n */\nconst BUNDLED_DEFAULT_POLICY_PACKAGES = [\n\t\"agent-loop-policy\",\n\t\"retry-policy\",\n\t\"overflow-policy\",\n\t\"compaction-policy\",\n] as const;\n\n/**\n * Bundled distribution roots (D-082 §4.9 bundled 分发通道):按工具面与策略面\n * 分组的插件目录,其 plugin.json 清单加入候选池。两组各自探测两种布局,目录\n * 不存在即跳过:\n *\n * - Released form: the build copies built plugin packages to\n * `<packageRoot>/bundled-plugins/<name>/` (data files, not npm deps).\n * - Dev repository form: the repo-root working copies of the packages this\n * batch migrated (`<repoRoot>/plugins/coding-tools` — 批 1;四个策略包 — 批 3;\n * provider-failover — 批 3b).\n * Sibling first-party packages keep their install-store assembly (D-075\n * S4/S5 semantics, pinned by the ecosystem assembly tests) until their own\n * migration batch (S7-S9) widens this root.\n *\n * 工具面(coding-tools)受 noTools 整层跳过(对照内嵌工具装配的跳过语义);\n * 策略面不受 noTools 门控——内嵌 installBootstrap* 时代它们随会话无条件安装。\n *\n * The package root is derived from this module's URL: src runs sit at\n * `src/core/`, unbundled dist runs at `dist/core/` (both two levels up), and\n * the Node bundle runs at `dist/bundle/` (three levels up). Depth candidates\n * are tried in order and the first ancestor carrying a `package.json` wins.\n */\nfunction bundledCapabilityPluginRoots(): { toolRoots: string[]; policyRoots: string[] } {\n\tconst moduleDir = fileURLToPath(new URL(\".\", import.meta.url));\n\tlet packageRoot: string | undefined;\n\tfor (const depth of [2, 3]) {\n\t\tlet candidate = moduleDir;\n\t\tfor (let index = 0; index < depth; index++) candidate = dirname(candidate);\n\t\tif (existsSync(join(candidate, \"package.json\"))) {\n\t\t\tpackageRoot = candidate;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (packageRoot === undefined) return { toolRoots: [], policyRoots: [] };\n\tconst toolRoots: string[] = [];\n\tconst policyRoots: string[] = [];\n\t// Dev repository layout first: the repo-root plugins/ working copies (two\n\t// levels above the package root; exist only inside a source checkout).\n\t// When both roots exist the fresh working copy must win — the bundled copy\n\t// is a build-time snapshot that lags plugin src until the next root build,\n\t// and letting it shadow the working copy would silently run stale tool\n\t// code in dev (review finding, D-082 批 1). check:plugin-dist-fresh pins\n\t// the two copies content-identical so a stale bundled snapshot fails the\n\t// gate instead of passing unnoticed.\n\tconst devPluginsRoot = join(packageRoot, \"..\", \"..\", \"plugins\");\n\ttoolRoots.push(join(devPluginsRoot, \"coding-tools\"));\n\tfor (const name of BUNDLED_DEFAULT_POLICY_PACKAGES) policyRoots.push(join(devPluginsRoot, name));\n\t// provider-failover(D-082 批 3b):config 门控可选能力,随策略面根分发\n\t// (不受 noTools 门控,与内嵌装配同语义)。\n\tpolicyRoots.push(join(devPluginsRoot, \"provider-failover\"));\n\tconst bundledRoot = join(packageRoot, \"bundled-plugins\");\n\ttoolRoots.push(join(bundledRoot, \"coding-tools\"));\n\tfor (const name of BUNDLED_DEFAULT_POLICY_PACKAGES) policyRoots.push(join(bundledRoot, name));\n\tpolicyRoots.push(join(bundledRoot, \"provider-failover\"));\n\treturn { toolRoots, policyRoots };\n}\n\n/**\n * memory.mode 解析(2.4d6 S1,D-075 S4 第四批宿主收口后 sdk 内联): 显式值 →\n * env `AGENT_FORGE_MEMORY_MODE` → settings.json `memory.mode`(settingsMode 携\n * 带)→ 旧别名 `AGENT_FORGE_MEMORY_VECTOR`(兼容期)→ light(2026-10-05 用户裁\n * 决翻转默认 off→light,对齐主流编程助手开箱即用方向)。与包内\n * `resolveMemoryMode`(plugin-sdk/插件包面)语义逐点一致;宿主不依赖插件包源,\n * 非法值 fail-closed 回 off 并携带原值供一次性诊断。诊断文案由 builtin 时代\n * 逐字迁移(capabilities-builtin.test.ts / memory-mode-gating.test.ts pin)。\n */\ninterface SdkMemoryModeResolution {\n\treadonly mode: MemoryModeV1;\n\treadonly invalidEnvValue?: string;\n\treadonly invalidSettingsValue?: string;\n}\n\nconst isMemoryModeV1 = (value: string): value is MemoryModeV1 =>\n\tvalue === \"off\" || value === \"light\" || value === \"full\";\n\nfunction resolveSdkMemoryMode(\n\texplicitMode: string | undefined,\n\tenv: Readonly<Record<string, string | undefined>>,\n\tsettingsMode?: string,\n): SdkMemoryModeResolution {\n\tif (explicitMode !== undefined) {\n\t\tif (isMemoryModeV1(explicitMode)) return { mode: explicitMode };\n\t\treturn { mode: \"off\", invalidEnvValue: explicitMode };\n\t}\n\tconst configured = env.AGENT_FORGE_MEMORY_MODE?.trim().toLowerCase();\n\tif (configured !== undefined && configured !== \"\") {\n\t\tif (isMemoryModeV1(configured)) return { mode: configured };\n\t\treturn { mode: \"off\", invalidEnvValue: configured };\n\t}\n\tconst fromSettings = settingsMode?.trim().toLowerCase();\n\tif (fromSettings !== undefined && fromSettings !== \"\") {\n\t\tif (isMemoryModeV1(fromSettings)) return { mode: fromSettings };\n\t\treturn { mode: \"off\", invalidSettingsValue: fromSettings };\n\t}\n\tconst legacy = env.AGENT_FORGE_MEMORY_VECTOR?.trim().toLowerCase();\n\tif (legacy !== undefined && legacy !== \"\") {\n\t\tif (isMemoryModeV1(legacy)) return { mode: legacy };\n\t\treturn { mode: \"off\", invalidEnvValue: legacy };\n\t}\n\treturn { mode: \"light\" };\n}\n\nexport interface CreateAgentSessionOptions {\n\t/** Working directory for project-local discovery. Default: process.cwd() */\n\tcwd?: string;\n\t/** Global config directory. Default: ~/.agent-forge/agent */\n\tagentDir?: string;\n\t/**\n\t * Explicit suite/profile migration on resume (CRM seat finding F1/F2):\n\t * adopt the currently resolved suite + profile identity even when the\n\t * session's recorded binding no longer matches (e.g. a plugin was\n\t * installed after the conversation started), rewrite the binding entry,\n\t * and continue. Without it the drift guard keeps rejecting the resume.\n\t */\n\tallowSuiteRebind?: boolean;\n\n\t/** Canonical model/auth runtime. Defaults to a runtime using agentDir/auth.json and models.json. */\n\tmodelRuntime?: ModelRuntime;\n\t/**\n\t * Credential storage used by the default model runtime (D-067 phase 1):\n\t * forwarded to `ModelRuntime.create` when `modelRuntime` is omitted.\n\t * Ignored when an explicit `modelRuntime` is supplied. Defaults to the\n\t * file at `<agentDir>/auth.json`.\n\t */\n\tcredentials?: CredentialStore;\n\t/** Explicit model stream function for deterministic hosts and mock providers. */\n\tstreamFn?: StreamFn;\n\n\t/** Model to use. Default: from settings, else first available */\n\tmodel?: Model<Api>;\n\t/** Thinking level. Default: from settings, else 'medium' (clamped to model capabilities) */\n\tthinkingLevel?: ThinkingLevel;\n\t/** Models available for cycling (Ctrl+P in interactive mode) */\n\tscopedModels?: Array<{ model: Model<Api>; thinkingLevel?: ThinkingLevel }>;\n\n\t/**\n\t * Optional default tool suppression mode when no explicit allowlist is provided.\n\t *\n\t * - \"all\": start with no tools enabled\n\t * - \"builtin\": disable the default built-in tools (read, bash, edit, write)\n\t * but keep extension/custom tools enabled\n\t */\n\tnoTools?: \"all\" | \"builtin\";\n\t/**\n\t * Optional allowlist of tool names.\n\t *\n\t * When omitted (and `noTools` is not set) in the default full-control mode,\n\t * the active suite's declared `tools` are the initial selection (设计 §5);\n\t * readonly mode starts from the read-only base face, where the\n\t * `defaultTools` setting still applies when configured. When provided, only\n\t * the listed tool names are enabled.\n\t */\n\ttools?: string[];\n\t/** Optional denylist of tool names to disable. Applies after `tools` when both are provided. */\n\texcludeTools?: string[];\n\t/**\n\t * Plugin ids whose tools register normally but stay out of the default\n\t * active (prompt-visible) set; the built-in tool_search tool discovers and\n\t * activates them on demand. createAgentSessionFromServices forwards the\n\t * MCP pool's `deferredTools: true` server ids here. Explicit activation\n\t * (allowlist or setActiveTools) overrides the deferral.\n\t */\n\tdeferredToolPluginIds?: readonly string[];\n\t/** Custom tools to register (in addition to built-in tools). */\n\tcustomTools?: ToolDefinition[];\n\n\t/** Resource loader. When omitted, DefaultResourceLoader is used. */\n\tresourceLoader?: ResourceLoader;\n\n\t/** Session manager. Default: SessionManager.create(cwd) */\n\tsessionManager?: SessionManager;\n\n\t/** Settings manager. Default: SettingsManager.create(cwd, agentDir) */\n\tsettingsManager?: SettingsManager;\n\t/** Session start metadata dispatched to the capability lifecycle on session start. */\n\tsessionStartEvent?: SessionStartMetadata;\n\t/** Core capability mode. Defaults to \"full-control\". */\n\tcapabilityMode?: \"readonly\" | \"full-control\";\n\t/**\n\t * Discover plugin manifests recursively below `<agentDir>/plugins` and\n\t * `<cwd>/.agent-forge/plugins`. Defaults to true.\n\t */\n\tdiscoverCapabilityPlugins?: boolean;\n\t/**\n\t * Additional capability plugin manifest paths. They load after discovered\n\t * manifests; duplicate plugin IDs are an explicit startup error. Explicit\n\t * paths are caller intent: they bypass the suite's `associations.plugins`\n\t * filtering (方案系统 M3) and load regardless of the active suite.\n\t */\n\tcapabilityPluginPaths?: string[];\n\t/**\n\t * Installed capability plugins from the host's active-install store\n\t * (D-075 S2 installed-code-loading): each entry pairs a verified active\n\t * plugin id with its installation directory's plugin.json path. Only\n\t * entries whose plugin id is a member of the resolved plugin profile\n\t * (selected and not disabled) enter the candidate pool, as explicit\n\t * candidates like `capabilityPluginPaths`; non-members stay unloaded with\n\t * one suite diagnostic.\n\t */\n\tinstalledCapabilityPlugins?: readonly InstalledCapabilityPluginV1[];\n\t/**\n\t * Per-plugin manifest config overrides keyed by plugin id (D-082 批 1):\n\t * when the assembler loads a manifest whose id has an entry here, the value\n\t * merges into that plugin's `configOverride` — host-injected assembly facts\n\t * first, these values win per top-level key, and the plugin-side agent-dir\n\t * config file still merges above everything inside the plugin entry.\n\t */\n\tcapabilityPluginConfigs?: Record<string, PluginConfig>;\n\t/** Optional host-owned AgentDefinition/AgentInstance composition facade. */\n\tagentComposition?: AgentCompositionAPI;\n\t/** Optional host adapter for cancellable interaction tasks (interaction capability). */\n\tinteractionHost?: InteractionHostV1;\n\t/**\n\t * Suite (方案) id for workspace and context assembly. When omitted, resolved\n\t * via AGENT_FORGE_SUITE, then project settings `suite`, then global settings\n\t * `suite`, then the builtin default \"coding\".\n\t */\n\tsuite?: string;\n\t/** Optional context strategy supplied by a capability plugin. */\n\tcontextStrategyName?: string;\n\t/** Optional retry policy supplied by a capability plugin. */\n\tretryPolicyName?: string;\n\t/** Optional automatic compaction policy supplied by a capability plugin. */\n\tcompactionPolicyName?: string;\n\t/** Optional provider overflow policy supplied by a capability plugin. */\n\toverflowPolicyName?: string;\n\tbranchSummaryPolicyName?: string;\n\t/** Optional post-run continuation strategy supplied by a capability plugin. */\n\trunLoopStrategyName?: string;\n\t/**\n\t * 关闭本会话的委派/回读面(agents 能力整体缺席):`subagent_run` 等工具不注册,\n\t * reader/lister 也不注入。默认开启;委派承载由 `agentTaskAdapter`(宿主自带)或\n\t * `subagentPoolFromSelfInvocation`(CLI 自动池化)决定,二者都不在时委派面不注册。\n\t */\n\tenableAgentTasks?: boolean;\n\t/**\n\t * Host-injected adapter(承载退役后唯一的手工承载入口):池化 runner adapter 或\n\t * 宿主自定义实现。装配域自身不再提供默认子任务 creator(shared 递归装配已随\n\t * 承载退役删除);嵌套委派由 runner 叶子的自动池化承载,递归边界在 delegate\n\t * 的深度/总量硬限。`enableAgentTasks` 为 false 时忽略。\n\t */\n\tagentTaskAdapter?: AgentTaskAdapter;\n\t/**\n\t * 承载退役切片 1(生产 CLI 默认 pooled):宿主声明\"本进程的自身入口可信\"。\n\t * 仅真实 CLI 装配传 true——delegate 在未显式配置池且 self-invocation 可解析时\n\t * 自动池化。SDK 嵌入方与测试不传,行为不变。\n\t */\n\tsubagentPoolFromSelfInvocation?: boolean;\n\t/**\n\t * Subagent communication wiring (D-060 S4): host-bound mailbox closures for the\n\t * subagent-delegate capability. The parent assembly builds its own drain wiring\n\t * internally; child assemblies receive the post/drainInbox wiring with the child\n\t * identity bound by the parent scope. Absent = the communication tools never\n\t * register (the config flags are necessary but the wiring is the channel).\n\t */\n\tsubagentCommunicationWiring?: SubagentCommunicationWiringV1;\n\t/**\n\t * Durable replay channel for agent task terminal outcomes (agent-result-replay-v1).\n\t * Requires the agents capability (only pass it when `enableAgentTasks` is not\n\t * false); the runtime guard pair rejects a replay option without the feature.\n\t * Serve hosts inject `{ store, writerId }` here; child sessions never\n\t * inherit it.\n\t */\n\tagentTaskResults?: {\n\t\treadonly store: DurableServiceV1;\n\t\treadonly writerId: string;\n\t};\n\t/**\n\t * Wire the suite's capability surface (方案系统 M3): the `capabilities`\n\t * whitelist loads the embedded builtin plugins, the external plugin pool\n\t * is filtered by `associations.plugins`, and the legacy plugin skill face\n\t * is filtered by `associations.skills`. Default: on when this call builds\n\t * its own resource loader, off when the caller brings one (the M1a/M1b\n\t * assembly boundary); callers with their own loader can opt in explicitly.\n\t */\n\tsuiteCapabilityWiring?: boolean;\n\t/** Optional domain plugin profile selected for the active suite. */\n\tpluginProfileId?: BuiltinPluginProfileIdV1;\n\t/** Optional subset of plugins from the selected builtin Profile. */\n\tselectedPluginIds?: readonly string[];\n\t/** Optional plugin IDs disabled within the selected builtin Profile. */\n\tdisabledPluginIds?: readonly string[];\n\tpluginHost?: HostFactsV1;\n\tverifiedPlugins?: readonly VerifiedToolPluginV1[];\n\t/** Explicit host-owned active installed manifests; never discovered implicitly. */\n\tmanifestOverrides?: BuiltinPluginManifestOverridesV1;\n\tpluginProfile?: BuiltinPluginProfileResolutionV1;\n\t/**\n\t * Session trace collection (设计 §4.4/§6). When not `false`, the assembler\n\t * registers the first-party `agent-forge.observability` plugin so every\n\t * session carries a `.trace.jsonl` file next to its session file. Default:\n\t * `true`; `--no-trace` maps to `false` on the CLI.\n\t */\n\ttraceEnabled?: boolean;\n\t/**\n\t * Trace-sink budget overrides (设计 §6 控制面):forwarded to the first-party\n\t * observability plugin's snapshot serializer. Defaults when omitted:\n\t * 16 000 chars per string, 384 KiB per serialized snapshot\n\t * (TraceSinkOptionsV1). Consumed by the trace sink registered through\n\t * `traceEnabled`; only meaningful while tracing is on.\n\t */\n\ttraceOptions?: TraceSinkOptionsV1;\n\t/**\n\t * Host-process logger for runtime diagnostics (设计 §5). Absent = the SDK\n\t * embedder opted out of process logging; this is an explicit contract, not\n\t * a default — every instrumentation point behind it is a no-op then.\n\t */\n\thostLogger?: HostLogger;\n\t/**\n\t * 记忆全局档位与底层组件注入(2.4d6 S1 / 扩展位盘点 A1/A2,D-075 S4 第四批\n\t * 拆包后形态):显式定档最优先,缺省走解析链(env `AGENT_FORGE_MEMORY_MODE`\n\t * → settings.json `memory.mode` → 旧别名 → off);off 时 memory 插件包不进\n\t * 装配成员资格(零工具零命令零事件),启动诊断带一行声明。`storage`(store/\n\t * ledger 工厂与向量组件公共契约)经公共 HostCapabilities\n\t * (`api.host.memoryStorage`) 注入安装店的 memory 插件包;缺省成员 = 包内默认\n\t * 实现。测试专用向量注入面经 `storage.vectorComponents` 携带(原顶层\n\t * `vectorComponents` 字段随内嵌装配退役)。\n\t */\n\tmemoryCapability?: {\n\t\treadonly mode?: MemoryModeV1;\n\t\t/**\n\t\t * 记忆底层组件注入(扩展位盘点 A1/A2):store/ledger 工厂与向量组件公共\n\t\t * 契约,经 HostCapabilities.memoryStorage 原样透传给 memory 插件包;缺省\n\t\t * 任一成员 = 包内默认实现,默认行为零变化。\n\t\t */\n\t\treadonly storage?: MemoryStorageComponentsV1;\n\t};\n}\n\n/**\n * 子代理 headless 交互宿主(D-044 §5.5):child 会话无宿主 UI,interaction 请求\n * 落回冻结 InteractionOutcomeV1 语义——prompt 返回 \"unavailable\"(宿主无 UI),\n * signal 已中止返回 \"cancelled\";notify 为 fire-and-forget 空操作(语义 delivered)。\n */\nexport const HEADLESS_INTERACTION_HOST: InteractionHostV1 = {\n\tnotify: () => {},\n\tprompt: async (_request, context) => {\n\t\tif (context.signal.aborted) return { status: \"cancelled\" };\n\t\treturn { status: \"unavailable\" };\n\t},\n};\n\n/** Result from createAgentSession */\nexport interface CreateAgentSessionResult {\n\t/** The created session */\n\tsession: AgentSession;\n\t/** Warning if session was restored with a different model than saved */\n\tmodelFallbackMessage?: string;\n\t/**\n\t * Capability plugins rejected during startup without blocking the session\n\t * (D-028). Empty when every discovered/explicit plugin loaded. Combination-level\n\t * conflicts (duplicate capability identity, dependency cycles) still fail\n\t * session creation outright.\n\t */\n\tpluginRejections: readonly PluginRejection[];\n\t/**\n\t * Suite assembly diagnostics (suite.json corruption fallbacks, blocked\n\t * system agents.md layer hints, association counts). Empty when suite\n\t * assembly found nothing to report.\n\t */\n\tsuiteDiagnostics: readonly string[];\n\t/** Optional domain plugin profile resolution for UI and diagnostics. */\n\tpluginProfile?: BuiltinPluginProfileResolutionV1;\n\t/**\n\t * The immutable per-session aggregate view over the resolved suite profile\n\t * (D-047 S4a): identity, lock verification, plugin profile summary, and\n\t * workspace path projection — a deep-frozen view of the existing\n\t * authoritative sources, not a new generation mechanism. AgentSession stays\n\t * suite-unaware: the aggregate rides this creation result only, never\n\t * AgentSessionConfig.\n\t */\n\tresolvedAgentProfile?: ResolvedAgentProfileV1;\n}\n\n// Re-exports\n\nexport * from \"./agent-session-runtime.ts\";\nexport type { PluginRejection } from \"./extensions/index.ts\";\nexport type { PromptTemplate } from \"./prompt-templates.ts\";\nexport type { Skill } from \"./skills.ts\";\nexport type { SlashCommandInfo, SlashCommandSource } from \"./slash-commands.ts\";\nexport type { Tool } from \"./tools/index.ts\";\nexport { withFileMutationQueue } from \"./tools/index.ts\";\nexport type { ToolDefinition, ToolInfo, ToolRenderContext, ToolRenderResultOptions } from \"./tools/tool-definition.ts\";\n\n// Helper Functions\n\nfunction getDefaultAgentDir(): string {\n\treturn getAgentDir();\n}\n\nasync function readCapabilityPluginManifestForOrdering(manifestPath: string): Promise<PluginManifest> {\n\tlet raw: unknown;\n\ttry {\n\t\traw = JSON.parse(await readFile(manifestPath, \"utf8\"));\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\tt(\"Failed to read capability plugin manifest {path}: {reason}\", {\n\t\t\t\tpath: manifestPath,\n\t\t\t\treason: error instanceof Error ? error.message : String(error),\n\t\t\t}),\n\t\t);\n\t}\n\treturn parseCapabilityPluginManifest(raw, manifestPath);\n}\n\n/**\n * Create an AgentSession with the specified options.\n *\n * @example\n * ```typescript\n * // Minimal - uses defaults\n * const { session } = await createAgentSession();\n *\n * // With explicit model\n * import { getModel } from '@agent-forge/ai';\n * const { session } = await createAgentSession({\n * model: getModel('anthropic', 'claude-opus-4-5'),\n * thinkingLevel: 'high',\n * });\n *\n * // Continue previous session\n * const { session, modelFallbackMessage } = await createAgentSession({\n * continueSession: true,\n * });\n *\n * // Full control\n * const loader = new DefaultResourceLoader({\n * cwd: process.cwd(),\n * agentDir: getAgentDir(),\n * settingsManager: SettingsManager.create(),\n * });\n * await loader.reload();\n * const { session } = await createAgentSession({\n * model: myModel,\n * tools: [\"read\", \"bash\"],\n * resourceLoader: loader,\n * sessionManager: SessionManager.inMemory(),\n * });\n * ```\n */\nexport async function createAgentSession(options: CreateAgentSessionOptions = {}): Promise<CreateAgentSessionResult> {\n\tconst cwd = resolvePath(options.cwd ?? options.sessionManager?.getCwd() ?? process.cwd());\n\tconst agentDir = options.agentDir ? resolvePath(options.agentDir) : getDefaultAgentDir();\n\tlet resourceLoader = options.resourceLoader;\n\n\tconst authPath = options.agentDir ? join(agentDir, \"auth.json\") : undefined;\n\tconst modelsPath = options.agentDir ? join(agentDir, \"models.json\") : undefined;\n\tconst modelRuntime =\n\t\toptions.modelRuntime ?? (await ModelRuntime.create({ authPath, modelsPath, credentials: options.credentials }));\n\n\tconst settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n\n\t// Suite assembly (方案系统 M1a/M2): resolve the active suite and build the\n\t// shared assembly (workspace + loader overrides + diagnostics channel).\n\t// The inherit switch also gates the global agentDir SYSTEM.md/\n\t// APPEND_SYSTEM.md prompt channel (设计 §8: it governs the whole system\n\t// layer). Unknown ids fail here with a structured error listing the\n\t// available suites. The loader overrides below are applied only when this\n\t// call builds its own DefaultResourceLoader; callers that bring their own\n\t// resourceLoader keep the M1a bypass boundary (unchanged).\n\tconst suiteId = resolveSuiteId({\n\t\texplicit: options.suite,\n\t\tenvSuite: process.env[SUITE_ENV_VAR],\n\t\tsettings: settingsManager,\n\t\tagentDir,\n\t});\n\tconst suiteAssembly = createSuiteAssembly({\n\t\tcwd,\n\t\tagentDir,\n\t\tsuiteId,\n\t\tpluginProfileId: options.pluginProfileId,\n\t\tselectedPluginIds: options.selectedPluginIds,\n\t\tdisabledPluginIds: options.disabledPluginIds,\n\t\tpluginHost: options.pluginHost,\n\t\tverifiedPlugins: options.verifiedPlugins,\n\t\tmanifestOverrides: options.manifestOverrides,\n\t\tpluginProfile: options.pluginProfile,\n\t});\n\tconst suiteWorkspace = suiteAssembly.workspace;\n\n\t// ResolvedAgentProfile (D-047 S4a): one deep-frozen aggregate view over the\n\t// resolved suite per session, built once at the existing single resolution\n\t// point right after suite assembly. Pure projection of the authoritative\n\t// sources above (identity, lock verification, plugin profile, workspace\n\t// paths) — no new generation mechanism; AgentSession stays suite-unaware.\n\tconst resolvedAgentProfile = buildResolvedAgentProfileV1({\n\t\tsuiteId,\n\t\tworkspace: suiteWorkspace,\n\t\t...(suiteAssembly.pluginProfile === undefined ? {} : { pluginProfile: suiteAssembly.pluginProfile }),\n\t});\n\n\t// Capability wiring (方案系统 M3): resolve the suite's `capabilities`\n\t// short ids onto the builtin family mapping (every short id assembles from\n\t// its independent plugin package; unknown ids surface as dangling\n\t// diagnostics, never as errors — 决策记录 §8) and prepare the external\n\t// pool / legacy skill association filters. Follows the M1a/M1b assembly\n\t// boundary: wiring is on when this call builds its own loader and off for\n\t// callers that bring one unless they opt in explicitly.\n\tconst capabilityWiring = options.suiteCapabilityWiring ?? !options.resourceLoader;\n\tconst capabilityDiagnostics: string[] = [];\n\t// Suite preference diagnostics (统一修复轮 B): unresolvable suite.model /\n\t// suite.thinking declarations surface here instead of failing startup.\n\tconst suitePreferenceDiagnostics: string[] = [];\n\tlet capabilitySkillsFilter: ((skills: Skill[]) => Skill[]) | undefined;\n\t// 子代理通信面(D-060 S4/S5):每个装配域自持**一个**信箱(本会话的子代理们向它\n\t// post escalation/兄弟消息,本会话的 delegate drain)。嵌套委派时,子装配域的信箱\n\t// 由父侧 creator 构造并经 `subagentMailbox` 注入,保证 post 目标与 drain 来源同一\n\t// 实例;post-up(向自己的父)接线经 `subagentCommunicationWiring` 注入,两者合并。\n\tlet communicationMailbox: SubagentMailboxV1 | undefined;\n\tconst selfMailbox = (): SubagentMailboxV1 => {\n\t\tcommunicationMailbox ??= createSubagentMailbox({\n\t\t\tagentDir,\n\t\t\townerParentSessionId: () => agentSessionRef.current?.sessionId,\n\t\t});\n\t\treturn communicationMailbox;\n\t};\n\tconst communicationWiring: SubagentCommunicationWiringV1 | undefined =\n\t\toptions.enableAgentTasks === false && options.subagentCommunicationWiring === undefined\n\t\t\t? undefined\n\t\t\t: {\n\t\t\t\t\tdrainEscalations: (sessionId: string) => selfMailbox().drainEscalations(sessionId),\n\t\t\t\t\t// 父侧只读的兄弟流量摘录(D-060 裁决 14 父可见性):随验收信封对父可见。\n\t\t\t\t\treadSiblingTraffic: (sessionId: string, limit: number) =>\n\t\t\t\t\t\tselfMailbox().readSiblingTraffic(sessionId, limit),\n\t\t\t\t\t...(options.subagentCommunicationWiring ?? {}),\n\t\t\t\t};\n\t// 记忆档位解析(2.4d6 S1;D-075 S4 第四批):SDK 显式选项最优先,settings.json\n\t// 档位作为 env 之下的持久来源进入解析链(显式 > env > settings > 旧别名 env >\n\t// light,2026-10-05 翻转默认);两者皆缺省时同样走 env/别名/light 解析\n\t// (off = memory 插件包不装配)。门控诊断与成员资格判定在下方 capabilityWiring 块产出。\n\tconst settingsMemoryMode = settingsManager.getMemoryModeSetting();\n\tconst memoryModeOption = options.memoryCapability?.mode;\n\tconst memoryModeResolution = resolveSdkMemoryMode(memoryModeOption, process.env, settingsMemoryMode);\n\tif (capabilityWiring) {\n\t\t// 非 builtin 的 capabilities 条目按安装店插件包 id 直通(成员资格与\n\t\t// dangling 诊断都在下方装配块统一处理),这里不再产出旧的 unknown 短 id\n\t\t// 诊断——同一批条目报两条且会误报已安装插件。\n\t\t// 记忆全局门控诊断(2.4d6 S1, D-075 S4 第四批自 builtin 通道迁入):套件确实\n\t\t// 声明了 builtin.memory 时才输出(抑制发生了才声明;未声明的场合由白名单语\n\t\t// 义覆盖,不加噪音)。文案由 builtin 时代逐字迁移(memory-mode-gating 等 pin)。\n\t\tif (suiteWorkspace.suite.capabilities.includes(\"builtin.memory\")) {\n\t\t\tif (memoryModeResolution.invalidEnvValue !== undefined) {\n\t\t\t\tcapabilityDiagnostics.push(\n\t\t\t\t\t`invalid AGENT_FORGE_MEMORY_MODE value \"${memoryModeResolution.invalidEnvValue}\"; memory stays off (fail-closed)`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (memoryModeResolution.invalidSettingsValue !== undefined) {\n\t\t\t\tcapabilityDiagnostics.push(\n\t\t\t\t\t`invalid memory.mode setting \"${memoryModeResolution.invalidSettingsValue}\"; memory stays off (fail-closed)`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (memoryModeResolution.mode === \"off\") {\n\t\t\t\tcapabilityDiagnostics.push(\n\t\t\t\t\t\"memory disabled (mode=off) — set memory.mode (light|full) in settings.json to enable\",\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\t// Legacy plugin skill face: the bootstrap-skills contribution face is\n\t\t// already filtered loader-side (M1b); only runtime.listSkills() entries\n\t\t// pass through this hook. Association dangling is reported by the\n\t\t// loader-side skills filter; this hook only narrows the plugin face.\n\t\t// The suite-local skill layer (统一修复轮 B) passes by path there.\n\t\tconst suiteDefinition = suiteWorkspace.suite;\n\t\tconst suiteLocalSkillsDir = suiteAssembly.localSkillsDir;\n\t\tcapabilitySkillsFilter = (skills: Skill[]) =>\n\t\t\tfilterSuiteSkills(suiteDefinition, skills, { localSkillsDir: suiteLocalSkillsDir }).kept;\n\t}\n\n\tconst sessionManager = options.sessionManager ?? SessionManager.create(cwd, getDefaultSessionDir(cwd, agentDir));\n\n\t// 打点通道(设计 §5.2):streamFn 闭包的 options 参数会遮蔽装配 options,统一\n\t// 捕获为局部常量;未注入时全部打点为 no-op。\n\tconst hostLogger = options.hostLogger;\n\t// 轨迹快照预算(设计 §6 控制面,第 2 期外露):随 trace 服务注入安装店\n\t// observability 插件;缺省 = 插件内默认(16000 字符/串、384KiB/快照)。\n\tconst traceOptions = options.traceOptions;\n\n\t// 轨迹收集默认装配(设计 §4.4/§6,D-065;S4 拆包改造,D-075 第二批):\n\t// `traceEnabled` 缺省开启时,安装店 `agent-forge.plugin.observability` 包\n\t// 随装配链加载(成员资格并入 installed 插件集合,可经 disabledPluginIds\n\t// 显式禁用;第三方可经同一公共 lifecycle 订阅面替换)。宿主适配器闭包只\n\t// 依赖装配域内既有事实:会话文件路径(惰性解析,经既有 getSessionFile()\n\t// 读面加 §4.1 配对纯函数)、进程日志(options.hostLogger,未注入为 no-op)、\n\t// payload 捕获(onPayload 读取;无隐藏全局)。适配器经新 `api.trace` 服务\n\t// 面注入插件;插件 entry 经适配器可选 `registerFacade` 通道把门面写回\n\t// 下方三个装配域 ref(payload 捕获 / plugin.log 镜像 / /metrics 数据源),\n\t// dispose 时置空——与内嵌工厂时代的 ref 语义逐点一致。\n\tconst observabilityCapture: { current?: ObservabilityPluginFacadeV1[\"captureProviderPayload\"] } = {};\n\t// 插件日志镜像共享 ref(会话轨迹 plugin.log,设计 §7.2):插件门面\n\t// mirrorPluginLog 注册时写入,dispose 时置空;AgentSession 的 runtime\n\t// 日志 sink 经 AgentSessionConfig.logRecordMirrorRef 读它。\n\tconst observabilityLogMirror: { current?: (record: LoggerRecord) => void } = {};\n\t// /metrics 命令的数据源(observability 门面直通):插件门面 getMetrics\n\t// 注册时写入,dispose 时置空;宿主(TUI/RPC)在装配完成后读取并接进命令\n\t// options。\n\tconst observabilityGetMetrics: { current?: ObservabilityPluginFacadeV1[\"getMetrics\"] } = {};\n\tlet traceService: TraceServiceV1 | undefined;\n\tif (options.traceEnabled !== false) {\n\t\tconst adapter: ObservabilityHostAdapterV1 = {\n\t\t\tgetTraceFilePath: () => {\n\t\t\t\tconst sessionFilePath = sessionManager.getSessionFile();\n\t\t\t\treturn sessionFilePath === undefined ? null : getTraceFilePathForSession(sessionFilePath);\n\t\t\t},\n\t\t\tcaptureProviderPayload: (payload, model) => {\n\t\t\t\tobservabilityCapture.current?.(payload, model);\n\t\t\t},\n\t\t\tonSinkFailure: (error) => {\n\t\t\t\thostLogger?.error(\"observability\", \"trace sink failure\", { cause: error });\n\t\t\t},\n\t\t\tgetTurnCorrelationId: () => agentSessionRef.current?.getTurnCorrelationId(),\n\t\t\tgetParentAgentSessionId: () => sessionManager.getHeader()?.parentAgentSession,\n\t\t\tgetParentTraceId: () => sessionManager.getHeader()?.parentTraceId,\n\t\t\tregisterFacade: (facade) => {\n\t\t\t\tobservabilityCapture.current = facade?.captureProviderPayload;\n\t\t\t\tobservabilityLogMirror.current = facade?.mirrorPluginLog;\n\t\t\t\tobservabilityGetMetrics.current = facade?.getMetrics;\n\t\t\t},\n\t\t};\n\t\ttraceService = { adapter, ...(traceOptions === undefined ? {} : { options: traceOptions }) };\n\t}\n\n\tif (!resourceLoader) {\n\t\t// Suite association filtering (方案系统 M1b, 设计 §3/§4): the default\n\t\t// loader's skills are filtered down to the suite's\n\t\t// associations here, at the assembler layer; project-scope entries\n\t\t// (cwd/.agent-forge) always pass. Dangling associations surface through\n\t\t// suiteDiagnostics, never as errors.\n\t\tresourceLoader = new DefaultResourceLoader({\n\t\t\tcwd,\n\t\t\tagentDir,\n\t\t\tsettingsManager,\n\t\t\t...suiteAssembly.loaderOverrides,\n\t\t\t// Suite-local skill layer (统一修复轮 B): <suiteDir>/skills rides the\n\t\t\t// loader's skill paths when the suite is active. The filterSuiteSkills\n\t\t\t// suite-local exemption keeps these entries; user-level and other\n\t\t\t// unassociated layers stay filtered. Undefined (absent directory)\n\t\t\t// injects nothing, so empty and missing directories are both silent.\n\t\t\t...(suiteAssembly.localSkillsDir === undefined\n\t\t\t\t? {}\n\t\t\t\t: { additionalSkillPaths: [suiteAssembly.localSkillsDir] }),\n\t\t});\n\t\tawait resourceLoader.reload();\n\t\ttime(\"resourceLoader.reload\");\n\t}\n\n\t// Check if session has existing data to restore\n\tconst existingSession = sessionManager.buildSessionContext();\n\tconst hasExistingSession = existingSession.messages.length > 0;\n\tconst branchEntries = sessionManager.getBranch();\n\tconst sessionSuiteBinding = readSessionSuiteBinding(branchEntries);\n\t// 绑定护栏保护的是有对话上下文的会话:会话创建先于插件装载,装载失败(profile\n\t// drift 等)会留下只有初始化 entry 与绑定的残留——这些 message entries 会让\n\t// hasExistingSession 为真,若按它门控,用户用同一 session id 重试会永远撞墙\n\t// (dogfood 2026-09-25 实测)。真实用户输入(user entry)才算对话开始。\n\tconst hasConversation = branchEntries.some(\n\t\t(entry) => entry.type === \"message\" && (entry as { message?: { role?: string } }).message?.role === \"user\",\n\t);\n\tif (hasConversation && sessionSuiteBinding !== undefined && !options.allowSuiteRebind) {\n\t\tif (sessionSuiteBinding.suiteId !== suiteId) {\n\t\t\tthrow new SuiteRebindError(\n\t\t\t\tt(\n\t\t\t\t\t'Session is bound to suite \"{boundSuiteId}\" and cannot resume with \"{suiteId}\"; rerun with --rebind-suite to adopt the new suite, or create a new session',\n\t\t\t\t\t{ boundSuiteId: sessionSuiteBinding.suiteId, suiteId },\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\tif (\n\t\t\tsessionSuiteBinding.profileIdentity !== undefined &&\n\t\t\t!profileIdentitiesCompatible(sessionSuiteBinding.profileIdentity, suiteWorkspace.identity)\n\t\t) {\n\t\t\tthrow new SuiteRebindError(\n\t\t\t\tt(\n\t\t\t\t\t\"Session Profile identity drift detected (the active plugin set changed since the conversation started); rerun with --rebind-suite to adopt the new plugin set, or create a new session\",\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n\tconst hasThinkingEntry = sessionManager.getBranch().some((entry) => entry.type === \"thinking_level_change\");\n\n\tlet model = options.model;\n\tlet modelFallbackMessage: string | undefined;\n\n\t// If session has data, try to restore model from it\n\tif (!model && hasExistingSession && existingSession.model) {\n\t\tconst restoredModel = modelRuntime.getModel(existingSession.model.provider, existingSession.model.modelId);\n\t\tif (restoredModel && modelRuntime.hasConfiguredAuth(restoredModel.provider)) {\n\t\t\tmodel = restoredModel;\n\t\t}\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = `Could not restore model ${existingSession.model.provider}/${existingSession.model.modelId}`;\n\t\t}\n\t}\n\n\t// Suite model preference (统一修复轮 B): sits below the CLI/explicit option\n\t// and the restored session model, above the settings default that\n\t// findInitialModel resolves below. A suite model that matches no\n\t// authenticated model falls through to the next tier with a diagnostic —\n\t// never a failure (设计 §9: suite content never blocks startup). Factory\n\t// builtin suites declare null, so their resolution is unchanged.\n\tconst suiteModelPreference = suiteWorkspace.suite.model;\n\tif (!model && suiteModelPreference !== null) {\n\t\tconst suiteModel = findExactModelReferenceMatch(suiteModelPreference, [...modelRuntime.getModels()]);\n\t\tif (suiteModel && modelRuntime.hasConfiguredAuth(suiteModel.provider)) {\n\t\t\tmodel = suiteModel;\n\t\t} else {\n\t\t\tsuitePreferenceDiagnostics.push(\n\t\t\t\t`Suite \"${suiteId}\" model \"${suiteModelPreference}\" does not resolve to an authenticated model; using the normal model resolution instead.`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// If still no model, use findInitialModel (checks settings default, then provider defaults)\n\tif (!model) {\n\t\tconst result = await findInitialModel({\n\t\t\tscopedModels: [],\n\t\t\tisContinuing: hasExistingSession,\n\t\t\tdefaultProvider: settingsManager.getDefaultProvider(),\n\t\t\tdefaultModelId: settingsManager.getDefaultModel(),\n\t\t\tdefaultThinkingLevel: settingsManager.getDefaultThinkingLevel(),\n\t\t\tmodelThinkingLevels: settingsManager.getAllModelThinkingLevels(),\n\t\t\tmodelRuntime,\n\t\t});\n\t\tmodel = result.model;\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = formatNoModelsAvailableMessage();\n\t\t} else if (modelFallbackMessage) {\n\t\t\tmodelFallbackMessage += `. Using ${model.provider}/${model.id}`;\n\t\t}\n\t}\n\n\tlet thinkingLevel = options.thinkingLevel;\n\n\t// If session has data, restore thinking level from it\n\tif (thinkingLevel === undefined && hasExistingSession && hasThinkingEntry) {\n\t\tthinkingLevel = existingSession.thinkingLevel as ThinkingLevel;\n\t}\n\n\t// Suite thinking preference (统一修复轮 B): below the session's persisted\n\t// thinking entry, above the settings-derived tiers. An invalid value falls\n\t// through with a diagnostic; factory builtin suites declare null, so their\n\t// resolution is unchanged.\n\tconst suiteThinkingPreference = suiteWorkspace.suite.thinking;\n\tif (thinkingLevel === undefined && suiteThinkingPreference !== null) {\n\t\tif (isValidThinkingLevel(suiteThinkingPreference)) {\n\t\t\tthinkingLevel = suiteThinkingPreference;\n\t\t} else {\n\t\t\tsuitePreferenceDiagnostics.push(\n\t\t\t\t`Suite \"${suiteId}\" thinking \"${suiteThinkingPreference}\" is not a valid thinking level; using the normal thinking resolution instead.`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// If session has data without a persisted thinking entry, the settings\n\t// default applies (same tier as before the suite preference was inserted).\n\tif (thinkingLevel === undefined && hasExistingSession) {\n\t\tthinkingLevel = settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;\n\t}\n\n\t// Fall back to per-model override, then global default\n\tif (thinkingLevel === undefined && model) {\n\t\tconst perModel = settingsManager.getModelThinkingLevel(model.provider, model.id);\n\t\tif (perModel) {\n\t\t\tthinkingLevel = perModel;\n\t\t}\n\t}\n\tif (thinkingLevel === undefined) {\n\t\tthinkingLevel = settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;\n\t}\n\n\t// Clamp to model capabilities\n\tif (!model) {\n\t\tthinkingLevel = \"off\";\n\t} else {\n\t\tthinkingLevel = clampThinkingLevel(model, thinkingLevel) as ThinkingLevel;\n\t}\n\n\tconst defaultActiveToolNames: ToolName[] =\n\t\toptions.capabilityMode === \"readonly\" ? [\"read\", \"grep\", \"find\", \"ls\"] : [\"read\", \"bash\", \"edit\", \"write\"];\n\tconst configuredDefaultToolNames = settingsManager.getDefaultTools();\n\tconst allowedToolNames = options.tools ?? (options.noTools === \"all\" ? [] : undefined);\n\tconst excludedToolNames = options.excludeTools;\n\tconst excludedToolNameSet = excludedToolNames ? new Set(excludedToolNames) : undefined;\n\t// Suite tool surface (设计 §5/§6): the resolved suite's declared tools\n\t// override the default allowlist when the caller passed neither tools nor\n\t// noTools. Both builtin suites share the same unrestricted 8-tool\n\t// declaration (设计 §5: \"两方案同一全集、无任何限制\"), so whichever suite\n\t// is default activates it too — the historical DEFAULT_SUITE_ID exemption\n\t// that pinned assistant to the 4-tool base was removed in the 统一修复轮\n\t// (2026-09-08, per 方案设计 §5 and the user decision \"不需要限制这么死\").\n\t// capabilityMode stays a separate, orthogonal axis (设计 §5 权限段):\n\t// readonly narrows BOTH suites' faces a second time, so the suite\n\t// declaration never defeats the readonly base face.\n\tconst suiteToolOverride =\n\t\toptions.tools === undefined && options.noTools === undefined && options.capabilityMode !== \"readonly\"\n\t\t\t? [...suiteWorkspace.suite.tools]\n\t\t\t: undefined;\n\tconst initialActiveToolNames = (\n\t\tsuiteToolOverride ??\n\t\toptions.tools ??\n\t\t(options.noTools ? [] : (configuredDefaultToolNames ?? defaultActiveToolNames))\n\t).filter((name) => !excludedToolNameSet?.has(name));\n\n\tlet agent: Agent;\n\n\t// Create convertToLlm wrapper that filters images if blockImages is enabled (defense-in-depth)\n\tconst convertToLlmWithBlockImages = (messages: AgentMessage[]): Message[] => {\n\t\tconst converted = convertToLlm(messages);\n\t\t// Check setting dynamically so mid-session changes take effect\n\t\tif (!settingsManager.getBlockImages()) {\n\t\t\treturn converted;\n\t\t}\n\t\t// Filter out ImageContent from all messages, replacing with text placeholder\n\t\treturn converted.map((msg) => {\n\t\t\tif (msg.role === \"user\" || msg.role === \"toolResult\") {\n\t\t\t\tconst content = msg.content;\n\t\t\t\tif (Array.isArray(content)) {\n\t\t\t\t\tconst hasImages = content.some((c) => c.type === \"image\");\n\t\t\t\t\tif (hasImages) {\n\t\t\t\t\t\tconst filteredContent = content\n\t\t\t\t\t\t\t.map((c) =>\n\t\t\t\t\t\t\t\tc.type === \"image\" ? { type: \"text\" as const, text: \"Image reading is disabled.\" } : c,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.filter(\n\t\t\t\t\t\t\t\t(c, i, arr) =>\n\t\t\t\t\t\t\t\t\t// Dedupe consecutive \"Image reading is disabled.\" texts\n\t\t\t\t\t\t\t\t\t!(\n\t\t\t\t\t\t\t\t\t\tc.type === \"text\" &&\n\t\t\t\t\t\t\t\t\t\tc.text === \"Image reading is disabled.\" &&\n\t\t\t\t\t\t\t\t\t\ti > 0 &&\n\t\t\t\t\t\t\t\t\t\tarr[i - 1].type === \"text\" &&\n\t\t\t\t\t\t\t\t\t\t(arr[i - 1] as { type: \"text\"; text: string }).text === \"Image reading is disabled.\"\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\treturn { ...msg, content: filteredContent };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn msg;\n\t\t});\n\t};\n\n\tconst agentSessionRef: { current?: AgentSession } = {};\n\tconst customStreamFn = options.streamFn;\n\tagent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt: \"\",\n\t\t\tmodel,\n\t\t\tthinkingLevel,\n\t\t\ttools: [],\n\t\t},\n\t\tconvertToLlm: convertToLlmWithBlockImages,\n\t\tstreamFn: customStreamFn\n\t\t\t? (model, context, streamOptions) => customStreamFn(model, context, streamOptions)\n\t\t\t: async (model, context, options) => {\n\t\t\t\t\tconst providerRetrySettings = settingsManager.getProviderRetrySettings();\n\t\t\t\t\tconst httpIdleTimeoutMs = settingsManager.getHttpIdleTimeoutMs();\n\t\t\t\t\t// SDKs treat timeout=0 as 0ms (immediate timeout), not \"no timeout\".\n\t\t\t\t\t// Use max int32 to effectively disable the timeout.\n\t\t\t\t\tconst effectiveTimeoutMs = httpIdleTimeoutMs === 0 ? 2147483647 : httpIdleTimeoutMs;\n\t\t\t\t\tconst timeoutMs = options?.timeoutMs ?? providerRetrySettings.timeoutMs ?? effectiveTimeoutMs;\n\t\t\t\t\tconst websocketConnectTimeoutMs =\n\t\t\t\t\t\toptions?.websocketConnectTimeoutMs ?? settingsManager.getWebSocketConnectTimeoutMs();\n\t\t\t\t\t// 默认闭包:底层 streamSimple 调用(请求预算/超时按本次调用捕获;header\n\t\t\t\t\t// 变换闭包绑定请求模型参数,使换道重放后的备用模型也走各自变换)。\n\t\t\t\t\tconst baseStreamFn = (\n\t\t\t\t\t\trequestModel: Model<Api>,\n\t\t\t\t\t\trequestContext: Context,\n\t\t\t\t\t\trequestOptions?: SimpleStreamOptions,\n\t\t\t\t\t): AssistantMessageEventStream => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\treturn modelRuntime.streamSimple(requestModel, requestContext, {\n\t\t\t\t\t\t\t\t...requestOptions,\n\t\t\t\t\t\t\t\ttimeoutMs,\n\t\t\t\t\t\t\t\twebsocketConnectTimeoutMs,\n\t\t\t\t\t\t\t\tmaxRetries: requestOptions?.maxRetries ?? providerRetrySettings.maxRetries,\n\t\t\t\t\t\t\t\tmaxRetryDelayMs: requestOptions?.maxRetryDelayMs ?? providerRetrySettings.maxRetryDelayMs,\n\t\t\t\t\t\t\t\ttransformHeaders: async (requestHeaders) => {\n\t\t\t\t\t\t\t\t\tconst session = agentSessionRef.current;\n\t\t\t\t\t\t\t\t\t// v8 ignore next -- 流式请求仅在会话初始化后发生,session 恒已赋值\n\t\t\t\t\t\t\t\t\tif (!session)\n\t\t\t\t\t\t\t\t\t\tthrow new Error(t(\"Capability runtime is not initialized for provider request\"));\n\t\t\t\t\t\t\t\t\treturn session.getCapabilityRuntime().transformProviderHeaders({\n\t\t\t\t\t\t\t\t\t\tmodel: requestModel,\n\t\t\t\t\t\t\t\t\t\t...(requestOptions?.sessionId === undefined\n\t\t\t\t\t\t\t\t\t\t\t? {}\n\t\t\t\t\t\t\t\t\t\t\t: { sessionId: requestOptions.sessionId }),\n\t\t\t\t\t\t\t\t\t\theaders: requestHeaders,\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t// streamFn 错误路径打点(设计 §5.2):保留原始错误向上传播。\n\t\t\t\t\t\t\thostLogger?.error(\"sdk\", \"provider stream failed\", { cause: error });\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t\t// streamFn wrapper 链(provider-failover 家族注册面,设计 供应商能力槽位\n\t\t\t\t\t// 与主备切换 §4.8):getStreamFnWrappers 已按 (priority 升序, 注册序升序)\n\t\t\t\t\t// 稳定排序(D-082 批 3b 契约 A,低值更外层);从数组末尾向前包裹,首位\n\t\t\t\t\t// wrapper 即最外层,其 next 覆盖其余 wrapper 直至底层默认调用。每次请求\n\t\t\t\t\t// 时从会话 capability runtime 读取,使 bundled failover 插件(随 manifest\n\t\t\t\t\t// 链装载)与第三方 wrapper 都进入链中——failover 以 priority -100 注册,\n\t\t\t\t\t// 无论装载顺序都在最外层。调用方显式传 options.streamFn 的会话整体绕过\n\t\t\t\t\t// 本装配(含 wrapper),不参与 failover——已知边界。\n\t\t\t\t\tconst wrappers = agentSessionRef.current?.getCapabilityRuntime().getStreamFnWrappers() ?? [];\n\t\t\t\t\ttype ChainStreamFn = (\n\t\t\t\t\t\trequestModel: Model<Api>,\n\t\t\t\t\t\trequestContext: Context,\n\t\t\t\t\t\trequestOptions?: SimpleStreamOptions,\n\t\t\t\t\t) => AssistantMessageEventStream;\n\t\t\t\t\tlet chain: ChainStreamFn = baseStreamFn;\n\t\t\t\t\tfor (let index = wrappers.length - 1; index >= 0; index -= 1) {\n\t\t\t\t\t\tconst wrapper = wrappers[index];\n\t\t\t\t\t\tconst inner = chain;\n\t\t\t\t\t\tchain = (requestModel, requestContext, requestOptions) =>\n\t\t\t\t\t\t\twrapper(\n\t\t\t\t\t\t\t\trequestModel,\n\t\t\t\t\t\t\t\trequestContext,\n\t\t\t\t\t\t\t\trequestOptions,\n\t\t\t\t\t\t\t\t(nextModel, nextContext, nextOptions) =>\n\t\t\t\t\t\t\t\t\tinner(\n\t\t\t\t\t\t\t\t\t\tnextModel as Model<Api>,\n\t\t\t\t\t\t\t\t\t\tnextContext as Context,\n\t\t\t\t\t\t\t\t\t\tnextOptions as SimpleStreamOptions | undefined,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tresolveModel: (provider, modelId) => modelRuntime.getModel(provider, modelId),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t) as AssistantMessageEventStream;\n\t\t\t\t\t}\n\t\t\t\t\treturn chain(model, context, options);\n\t\t\t\t},\n\t\tonPayload: async (payload, model) => {\n\t\t\t// 轨迹快照(设计 §4.2 llm.request):最终 payload 转发给装配域收集器;\n\t\t\t// 转发自身失败只记日志,绝不影响请求。\n\t\t\ttry {\n\t\t\t\ttraceService?.adapter.captureProviderPayload(payload, model?.id);\n\t\t\t} catch (error) {\n\t\t\t\thostLogger?.warn(\"sdk\", \"trace payload capture failed\", { cause: error });\n\t\t\t}\n\t\t},\n\t\tsessionId: sessionManager.getSessionId(),\n\t\ttransformContext: async (messages) => {\n\t\t\t// (B1 记忆自动注入已迁至 builtin memory 能力插件的 transformContext 链\n\t\t\t// 环节,D-071;后台委派结算回注迁至 sink 侧 sendCustomMessage,D-060\n\t\t\t// 裁决 12——本装配域自身不再做请求时注入。)\n\t\t\treturn messages;\n\t\t},\n\t\tsteeringMode: settingsManager.getSteeringMode(),\n\t\tfollowUpMode: settingsManager.getFollowUpMode(),\n\t\ttransport: settingsManager.getTransport(),\n\t\tthinkingBudgets: settingsManager.getThinkingBudgets(),\n\t\tmaxRetryDelayMs: settingsManager.getProviderRetrySettings().maxRetryDelayMs,\n\t});\n\n\t// Restore messages if session has existing data\n\tif (hasExistingSession) {\n\t\tagent.state.messages = existingSession.messages;\n\t\tif (!hasThinkingEntry) {\n\t\t\tsessionManager.appendThinkingLevelChange(thinkingLevel);\n\t\t}\n\t} else {\n\t\t// Save initial model and thinking level for new sessions so they can be restored on resume\n\t\tif (model) {\n\t\t\tsessionManager.appendModelChange(model.provider, model.id);\n\t\t}\n\t\tsessionManager.appendThinkingLevelChange(thinkingLevel);\n\t}\n\n\t// Assistant preference card (统一修复轮 A 交付3, H2 接线) migrated into the\n\t// memory plugin package with the S4 fourth batch: the plugin's\n\t// transformContext loop hook reads the ledger-backed card and injects it on\n\t// assistant-oriented sessions itself. The sdk no longer loads or injects\n\t// the card.\n\n\tconst session = new AgentSession({\n\t\tagent,\n\t\tsessionManager,\n\t\tsettingsManager,\n\t\tcwd,\n\t\tscopedModels: options.scopedModels,\n\t\tresourceLoader,\n\t\tcustomTools: options.customTools,\n\t\tmodelRuntime,\n\t\tinitialActiveToolNames,\n\t\tallowedToolNames,\n\t\texcludedToolNames,\n\t\t// 延迟工具(MCP `deferredTools: true`):services 装配域解析出的插件 id 集\n\t\t// 合在此过线;AgentSession 据此注册 tool_search 并把对应插件的新工具排除出\n\t\t// 默认激活集(agent-session-tools 的默认激活分支)。\n\t\t...(options.deferredToolPluginIds === undefined ? {} : { deferredToolPluginIds: options.deferredToolPluginIds }),\n\t\tsessionStartEvent: options.sessionStartEvent,\n\t\tcapabilityMode: options.capabilityMode,\n\t\tcontextStrategyName: options.contextStrategyName,\n\t\tretryPolicyName: options.retryPolicyName,\n\t\tcompactionPolicyName: options.compactionPolicyName,\n\t\toverflowPolicyName: options.overflowPolicyName,\n\t\tbranchSummaryPolicyName: options.branchSummaryPolicyName,\n\t\trunLoopStrategyName: options.runLoopStrategyName,\n\t\t// 承载退役切片 2:装配域无默认 creator——委派承载 = 宿主 adapter 或 CLI 自动池化。\n\t\tagentTaskAdapter: options.enableAgentTasks === false ? undefined : options.agentTaskAdapter,\n\t\t...(options.agentTaskResults === undefined ? {} : { agentTaskResults: options.agentTaskResults }),\n\t\t// 会话回读(D-060 S3):按 sessionId 读子会话 transcript,作用域在**宿主侧**强制——\n\t\t// 只放行本会话自己的子会话(文件头 parentAgentSession 必须等于本会话 id),\n\t\t// 越界与不存在同型返回 undefined。\n\t\t...(options.enableAgentTasks === false\n\t\t\t? {}\n\t\t\t: {\n\t\t\t\t\tagentSessionReader: async (sessionId: string) => {\n\t\t\t\t\t\tconst parentSession = agentSessionRef.current;\n\t\t\t\t\t\tif (parentSession === undefined) return undefined;\n\t\t\t\t\t\tconst read = readAgentSession({ agentDir, sessionId });\n\t\t\t\t\t\tif (read === undefined || read.parentAgentSession !== parentSession.sessionId) return undefined;\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tsessionId: read.sessionId,\n\t\t\t\t\t\t\t...(read.parentAgentSession === undefined ? {} : { parentAgentSession: read.parentAgentSession }),\n\t\t\t\t\t\t\t...(read.agentRole === undefined ? {} : { agentRole: read.agentRole }),\n\t\t\t\t\t\t\t...(read.createdAt === undefined ? {} : { createdAt: read.createdAt }),\n\t\t\t\t\t\t\tbytes: read.bytes,\n\t\t\t\t\t\t\tentryCount: read.entryCount,\n\t\t\t\t\t\t\ttruncated: read.truncated,\n\t\t\t\t\t\t\tentries: read.entries,\n\t\t\t\t\t\t};\n\t\t\t\t\t},\n\t\t\t\t\t// 子会话盘点(D-060 模型面):只列本会话自己的子会话摘要(store 默认\n\t\t\t\t\t// 最近活动倒序、上限 200),读落盘目录,跨进程重启仍可列出。\n\t\t\t\t\tagentSessionLister: async (): Promise<AgentTaskSessionSummaryV1[]> => {\n\t\t\t\t\t\tconst parentSession = agentSessionRef.current;\n\t\t\t\t\t\tif (parentSession === undefined) return [];\n\t\t\t\t\t\treturn listAgentSessions({ agentDir, parentAgentSession: parentSession.sessionId }).map(\n\t\t\t\t\t\t\t(summary) => ({\n\t\t\t\t\t\t\t\tsessionId: summary.sessionId,\n\t\t\t\t\t\t\t\t...(summary.agentRole === undefined ? {} : { agentRole: summary.agentRole }),\n\t\t\t\t\t\t\t\t...(summary.createdAt === undefined ? {} : { createdAt: summary.createdAt }),\n\t\t\t\t\t\t\t\tmodifiedAt: summary.modifiedAt,\n\t\t\t\t\t\t\t\tbytes: summary.bytes,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\tagentComposition: options.agentComposition,\n\t\tinteractionHost: options.interactionHost,\n\t\t// 打点通道下沉(设计 §5.2/§7.2):会话级进程日志打点(插件日志镜像、内建\n\t\t// 装载失败等)与 plugin.log 轨迹镜像共享 ref(插件门面注册时写入,空 = 无\n\t\t// 镜像)。\n\t\thostLogger: options.hostLogger,\n\t\tlogRecordMirrorRef: observabilityLogMirror,\n\t\tobservabilityGetMetricsRef: observabilityGetMetrics,\n\t\t// D-075 S4 第二批:宿主 agentDir 上公共 HostCapabilities(磁盘状态插件的\n\t\t// 配置通道),trace 服务随 traceEnabled 注入 installed observability 包。\n\t\tagentDir,\n\t\t// D-075 S4 第三批:subagent-delegate 宿主服务上公共 HostCapabilities——\n\t\t// communication(父侧 drain + 注入的叶子 post 接线合并)、turnContext\n\t\t// (后台结算摘要 sink + 回合 correlationId 捕获)、roleAssociations(当前\n\t\t// 方案关联角色;角色定义只在磁盘 <agentDir>/roles/,无编译内定义)。\n\t\t// 原内嵌 builtin 构造选项链退役;独立插件包 entry 从 api.host 组装同一形状。\n\t\t...(communicationWiring === undefined ? {} : { communication: communicationWiring }),\n\t\t...(options.enableAgentTasks === false\n\t\t\t? {}\n\t\t\t: {\n\t\t\t\t\tturnContext: {\n\t\t\t\t\t\tbackgroundDigestSink: (line: string) => {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tconst session = agentSessionRef.current;\n\t\t\t\t\t\t\t\t// 轨迹闭合(第 4 期):结算行同步投递为 agent.task.settled@1(解析\n\t\t\t\t\t\t\t\t// 失败/非法 status 降级为 hostLogger warn;dispose 后派发助手 no-op),\n\t\t\t\t\t\t\t\t// 返回的 facts 供回注复用(同一行不二次 parse)。\n\t\t\t\t\t\t\t\tconst facts = deliverAgentTaskSettledDigestLine(session, line, hostLogger);\n\t\t\t\t\t\t\t\t// 结算回注(D-060 裁决 12,用户裁决 2026-10-02):结算即时回注主\n\t\t\t\t\t\t\t\t// 会话为一条 agent-task-settled custom message——主在跑经 followUp\n\t\t\t\t\t\t\t\t// 入队(本轮 drain、不抢占当前回合),主空闲时同一调用原子触发验\n\t\t\t\t\t\t\t\t// 收回合(被动机制,主不需要主动找子)。会话未建、已 dispose(同\n\t\t\t\t\t\t\t\t// 步置 isDisposed,读取时点无竞态)或行解析失败时跳过,不产生孤儿\n\t\t\t\t\t\t\t\t// 回合;手动压缩进行中由会话层降级为 followUp 入队(不穿透压缩\n\t\t\t\t\t\t\t\t// revision 互斥)。\n\t\t\t\t\t\t\t\tif (facts === undefined || session === undefined || session.isDisposed) return;\n\t\t\t\t\t\t\t\tconst reasonSuffix = facts.reasonCode === undefined ? \"\" : ` (reason: ${facts.reasonCode})`;\n\t\t\t\t\t\t\t\tconst summary = `Background subagent task ${facts.taskId} settled: ${facts.status}${reasonSuffix}.`;\n\t\t\t\t\t\t\t\tvoid session\n\t\t\t\t\t\t\t\t\t.sendCustomMessage(\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tcustomType: \"agent-task-settled\",\n\t\t\t\t\t\t\t\t\t\t\t// 首行是用户可读摘要(TUI custom message 渲染 content 全文),\n\t\t\t\t\t\t\t\t\t\t\t// 第二行指引模型收割完整结果并验收(custom 投影为 user 消息,\n\t\t\t\t\t\t\t\t\t\t\t// content 全文模型可见)。\n\t\t\t\t\t\t\t\t\t\t\tcontent:\n\t\t\t\t\t\t\t\t\t\t\t\t`${summary}\\n` +\n\t\t\t\t\t\t\t\t\t\t\t\t\"The settled result can be read with subagent_result (optionally waiting); read it and review the outcome before continuing.\",\n\t\t\t\t\t\t\t\t\t\t\tdisplay: true,\n\t\t\t\t\t\t\t\t\t\t\tdetails: {\n\t\t\t\t\t\t\t\t\t\t\t\ttaskId: facts.taskId,\n\t\t\t\t\t\t\t\t\t\t\t\ttaskSessionId: facts.taskSessionId,\n\t\t\t\t\t\t\t\t\t\t\t\tstatus: facts.status,\n\t\t\t\t\t\t\t\t\t\t\t\t...(facts.reasonCode === undefined ? {} : { reasonCode: facts.reasonCode }),\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{ deliverAs: \"followUp\", triggerTurn: true },\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t.catch((error) => {\n\t\t\t\t\t\t\t\t\t\t// 回注失败不影响 delegate 任务本身(终态已在调度器落库,可经\n\t\t\t\t\t\t\t\t\t\t// subagent_result 收割)——与结算观察器的 catch 注释同风格。\n\t\t\t\t\t\t\t\t\t\thostLogger?.warn(\"sdk\", \"background delegation settlement delivery failed\", {\n\t\t\t\t\t\t\t\t\t\t\tcause: error,\n\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t\t// sink 是同步函数且挂在 promise 链上:守卫外异常只记日志,不外抛。\n\t\t\t\t\t\t\t\thostLogger?.warn(\"sdk\", \"background delegation settlement sink failed\", {\n\t\t\t\t\t\t\t\t\tcause: error,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t// 回合级血缘(第 3 期第二批):委派提交时刻捕获父回合 correlationId,\n\t\t\t\t\t\t// 随 subagent_run metadata 过线(仅 create 新建路径消费)。\n\t\t\t\t\t\tgetTurnCorrelationId: () => agentSessionRef.current?.getTurnCorrelationId(),\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t...(options.enableAgentTasks === false ? {} : { roleAssociations: suiteWorkspace.suite.associations.roles }),\n\t\t...(traceService === undefined ? {} : { traceService }),\n\t\t// D-075 S4 第四批:记忆底层组件注入上公共 HostCapabilities——\n\t\t// `api.host.memoryStorage`,安装店的 memory 插件包 entry 组装消费\n\t\t// (store/ledger 工厂与向量组件公共契约,缺省 = 包内默认实现)。\n\t\t...(options.memoryCapability?.storage === undefined ? {} : { memoryStorage: options.memoryCapability.storage }),\n\t\t// Orientation persona (设计 §6.2, M2): the resolved suite's orientation\n\t\t// text rides every system prompt rebuild on this session. A custom\n\t\t// orientation's persona text comes from the workspace persona.md,\n\t\t// already resolved by loadSuiteWorkspace (设计 §6.3). Capability tool\n\t\t// guides (memory / task management, D-071) ride the owning tools'\n\t\t// promptGuidelines instead.\n\t\torientationPrompt: suiteWorkspace.orientationPersona,\n\t\t// Capability wiring (方案系统 M3): undefined when the assembly boundary\n\t\t// disabled wiring, so the session keeps its default (unwired) identity.\n\t\t...(capabilitySkillsFilter === undefined ? {} : { capabilitySkillsFilter }),\n\t});\n\tagentSessionRef.current = session;\n\t// provider-failover 装配(设计 供应商能力槽位与主备切换 §4.8,D-082 批 3b):\n\t// 内嵌 installProviderFailoverPlugin 退役为 bundled 插件包\n\t// (plugins/provider-failover,id agent-forge.plugin.provider-failover),经\n\t// 下方 bundled 分发通道装载。配置注入见装载循环的 configOverride 分支\n\t// (settings `failover` 节存在时注入 `{version: 1, failover: <节点原样>}`,\n\t// 预检读面经 api.host.modelCatalog 契约 B 注入);wrapper 以 priority -100\n\t// 注册(契约 A),无论装载顺序都在链最外层——装配时序不再依赖 manifest 链。\n\t// Session-suite binding (设计 §10.1): record the suite as session protocol\n\t// data via the existing custom-entry extension point. New sessions only;\n\t// resumed sessions keep their original binding.\n\t// 新会话写入绑定;失败残留(有绑定但无对话)恢复时重写为当前装配——\n\t// readSessionSuiteBinding 取 latest,之后的绑定检查语义与实际装配一致。\n\t// 有对话的既有会话保持原绑定(护栏语义)。\n\tif (!hasExistingSession || (sessionSuiteBinding !== undefined && !hasConversation) || options.allowSuiteRebind) {\n\t\tsession.sessionManager.appendCustomEntry(SUITE_SESSION_ENTRY_TYPE, {\n\t\t\tsuiteId,\n\t\t\tprofileIdentity: suiteWorkspace.identity,\n\t\t});\n\t}\n\tconst pluginRejections: PluginRejection[] = [];\n\tconst recordRejection = async (\n\t\tcode: PluginRejection[\"code\"],\n\t\tmanifestPath: string,\n\t\tpluginId: string | undefined,\n\t\tmessage: string,\n\t): Promise<void> => {\n\t\tconst rejection: PluginRejection = Object.freeze({\n\t\t\tcode,\n\t\t\tmanifestPath,\n\t\t\t...(pluginId === undefined ? {} : { pluginId }),\n\t\t\tmessage,\n\t\t});\n\t\tpluginRejections.push(rejection);\n\t\t// 插件装载失败打点(设计 §5.2):结构化 rejection 之外的进程日志一行,\n\t\t// 让轨迹中断时可以凭日志定位。\n\t\thostLogger?.error(\"sdk\", `capability plugin rejected: ${message}`, {\n\t\t\tsessionId: session.sessionId,\n\t\t\tfields: { code: rejection.code, pluginId: rejection.pluginId, manifestPath: rejection.manifestPath },\n\t\t});\n\t\ttry {\n\t\t\tawait session.getCapabilityRuntime().recordPluginRejection(rejection);\n\t\t} catch {\n\t\t\t// Rejection visibility must never fail the remaining startup path.\n\t\t}\n\t};\n\tconst rejectionMessage = (error: unknown): string => (error instanceof Error ? error.message : String(error));\n\ttry {\n\t\tconst discoveredManifestPaths =\n\t\t\toptions.discoverCapabilityPlugins === false\n\t\t\t\t? []\n\t\t\t\t: discoverCapabilityPluginManifests([join(agentDir, \"plugins\"), join(cwd, CONFIG_DIR_NAME, \"plugins\")]);\n\t\t// Suite-local plugin layer (统一修复轮 B): manifests below\n\t\t// <suiteDir>/plugins load when the suite is active and the capability\n\t\t// surface is wired; suite activation is their association, so they bypass\n\t\t// associations.plugins filtering like explicit caller paths and win\n\t\t// duplicate-id resolution over the pools. The discovery switch gates them\n\t\t// too, so callers that disable plugin discovery (child sessions) keep\n\t\t// today's plugin-free face.\n\t\tconst suiteLocalManifestPaths =\n\t\t\tcapabilityWiring && options.discoverCapabilityPlugins !== false && suiteAssembly.localPluginsDir !== undefined\n\t\t\t\t? discoverCapabilityPluginManifests([suiteAssembly.localPluginsDir])\n\t\t\t\t: [];\n\t\t// Installed-code-loading (D-075 S2): verified active installations whose\n\t\t// plugin id is a member of the resolved plugin profile (selected, not\n\t\t// disabled) join the pool as explicit candidates; their code loads\n\t\t// through session.loadCapabilityPluginManifest exactly like\n\t\t// caller-supplied paths. Installed plugins that miss membership stay\n\t\t// unloaded — one diagnostic, no implicit third-party loading.\n\t\tconst disabledPluginIdSet = new Set(options.disabledPluginIds ?? []);\n\t\tconst profilePluginIds =\n\t\t\tsuiteAssembly.pluginProfile !== undefined && suiteAssembly.pluginProfile.status === \"resolved\"\n\t\t\t\t? new Set(\n\t\t\t\t\t\tsuiteAssembly.pluginProfile.profile.pluginIds.filter(\n\t\t\t\t\t\t\t(pluginId) => !disabledPluginIdSet.has(pluginId),\n\t\t\t\t\t\t),\n\t\t\t\t\t)\n\t\t\t\t: new Set<string>();\n\t\t// S4 拆包(D-075 §6 S4 第一批):suite.capabilities 声明的\n\t\t// builtin.goal/builtin.plan/builtin.todo-set 短 id 不再有内嵌注册,经\n\t\t// BUILTIN_CAPABILITY_PACKAGE_IDS 映射到独立插件包 id,并入 installed 插件的\n\t\t// 成员资格集合——已安装即随装配链加载(active-bindings 来源不变),未安装时\n\t\t// 静默缺席(不算 dangling);用户显式 disable 仍然生效。第二批:session-share\n\t\t// 短 id 同样经映射接管;observability 包 id 随 traceEnabled 直接并入(trace\n\t\t// 关闭时不并入 = 插件不加载,与内嵌时代\"不注册即禁用\"语义一致)。第四批:\n\t\t// builtin.memory 经映射接管,但 memory.mode 解析为 off 时不并入(禁用 = 不装\n\t\t// 配,与内嵌时代\"禁用 = 不注册\"同语义;上面已带一行启动声明)。\n\t\t// 直通语义(第三方分发链路修复):非 builtin 条目是安装店插件包 id,原样\n\t\t// 并入成员资格集合(与映射后的 agent-forge.plugin.* 同等:已安装即加载、\n\t\t// 用户显式 disable 仍生效)——不再静默丢弃,否则第三方插件经\n\t\t// plugin install 装入后任何套件都选不中它。\n\t\tconst passthroughCapabilityPluginIds: string[] = [];\n\t\tconst capabilityPackageIds = suiteWorkspace.suite.capabilities.flatMap((entry) => {\n\t\t\tconst mappedPluginId = (BUILTIN_CAPABILITY_PACKAGE_IDS as Readonly<Record<string, string>>)[entry];\n\t\t\tif (mappedPluginId !== undefined) return [mappedPluginId];\n\t\t\tpassthroughCapabilityPluginIds.push(entry);\n\t\t\treturn [entry];\n\t\t});\n\t\tif (options.traceEnabled !== false) capabilityPackageIds.push(OBSERVABILITY_PACKAGE_ID);\n\t\tif (memoryModeResolution.mode === \"off\") {\n\t\t\tconst memoryIndex = capabilityPackageIds.indexOf(MEMORY_PACKAGE_ID);\n\t\t\tif (memoryIndex >= 0) capabilityPackageIds.splice(memoryIndex, 1);\n\t\t}\n\t\tfor (const pluginId of capabilityPackageIds) {\n\t\t\tif (!disabledPluginIdSet.has(pluginId)) profilePluginIds.add(pluginId);\n\t\t}\n\t\t// 非 builtin 条目的 dangling 诊断(先例 associations.plugins,设计 §11.3):\n\t\t// 安装店无对应已装插件时恰一条;已装但被用户显式 disable 不诊断(主动\n\t\t// 行为);builtin 短 id 未安装保持静默缺席(上方映射注释)。门控跟随\n\t\t// capabilityWiring:自持 loader 的子装配域保持插件无关诊断面。\n\t\tif (capabilityWiring && passthroughCapabilityPluginIds.length > 0) {\n\t\t\tconst installedPluginIdSet = new Set(\n\t\t\t\t(options.installedCapabilityPlugins ?? []).map((plugin) => plugin.pluginId),\n\t\t\t);\n\t\t\t// Bundled-channel plugins (D-082 §4.9) ship with the host and load\n\t\t\t// without an install-store entry, so a suite declaration for one of\n\t\t\t// them is satisfiable even though it is absent from the installed\n\t\t\t// set (macCRM dogfood 2026-10-04: provider-failover worked while the\n\t\t\t// warning claimed it was missing).\n\t\t\tconst bundledDirNames = new Set(\n\t\t\t\tbundledCapabilityPluginRoots()\n\t\t\t\t\t.toolRoots.concat(bundledCapabilityPluginRoots().policyRoots)\n\t\t\t\t\t.flatMap((root) => (existsSync(root) ? readdirSync(root) : [])),\n\t\t\t);\n\t\t\tfor (const pluginId of passthroughCapabilityPluginIds) {\n\t\t\t\tif (installedPluginIdSet.has(pluginId)) continue;\n\t\t\t\tif (bundledDirNames.has(pluginId.split(\".\").pop() ?? \"\")) continue;\n\t\t\t\tcapabilityDiagnostics.push(\n\t\t\t\t\t`Suite \"${suiteId}\" capability \"${pluginId}\" has no installed active plugin; install it with agent-forge plugin install or remove the declaration`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tconst installedPluginManifestPaths: string[] = [];\n\t\tconst skippedInstalledPluginIds: string[] = [];\n\t\tfor (const plugin of options.installedCapabilityPlugins ?? []) {\n\t\t\tif (profilePluginIds.has(plugin.pluginId)) installedPluginManifestPaths.push(plugin.manifestPath);\n\t\t\telse skippedInstalledPluginIds.push(plugin.pluginId);\n\t\t}\n\t\tif (skippedInstalledPluginIds.length > 0) {\n\t\t\tcapabilityDiagnostics.push(\n\t\t\t\t`Installed capability plugins stay unloaded because the active profile did not select them: ${skippedInstalledPluginIds.sort().join(\", \")}`,\n\t\t\t);\n\t\t}\n\t\t// Bundled 分发通道(D-082 §4.9,批 1 工具批 / 批 3 策略批):发行物附带的第一方\n\t\t// 插件包作为数据文件随宿主分发,经与安装店完全相同的 manifest/jiti 通道装载;\n\t\t// 优先级在 installed 之后、目录发现之前(安装店显式安装 > bundled >\n\t\t// 目录发现)。这不是用户插件发现通道:内嵌默认面不受\n\t\t// discoverCapabilityPlugins 与 suite capabilities 声明门控——工具面\n\t\t// (coding-tools)沿用内嵌装配的无条件下发语义;策略面(四个默认策略插件,\n\t\t// 内嵌 installBootstrap* 时代随会话无条件安装)同样无条件下发且不受\n\t\t// noTools 门控;其余 bundled 候选按套件成员资格过滤。noTools(\"all\"/\n\t\t// \"builtin\",对照内嵌工具装配的跳过语义)只跳过工具面。\n\t\tconst bundledRoots = bundledCapabilityPluginRoots();\n\t\tconst bundledToolManifestPaths =\n\t\t\toptions.noTools === undefined ? discoverCapabilityPluginManifests(bundledRoots.toolRoots) : [];\n\t\tconst bundledPolicyManifestPaths = discoverCapabilityPluginManifests(bundledRoots.policyRoots);\n\t\tconst bundledManifestPaths = [...bundledToolManifestPaths, ...bundledPolicyManifestPaths];\n\t\tconst bundledManifestPathSet = new Set(bundledManifestPaths);\n\t\tconst manifestPaths = [\n\t\t\t...suiteLocalManifestPaths,\n\t\t\t...installedPluginManifestPaths,\n\t\t\t...bundledManifestPaths,\n\t\t\t...discoveredManifestPaths,\n\t\t\t...(options.capabilityPluginPaths ?? []),\n\t\t];\n\t\tconst explicitCandidatePaths = new Set([\n\t\t\t...suiteLocalManifestPaths,\n\t\t\t...installedPluginManifestPaths,\n\t\t\t...bundledManifestPaths,\n\t\t\t...(options.capabilityPluginPaths ?? []),\n\t\t]);\n\t\tconst loadedManifestPaths = new Set<string>();\n\t\tconst explicitManifestPaths = new Set<string>();\n\t\tconst candidatePaths: string[] = [];\n\t\tfor (const manifestPath of manifestPaths) {\n\t\t\tconst resolvedManifestPath = resolve(cwd, manifestPath);\n\t\t\tconst manifestIdentity = existsSync(resolvedManifestPath)\n\t\t\t\t? realpathSync(resolvedManifestPath)\n\t\t\t\t: resolvedManifestPath;\n\t\t\tif (loadedManifestPaths.has(manifestIdentity)) continue;\n\t\t\tloadedManifestPaths.add(manifestIdentity);\n\t\t\tif (explicitCandidatePaths.has(manifestPath)) explicitManifestPaths.add(manifestIdentity);\n\t\t\tcandidatePaths.push(manifestIdentity);\n\t\t}\n\t\t// Single-plugin manifest failures reject that plugin only (D-028); the\n\t\t// session keeps loading the remaining candidates. The D-073 host-version\n\t\t// range gate is semantic (not a parse failure): a manifest whose\n\t\t// declared hostVersion range excludes the running VERSION is rejected\n\t\t// with its own reason code, and a manifest without hostVersion loads\n\t\t// but emits a one-line diagnostic.\n\t\tconst manifestEntries: Array<{ path: string; manifest: PluginManifest }> = [];\n\t\tfor (const manifestPath of candidatePaths) {\n\t\t\ttry {\n\t\t\t\tconst manifest = await readCapabilityPluginManifestForOrdering(manifestPath);\n\t\t\t\tif (manifest.hostVersion !== undefined) {\n\t\t\t\t\tif (!satisfies(VERSION, manifest.hostVersion)) {\n\t\t\t\t\t\tawait recordRejection(\n\t\t\t\t\t\t\t\"host_version_incompatible\",\n\t\t\t\t\t\t\tmanifestPath,\n\t\t\t\t\t\t\tmanifest.id,\n\t\t\t\t\t\t\t`Plugin ${manifest.id} declares host version range \"${manifest.hostVersion}\", but the host is ${VERSION}. Upgrade the host into the declared range, or install a plugin version that supports host ${VERSION}.`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tcapabilityDiagnostics.push(\n\t\t\t\t\t\t`Capability plugin ${manifest.id} (${manifestPath}) does not declare \"hostVersion\"; it loads, but published plugins must declare a host semver range (e.g. \">=${VERSION}\").`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tmanifestEntries.push({ path: manifestPath, manifest });\n\t\t\t} catch (error) {\n\t\t\t\tawait recordRejection(\"invalid_manifest\", manifestPath, undefined, rejectionMessage(error));\n\t\t\t}\n\t\t}\n\t\t// Duplicate plugin IDs keep the first candidate in discovery order and\n\t\t// reject the later duplicates. When suite capability wiring is on, the\n\t\t// external plugin pool is filtered by `associations.plugins` (方案系统\n\t\t// M3): the project-level pool (cwd/.agent-forge/plugins) is the third\n\t\t// layer and always passes; every other manifest must match an\n\t\t// association exactly. Explicit capabilityPluginPaths are caller intent\n\t\t// and bypass the filter; filtered plugins and dangling associations\n\t\t// surface as suite diagnostics, never as errors.\n\t\tconst poolFilter = capabilityWiring\n\t\t\t? {\n\t\t\t\t\tsuite: suiteWorkspace.suite,\n\t\t\t\t\tdecide: (manifestId: string, manifestPath: string) =>\n\t\t\t\t\t\tdecideSuiteCapabilityPlugin(suiteWorkspace.suite, { manifestId, manifestPath }, { cwd }),\n\t\t\t\t}\n\t\t\t: undefined;\n\t\tconst seenPluginIds = new Set<string>();\n\t\tconst uniqueEntries: Array<{ path: string; manifest: PluginManifest }> = [];\n\t\tconst discoveredPluginIds: string[] = [];\n\t\tfor (const entry of manifestEntries) {\n\t\t\tdiscoveredPluginIds.push(entry.manifest.id);\n\t\t\tconst bundledCandidate = bundledManifestPathSet.has(entry.path);\n\t\t\t// Bundled 层过滤:bundled 装配豁免集合(coding-tools 工具面 + 四个默认\n\t\t\t// 策略插件 + config 门控的 provider-failover,BUNDLED_WIRING_EXEMPT_\n\t\t\t// PLUGIN_IDS)不受 suite capabilities 声明门控,与内嵌装配同语义——\n\t\t\t// failover 的\"配置存在即装配\"不是套件声明可关闭的面(disabledPluginIds\n\t\t\t// 仍可显式禁用);其余 bundled 候选与 installed 层同法——\n\t\t\t// capabilityWiring 开启时插件 id 必须命中 capabilityPackageIds(套件\n\t\t\t// 未选中的包静默缺席),关闭(自持 loader 的宿主)全收,保底拿到产品\n\t\t\t// 默认面。disabledPluginIds(既有用户面)作用于全部 bundled 候选。\n\t\t\tif (bundledCandidate) {\n\t\t\t\tif (!BUNDLED_WIRING_EXEMPT_PLUGIN_IDS.has(entry.manifest.id) && capabilityWiring) {\n\t\t\t\t\tif (!capabilityPackageIds.includes(entry.manifest.id)) continue;\n\t\t\t\t}\n\t\t\t\tif (disabledPluginIdSet.has(entry.manifest.id)) continue;\n\t\t\t}\n\t\t\tif (poolFilter && !explicitManifestPaths.has(entry.path)) {\n\t\t\t\tconst decision = poolFilter.decide(entry.manifest.id, entry.path);\n\t\t\t\tif (!decision.keep) {\n\t\t\t\t\tif (decision.diagnostic) capabilityDiagnostics.push(decision.diagnostic);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (seenPluginIds.has(entry.manifest.id)) {\n\t\t\t\t// Bundled 候选与更高优先层(suiteLocal/installed/前一根 bundled)同 id\n\t\t\t\t// 时按发现优先级静默让位(安装店显式安装 > bundled;产品自带副本被\n\t\t\t\t// 遮蔽是设计内的优先级,不是冲突)。目录发现层的重复 id 保持既有\n\t\t\t\t// duplicate_plugin_id rejection(第三方同 id 冲突需要显形)。\n\t\t\t\tif (!bundledCandidate) {\n\t\t\t\t\tawait recordRejection(\n\t\t\t\t\t\t\"duplicate_plugin_id\",\n\t\t\t\t\t\tentry.path,\n\t\t\t\t\t\tentry.manifest.id,\n\t\t\t\t\t\t`Capability plugin is already loaded: ${entry.manifest.id}; the first manifest in discovery order wins`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tseenPluginIds.add(entry.manifest.id);\n\t\t\tuniqueEntries.push(entry);\n\t\t}\n\t\tif (poolFilter) {\n\t\t\tcapabilityDiagnostics.push(...suiteDanglingPluginAssociations(poolFilter.suite, discoveredPluginIds));\n\t\t}\n\t\t// Required-capability shortfalls reject the dependent plugin and, by\n\t\t// fixpoint, everything that (transitively) required it. Optional\n\t\t// requirements never reject. Combination-level failures that\n\t\t// resolvePluginCapabilityOrder still detects (duplicate capability\n\t\t// identity, dependency cycles) fail the whole startup explicitly.\n\t\tconst capabilityIdentity = (id: string, version: number): string => `${id}\\u0000${version}`;\n\t\tconst survivors = new Set(uniqueEntries);\n\t\tlet removedInLastPass = true;\n\t\twhile (removedInLastPass) {\n\t\t\tremovedInLastPass = false;\n\t\t\tconst providers = new Set<string>();\n\t\t\tfor (const entry of survivors) {\n\t\t\t\tfor (const declaration of entry.manifest.provides ?? []) {\n\t\t\t\t\tproviders.add(capabilityIdentity(declaration.id, declaration.version));\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const entry of [...survivors]) {\n\t\t\t\tconst missing = (entry.manifest.requires ?? []).filter(\n\t\t\t\t\t(requirement) =>\n\t\t\t\t\t\t!requirement.optional && !providers.has(capabilityIdentity(requirement.id, requirement.version)),\n\t\t\t\t);\n\t\t\t\tif (missing.length === 0) continue;\n\t\t\t\tawait recordRejection(\n\t\t\t\t\t\"missing_dependency\",\n\t\t\t\t\tentry.path,\n\t\t\t\t\tentry.manifest.id,\n\t\t\t\t\t`Plugin capability is required but unavailable: ${missing\n\t\t\t\t\t\t.map((requirement) => `${requirement.id}@${requirement.version}`)\n\t\t\t\t\t\t.join(\", \")} (${entry.manifest.id})`,\n\t\t\t\t);\n\t\t\t\tsurvivors.delete(entry);\n\t\t\t\tremovedInLastPass = true;\n\t\t\t}\n\t\t}\n\t\tconst pathByManifest = new Map([...survivors].map((entry) => [entry.manifest, entry.path] as const));\n\t\t// 按需挂载(插件按需挂载与能力手册设计 §4/§5):activation \"on-demand\"\n\t\t// 的幸存插件注册但不进初始激活集——卡片(一行描述)与手册路径在此定型并\n\t\t// 注册进会话,由 capability_mount 按插件粒度激活,unmount 仅摘 schema。\n\t\tconst deferredCapabilityCards = [...survivors]\n\t\t\t.filter((entry) => entry.manifest.activation === \"on-demand\")\n\t\t\t.map((entry) => ({\n\t\t\t\tpluginId: entry.manifest.id,\n\t\t\t\tdescription: entry.manifest.description,\n\t\t\t\tmanualPath:\n\t\t\t\t\tentry.manifest.manual === undefined ? undefined : resolve(dirname(entry.path), entry.manifest.manual),\n\t\t\t}));\n\t\tif (deferredCapabilityCards.length > 0) {\n\t\t\tsession.registerDeferredCapabilityCards(deferredCapabilityCards);\n\t\t}\n\t\t// 生图槽位注入供料(供应商能力槽位设计 §3.3):settings 槽位经 settings-manager\n\t\t// 校验后的读面取(非法形状已 fail-closed 丢弃并记 warning),目录快照经\n\t\t// ModelRuntime 投影 models.json 登记项(装配期静态数据)。\n\t\tconst imageGenerationSlot = settingsManager.getCapabilitiesSettings()?.imageGeneration;\n\t\tconst imageModelCatalog = modelRuntime.getImageModelCatalog();\n\t\tfor (const manifest of resolvePluginCapabilityOrder([...survivors].map((entry) => entry.manifest))) {\n\t\t\tconst manifestPath = pathByManifest.get(manifest);\n\t\t\t// v8 ignore next -- 顺序解析返回的 manifest 均来自同一 survivors 集合,路径恒存在\n\t\t\tif (!manifestPath)\n\t\t\t\tthrow new Error(t(\"Capability plugin manifest path is unavailable: {id}\", { id: manifest.id }));\n\t\t\t// 宿主装配事实注入(公共 configOverride 通道):各插件分支注释记载注入\n\t\t\t// 内容与取值链;caller 的 capabilityPluginConfigs[插件 id](D-082 批 1\n\t\t\t// 新增会话选项)按 configOverride 既有分层合并在宿主事实之上(顶层键\n\t\t\t// caller 赢),插件入口的 agent-dir 配置文件仍合并在其上,用户显式配置\n\t\t\t// 保持最终决定权。\n\t\t\tlet hostConfigOverride: PluginConfig | undefined;\n\t\t\t// CLI 自动池化(承载退役切片 1,D-075 S4 第三批收敛):宿主声明自身\n\t\t\t// 入口可信时改写插件 config 的 runnerEntryAuto(原 builtin 注入链的\n\t\t\t// selfInvocationPool 旗标退役);插件入口的 agent-dir 配置文件仍合并\n\t\t\t// 在其上,用户显式配置保持最终决定权。\n\t\t\tif (manifest.id === SUBAGENT_DELEGATE_PACKAGE_ID && options.subagentPoolFromSelfInvocation === true) {\n\t\t\t\thostConfigOverride = { runnerEntryAuto: true };\n\t\t\t}\n\t\t\t// 记忆档位注入(D-075 S4 第四批):显式定档与 settings.json 持久档位经\n\t\t\t// 公共 configOverride 通道合并进 memory 插件包 manifest config——包 entry\n\t\t\t// 按同一解析链定档(显式 > env > settings > 旧别名 > off);agent-dir\n\t\t\t// 配置文件(capabilities/builtin.memory.json)仍合并在其上,用户显式\n\t\t\t// 配置保持最终决定权。mode=off 的包已在上面的成员资格门控中排除,\n\t\t\t// 不会走到这里。\n\t\t\tif (manifest.id === MEMORY_PACKAGE_ID) {\n\t\t\t\thostConfigOverride = {\n\t\t\t\t\t...hostConfigOverride,\n\t\t\t\t\t...(memoryModeOption === undefined ? {} : { memoryMode: memoryModeOption }),\n\t\t\t\t\t...(settingsMemoryMode === undefined ? {} : { memorySettingsMode: settingsMemoryMode }),\n\t\t\t\t};\n\t\t\t}\n\t\t\t// 生图槽位注入(供应商能力槽位设计 §3.3):settings 槽位(provider/model,\n\t\t\t// model 可省)与 models.json 生图目录快照经公共 configOverride 通道注入\n\t\t\t// image-generation 插件包;插件按六层取值链消费(设计 §3.2)。槽位缺省时\n\t\t\t// 只注入快照——插件回落到 env/主推断/唯一候选推断。\n\t\t\tif (manifest.id === IMAGE_GENERATION_PACKAGE_ID) {\n\t\t\t\thostConfigOverride = {\n\t\t\t\t\t...hostConfigOverride,\n\t\t\t\t\t...(imageGenerationSlot === undefined\n\t\t\t\t\t\t? {}\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\timageGeneration: {\n\t\t\t\t\t\t\t\t\tprovider: imageGenerationSlot.provider,\n\t\t\t\t\t\t\t\t\t...(imageGenerationSlot.model === undefined ? {} : { model: imageGenerationSlot.model }),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}),\n\t\t\t\t\timageModelCatalog,\n\t\t\t\t};\n\t\t\t}\n\t\t\t// 默认编码工具会话事实注入(D-082 批 1):cwd 用会话 cwd,read/bash 选项\n\t\t\t// 取值来源对齐内嵌 installSessionBootstrapTools 时代的 settings 解析链\n\t\t\t// (SettingsManager.getImageAutoResize/getShellCommandPrefix/getShellPath),\n\t\t\t// 形状即插件包 CodingToolsPluginConfigV1;未定义的设置键省略(插件侧\n\t\t\t// 保持自身缺省值,与内嵌时代传 undefined 同语义)。\n\t\t\tif (manifest.id === CODING_TOOLS_PACKAGE_ID) {\n\t\t\t\tconst autoResizeImages = settingsManager.getImageAutoResize();\n\t\t\t\tconst shellCommandPrefix = settingsManager.getShellCommandPrefix();\n\t\t\t\tconst shellPath = settingsManager.getShellPath();\n\t\t\t\thostConfigOverride = {\n\t\t\t\t\t...hostConfigOverride,\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tcwd,\n\t\t\t\t\tread: { autoResizeImages },\n\t\t\t\t\tbash: {\n\t\t\t\t\t\t...(shellCommandPrefix === undefined ? {} : { commandPrefix: shellCommandPrefix }),\n\t\t\t\t\t\t...(shellPath === undefined ? {} : { shellPath }),\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\t// provider-failover 配置注入(D-082 批 3b):settings `failover` 节存在\n\t\t\t// 时经 configOverride 通道注入 `{version: 1, failover: <节点原样>}`(节点\n\t\t\t// 来源与内嵌装配时代同一读面:settingsManager.getFailoverSettings 原样\n\t\t\t// 透传合并层对象,解析与校验收在插件包内);节点不存在则不注入——插件\n\t\t\t// 工厂自守卫 no-op(不注册任何面)。caller 的 capabilityPluginConfigs\n\t\t\t// 仍按既有分层合并在其上(顶层键 caller 赢),agent-dir 配置文件保持\n\t\t\t// 用户最终决定权。\n\t\t\tif (manifest.id === PROVIDER_FAILOVER_PACKAGE_ID) {\n\t\t\t\tconst failoverSettings = settingsManager.getFailoverSettings();\n\t\t\t\t// settings 层合并对象是 JSON 数据,仅静态接口不带索引签名;经公共\n\t\t\t\t// 守卫收窄为 PluginConfigValue 后节点原样透传(真实 settings 数据\n\t\t\t\t// 恒为 JSON,守卫不构成行为分支),解析与校验收在插件包内。\n\t\t\t\tif (failoverSettings !== undefined && isPluginConfigValue(failoverSettings)) {\n\t\t\t\t\thostConfigOverride = { version: 1, failover: failoverSettings };\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst callerConfigOverride = options.capabilityPluginConfigs?.[manifest.id];\n\t\t\tconst configOverride =\n\t\t\t\thostConfigOverride === undefined\n\t\t\t\t\t? callerConfigOverride\n\t\t\t\t\t: { ...hostConfigOverride, ...(callerConfigOverride ?? {}) };\n\t\t\ttry {\n\t\t\t\tawait session.loadCapabilityPluginManifest(manifestPath, {\n\t\t\t\t\t...(configOverride === undefined ? {} : { configOverride }),\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tawait recordRejection(\"plugin_load_failed\", manifestPath, manifest.id, rejectionMessage(error));\n\t\t\t}\n\t\t}\n\t\t// Plugin-owned context restoration runs only after all manifests are loaded.\n\t\t// The persisted session remains the source of truth; request-time transforms\n\t\t// must never be written back into that history implicitly.\n\t\tif (hasExistingSession && options.contextStrategyName) {\n\t\t\tawait session.replaceContext(existingSession.messages);\n\t\t}\n\t} catch (error) {\n\t\tawait session.dispose();\n\t\tthrow error;\n\t}\n\t// 会话创建完成打点(设计 §5.2):创建/恢复路径在装配全部完成后落一行 info。\n\thostLogger?.info(\"sdk\", \"agent session created\", {\n\t\tsessionId: session.sessionId,\n\t\tfields: {\n\t\t\tsuite: suiteId,\n\t\t\t...(model === undefined ? {} : { model: `${model.provider}/${model.id}` }),\n\t\t\ttrace: options.traceEnabled !== false,\n\t\t},\n\t});\n\n\treturn {\n\t\tsession,\n\t\tmodelFallbackMessage,\n\t\tpluginRejections: Object.freeze(pluginRejections.slice()),\n\t\tsuiteDiagnostics: Object.freeze([\n\t\t\t...suiteAssembly.collectDiagnostics(),\n\t\t\t...capabilityDiagnostics,\n\t\t\t...suitePreferenceDiagnostics,\n\t\t]),\n\t\t...(suiteAssembly.pluginProfile === undefined ? {} : { pluginProfile: suiteAssembly.pluginProfile }),\n\t\tresolvedAgentProfile,\n\t};\n}\n\n/**\n * Result from createStableAgentSession (B-S2b③-S2).\n *\n * The stable root philosophy: new consumers program against the facade and\n * the SessionAPI projection, never against the bare AgentSession — the raw\n * session stays an internal adapter behind the stable surface, so no `session`\n * field is exposed here.\n */\nexport interface CreateStableAgentSessionResult {\n\t/** Stable session facade v1 over the created session (D-043 stable root runtime center). */\n\tfacade: CodingAgentFacadeV1;\n\t/** Public session mechanism projection (`AgentSession.getSessionAPI()`), the stable read/write face for host adapters and embedded consumers. */\n\tsessionAPI: SessionAPI;\n\t/**\n\t * Create-time model fallback diagnostic, mirroring\n\t * `CreateAgentSessionResult.modelFallbackMessage`: set when the session could\n\t * not be created with the model that was restored from persisted state (or\n\t * when no model at all was available) and the normal resolution ran instead.\n\t * `undefined` when no fallback happened. It describes the create step, not\n\t * the session, which is why it rides the create result instead of a facade\n\t * member (D-061).\n\t */\n\tmodelFallbackMessage?: string;\n}\n\n/**\n * Create a stable agent session: the same assembly as createAgentSession\n * (zero behavior difference), returned as the stable facade pair instead of\n * the raw session (B-S2b③-S2).\n *\n * @example\n * ```typescript\n * const { facade, sessionAPI } = await createStableAgentSession({\n * streamFn: mockStreamFn,\n * sessionManager: SessionManager.inMemory(),\n * });\n * await facade.prompt(\"hello\");\n * console.log(sessionAPI.getSessionId());\n * ```\n */\nexport async function createStableAgentSession(\n\toptions: CreateAgentSessionOptions = {},\n): Promise<CreateStableAgentSessionResult> {\n\tconst result = await createAgentSession(options);\n\treturn {\n\t\tfacade: createCodingAgentFacade(result.session),\n\t\tsessionAPI: result.session.getSessionAPI(),\n\t\t// Pure passthrough of the legacy result's create-time diagnostic (D-061):\n\t\t// same value, same assembly, no behavior change.\n\t\tmodelFallbackMessage: result.modelFallbackMessage,\n\t};\n}\n\n/**\n * Result from createStableAgentSessionRuntime (D-063).\n *\n * The stable root philosophy: a consumer that orchestrates session replacement\n * programs against the runtime facade, never against the bare\n * `AgentSessionRuntime`/`AgentSession` — both stay internal adapters behind the\n * stable surface, so no `runtime`/`session` field is exposed here. The current\n * session's v1 face is reachable through\n * `runtimeFacade.getSessionFacade()`.\n */\nexport interface CreateStableAgentSessionRuntimeResult {\n\t/** Stable runtime facade v1 over the created runtime (阶段 4 slice 3 runtime 面, §3.5). */\n\truntimeFacade: CodingAgentRuntimeFacadeV1;\n}\n\n/**\n * Create a stable agent session runtime: the same assembly as\n * createAgentSessionRuntime (zero behavior difference), returned as the stable\n * runtime facade instead of the raw runtime (D-063, 阶段 4 close-out).\n *\n * @example\n * ```typescript\n * const { runtimeFacade } = await createStableAgentSessionRuntime(createRuntime, {\n * cwd: process.cwd(),\n * agentDir: getAgentDir(),\n * sessionManager: SessionManager.create(process.cwd()),\n * });\n * await runtimeFacade.newSession();\n * // Re-read after a replacement: the accessor projects the current session.\n * const facade = runtimeFacade.getSessionFacade();\n * await facade.prompt(\"hello\");\n * ```\n */\nexport async function createStableAgentSessionRuntime(\n\tcreateRuntime: CreateAgentSessionRuntimeFactory,\n\toptions: {\n\t\tcwd: string;\n\t\tagentDir: string;\n\t\tsessionManager: SessionManager;\n\t\tsessionStartEvent?: SessionStartMetadata;\n\t},\n): Promise<CreateStableAgentSessionRuntimeResult> {\n\tconst runtime = await createAgentSessionRuntime(createRuntime, options);\n\treturn { runtimeFacade: createCodingAgentRuntimeFacade(runtime) };\n}\n"]}
package/dist/core/sdk.js CHANGED
@@ -7,11 +7,10 @@ import { clampThinkingLevel, streamSimple, } from "@agent-forge/ai/compat";
7
7
  import { createSubagentMailbox } from "@agent-forge/protocol/subagent";
8
8
  import { satisfies } from "semver";
9
9
  import { BUILTIN_CAPABILITY_PACKAGE_IDS } from "../capabilities/builtin.js";
10
- import { isValidThinkingLevel } from "../cli/args.js";
11
10
  import { CONFIG_DIR_NAME, getAgentDir, VERSION } from "../config.js";
12
11
  import { profileIdentitiesCompatible } from "../profile/identity.js";
13
- import { buildResolvedAgentProfileV1 } from "../profiles/resolved-agent-profile.js";
14
- import { createSuiteAssembly, decideSuiteCapabilityPlugin, filterSuiteSkills, readSessionSuiteBinding, resolveSuiteId, SUITE_ENV_VAR, SUITE_SESSION_ENTRY_TYPE, SuiteRebindError, suiteDanglingPluginAssociations, } from "../profiles/suite-loader.js";
12
+ import { buildResolvedAgentProfileV1 } from "../suites/resolved-agent-profile.js";
13
+ import { createSuiteAssembly, decideSuiteCapabilityPlugin, filterSuiteSkills, readSessionSuiteBinding, resolveSuiteId, SUITE_ENV_VAR, SUITE_SESSION_ENTRY_TYPE, SuiteRebindError, suiteDanglingPluginAssociations, } from "../suites/suite-loader.js";
15
14
  import { resolvePath } from "../utils/paths.js";
16
15
  import { AgentSession } from "./agent-session.js";
17
16
  import { createAgentSessionRuntime } from "./agent-session-runtime.js";
@@ -25,7 +24,7 @@ import { createCodingAgentFacade } from "./facade/coding-agent-facade.js";
25
24
  import { createCodingAgentRuntimeFacade, } from "./facade/coding-agent-runtime-facade.js";
26
25
  import { t } from "./i18n/index.js";
27
26
  import { convertToLlm } from "./messages.js";
28
- import { findExactModelReferenceMatch, findInitialModel } from "./model-resolver.js";
27
+ import { findExactModelReferenceMatch, findInitialModel, isValidThinkingLevel } from "./model-resolver.js";
29
28
  import { ModelRuntime } from "./model-runtime.js";
30
29
  import { DefaultResourceLoader } from "./resource-loader.js";
31
30
  import { getDefaultSessionDir, getTraceFilePathForSession, SessionManager } from "./session-manager.js";
@@ -278,7 +277,7 @@ function resolveSdkMemoryMode(explicitMode, env, settingsMode) {
278
277
  return { mode: legacy };
279
278
  return { mode: "off", invalidEnvValue: legacy };
280
279
  }
281
- return { mode: "off" };
280
+ return { mode: "light" };
282
281
  }
283
282
  /**
284
283
  * 子代理 headless 交互宿主(D-044 §5.5):child 会话无宿主 UI,interaction 请求
@@ -428,8 +427,8 @@ export async function createAgentSession(options = {}) {
428
427
  };
429
428
  // 记忆档位解析(2.4d6 S1;D-075 S4 第四批):SDK 显式选项最优先,settings.json
430
429
  // 档位作为 env 之下的持久来源进入解析链(显式 > env > settings > 旧别名 env >
431
- // off);两者皆缺省时同样走 env/别名/off 解析(off = memory 插件包不装配)。
432
- // 门控诊断与成员资格判定在下方 capabilityWiring 块产出。
430
+ // light,2026-10-05 翻转默认);两者皆缺省时同样走 env/别名/light 解析
431
+ // (off = memory 插件包不装配)。门控诊断与成员资格判定在下方 capabilityWiring 块产出。
433
432
  const settingsMemoryMode = settingsManager.getMemoryModeSetting();
434
433
  const memoryModeOption = options.memoryCapability?.mode;
435
434
  const memoryModeResolution = resolveSdkMemoryMode(memoryModeOption, process.env, settingsMemoryMode);