@armadra/agent 0.4.0 → 0.5.0

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 (422) hide show
  1. package/CHANGELOG.md +174 -1
  2. package/README.md +201 -82
  3. package/THIRD_PARTY_NOTICES.md +34 -0
  4. package/dist/acp.d.ts +18 -0
  5. package/dist/acp.js +19 -0
  6. package/dist/agent/limits.d.ts +38 -0
  7. package/dist/agent/limits.js +127 -0
  8. package/dist/agent/loop-guard.d.ts +38 -0
  9. package/dist/agent/loop-guard.js +95 -0
  10. package/dist/agent/loop.d.ts +4 -0
  11. package/dist/agent/loop.js +7 -0
  12. package/dist/agent/prompt-rules.d.ts +12 -0
  13. package/dist/agent/prompt-rules.js +18 -0
  14. package/dist/agent/reminders.d.ts +59 -0
  15. package/dist/agent/reminders.js +327 -0
  16. package/dist/agent/session-cache.d.ts +5 -0
  17. package/dist/agent/session-cache.js +17 -1
  18. package/dist/agent/session-classifier.d.ts +1 -1
  19. package/dist/agent/session-classifier.js +3 -1
  20. package/dist/agent/session-compaction.d.ts +35 -6
  21. package/dist/agent/session-compaction.js +157 -31
  22. package/dist/agent/session-core.d.ts +27 -1
  23. package/dist/agent/session-extensions.d.ts +61 -0
  24. package/dist/agent/session-extensions.js +129 -0
  25. package/dist/agent/session-images.d.ts +23 -0
  26. package/dist/agent/session-images.js +97 -0
  27. package/dist/agent/session-plan.d.ts +21 -0
  28. package/dist/agent/session-plan.js +524 -0
  29. package/dist/agent/session-rewind.d.ts +81 -0
  30. package/dist/agent/session-rewind.js +354 -0
  31. package/dist/agent/session-run.d.ts +28 -1
  32. package/dist/agent/session-run.js +157 -6
  33. package/dist/agent/session-settings.d.ts +49 -0
  34. package/dist/agent/session-settings.js +95 -0
  35. package/dist/agent/session-subagent.d.ts +36 -24
  36. package/dist/agent/session-subagent.js +259 -129
  37. package/dist/agent/session-sync.d.ts +10 -3
  38. package/dist/agent/session-sync.js +37 -8
  39. package/dist/agent/session-telemetry.d.ts +39 -0
  40. package/dist/agent/session-telemetry.js +231 -0
  41. package/dist/agent/session-tools.js +40 -1
  42. package/dist/agent/session.d.ts +30 -29
  43. package/dist/agent/session.js +79 -123
  44. package/dist/agent/subagent-registry.d.ts +91 -0
  45. package/dist/agent/subagent-registry.js +494 -0
  46. package/dist/agent/system-prompt.d.ts +6 -3
  47. package/dist/agent/system-prompt.js +7 -2
  48. package/dist/agent/tool-runner.d.ts +8 -1
  49. package/dist/agent/tool-runner.js +57 -4
  50. package/dist/agent/types-w5.d.ts +192 -0
  51. package/dist/agent/types-w5.js +10 -0
  52. package/dist/agent/types.d.ts +47 -4
  53. package/dist/agent/types.js +2 -0
  54. package/dist/agent/worktree.d.ts +36 -0
  55. package/dist/agent/worktree.js +86 -0
  56. package/dist/agents/builtin.d.ts +14 -0
  57. package/dist/agents/builtin.js +39 -0
  58. package/dist/agents/catalog.d.ts +43 -0
  59. package/dist/agents/catalog.js +82 -0
  60. package/dist/agents/discover.d.ts +35 -0
  61. package/dist/agents/discover.js +83 -0
  62. package/dist/agents/external.d.ts +82 -0
  63. package/dist/agents/external.js +326 -0
  64. package/dist/agents/parse.d.ts +18 -0
  65. package/dist/agents/parse.js +116 -0
  66. package/dist/agents/result.d.ts +32 -0
  67. package/dist/agents/result.js +67 -0
  68. package/dist/agents/task-control.d.ts +17 -0
  69. package/dist/agents/task-control.js +17 -0
  70. package/dist/agents/task-record.d.ts +78 -0
  71. package/dist/agents/task-record.js +141 -0
  72. package/dist/agents/types.d.ts +46 -0
  73. package/dist/agents/types.js +8 -0
  74. package/dist/ai/apis/anthropic-compat.d.ts +36 -0
  75. package/dist/ai/apis/anthropic-compat.js +92 -0
  76. package/dist/ai/apis/anthropic-request.d.ts +7 -6
  77. package/dist/ai/apis/anthropic-request.js +10 -28
  78. package/dist/ai/apis/cache-params.d.ts +11 -2
  79. package/dist/ai/apis/cache-params.js +25 -6
  80. package/dist/ai/apis/openai-compat.d.ts +4 -1
  81. package/dist/ai/apis/openai-compat.js +8 -1
  82. package/dist/ai/image-limits.d.ts +45 -0
  83. package/dist/ai/image-limits.js +68 -0
  84. package/dist/ai/providers/builtin.d.ts +18 -6
  85. package/dist/ai/providers/builtin.js +135 -6
  86. package/dist/ai/providers/catalog-data.js +17 -13
  87. package/dist/ai/providers/catalog.d.ts +60 -7
  88. package/dist/ai/providers/catalog.js +197 -38
  89. package/dist/ai/providers/channels.d.ts +33 -3
  90. package/dist/ai/providers/channels.js +108 -7
  91. package/dist/ai/providers/enrich.d.ts +6 -3
  92. package/dist/ai/providers/enrich.js +19 -4
  93. package/dist/ai/providers/models-dev-cache.d.ts +28 -24
  94. package/dist/ai/providers/models-dev-cache.js +92 -78
  95. package/dist/ai/providers/models-dev-data.d.ts +7 -0
  96. package/dist/ai/providers/models-dev-data.js +32 -0
  97. package/dist/ai/providers/models-dev-snapshot.d.ts +50 -0
  98. package/dist/ai/providers/models-dev-snapshot.js +137 -0
  99. package/dist/ai/providers/models-dev.d.ts +51 -10
  100. package/dist/ai/providers/models-dev.js +132 -39
  101. package/dist/ai/providers/registry.d.ts +20 -10
  102. package/dist/ai/providers/registry.js +82 -43
  103. package/dist/ai/types.d.ts +28 -2
  104. package/dist/ai/types.js +5 -0
  105. package/dist/bundle/ama.cjs +36203 -20499
  106. package/dist/checkpoints/backend.d.ts +61 -0
  107. package/dist/checkpoints/backend.js +135 -0
  108. package/dist/checkpoints/blobs.d.ts +60 -0
  109. package/dist/checkpoints/blobs.js +203 -0
  110. package/dist/checkpoints/gc.d.ts +47 -0
  111. package/dist/checkpoints/gc.js +144 -0
  112. package/dist/checkpoints/git-head.d.ts +15 -0
  113. package/dist/checkpoints/git-head.js +89 -0
  114. package/dist/checkpoints/index.d.ts +17 -0
  115. package/dist/checkpoints/index.js +17 -0
  116. package/dist/checkpoints/replay.d.ts +48 -0
  117. package/dist/checkpoints/replay.js +154 -0
  118. package/dist/checkpoints/restore.d.ts +86 -0
  119. package/dist/checkpoints/restore.js +263 -0
  120. package/dist/checkpoints/settings.d.ts +14 -0
  121. package/dist/checkpoints/settings.js +23 -0
  122. package/dist/checkpoints/shadow-git.d.ts +108 -0
  123. package/dist/checkpoints/shadow-git.js +491 -0
  124. package/dist/checkpoints/shadow-restore.d.ts +25 -0
  125. package/dist/checkpoints/shadow-restore.js +128 -0
  126. package/dist/checkpoints/tracker.d.ts +64 -0
  127. package/dist/checkpoints/tracker.js +192 -0
  128. package/dist/checkpoints/types.d.ts +99 -0
  129. package/dist/checkpoints/types.js +12 -0
  130. package/dist/cli/args.d.ts +8 -4
  131. package/dist/cli/args.js +17 -97
  132. package/dist/cli/bootstrap.js +13 -1
  133. package/dist/cli/codemode-notice.d.ts +3 -2
  134. package/dist/cli/codemode-notice.js +3 -2
  135. package/dist/cli/compose-agents.d.ts +27 -0
  136. package/dist/cli/compose-agents.js +111 -0
  137. package/dist/cli/compose-extensions.d.ts +29 -0
  138. package/dist/cli/compose-extensions.js +44 -0
  139. package/dist/cli/compose-session.d.ts +3 -0
  140. package/dist/cli/compose-session.js +47 -4
  141. package/dist/cli/compose.d.ts +3 -0
  142. package/dist/cli/compose.js +33 -6
  143. package/dist/cli/deps.d.ts +6 -0
  144. package/dist/cli/exit-codes.d.ts +10 -0
  145. package/dist/cli/exit-codes.js +12 -0
  146. package/dist/cli/help-text.d.ts +4 -0
  147. package/dist/cli/help-text.js +102 -0
  148. package/dist/cli/startup-screen.js +5 -3
  149. package/dist/cli/startup-steps.js +7 -1
  150. package/dist/cli/subcommands/config.d.ts +4 -1
  151. package/dist/cli/subcommands/config.js +17 -6
  152. package/dist/cli/subcommands/doctor.js +21 -0
  153. package/dist/cli/subcommands/models-discover.js +5 -6
  154. package/dist/cli/subcommands/models.d.ts +2 -0
  155. package/dist/cli/subcommands/models.js +33 -14
  156. package/dist/cli/subcommands/providers.js +5 -6
  157. package/dist/cli/subcommands/sessions.d.ts +3 -1
  158. package/dist/cli/subcommands/sessions.js +36 -2
  159. package/dist/codemode/capability.d.ts +24 -7
  160. package/dist/codemode/capability.js +38 -10
  161. package/dist/codemode/host-side.d.ts +14 -0
  162. package/dist/codemode/host-side.js +24 -1
  163. package/dist/codemode/tool.d.ts +1 -1
  164. package/dist/codemode/tool.js +6 -4
  165. package/dist/compaction/breaker.d.ts +25 -9
  166. package/dist/compaction/breaker.js +47 -17
  167. package/dist/compaction/estimate.d.ts +11 -3
  168. package/dist/compaction/estimate.js +64 -22
  169. package/dist/compaction/image-budget.d.ts +45 -0
  170. package/dist/compaction/image-budget.js +115 -0
  171. package/dist/compaction/post-compact.d.ts +38 -0
  172. package/dist/compaction/post-compact.js +152 -0
  173. package/dist/compaction/protect.d.ts +27 -0
  174. package/dist/compaction/protect.js +56 -0
  175. package/dist/compaction/prune-tier.d.ts +58 -12
  176. package/dist/compaction/prune-tier.js +120 -54
  177. package/dist/compaction/summarize-tier.d.ts +23 -4
  178. package/dist/compaction/summarize-tier.js +100 -29
  179. package/dist/config/checker.d.ts +28 -0
  180. package/dist/config/checker.js +97 -0
  181. package/dist/config/json-schema.js +63 -2
  182. package/dist/config/key-docs.js +72 -3
  183. package/dist/config/merge.d.ts +5 -3
  184. package/dist/config/merge.js +81 -7
  185. package/dist/config/profile.d.ts +2 -0
  186. package/dist/config/profile.js +2 -0
  187. package/dist/config/schema-w5.d.ts +18 -0
  188. package/dist/config/schema-w5.js +109 -0
  189. package/dist/config/schema.d.ts +5 -9
  190. package/dist/config/schema.js +68 -114
  191. package/dist/config/types-w5.d.ts +118 -0
  192. package/dist/config/types-w5.js +20 -0
  193. package/dist/config/types.d.ts +50 -1
  194. package/dist/config/types.js +12 -0
  195. package/dist/drivers/acp/client.d.ts +57 -0
  196. package/dist/drivers/acp/client.js +160 -0
  197. package/dist/drivers/acp/driver.d.ts +31 -0
  198. package/dist/drivers/acp/driver.js +274 -0
  199. package/dist/drivers/acp/testing/fake-agent-main.d.ts +5 -0
  200. package/dist/drivers/acp/testing/fake-agent-main.js +7 -0
  201. package/dist/drivers/acp/testing/fake-agent.d.ts +27 -0
  202. package/dist/drivers/acp/testing/fake-agent.js +211 -0
  203. package/dist/drivers/acp/types.d.ts +285 -0
  204. package/dist/drivers/acp/types.js +36 -0
  205. package/dist/drivers/agents.d.ts +58 -0
  206. package/dist/drivers/agents.js +142 -0
  207. package/dist/drivers/base.d.ts +35 -0
  208. package/dist/drivers/base.js +59 -0
  209. package/dist/drivers/catalog.d.ts +46 -0
  210. package/dist/drivers/catalog.js +167 -0
  211. package/dist/drivers/env.d.ts +20 -0
  212. package/dist/drivers/env.js +46 -0
  213. package/dist/drivers/host-runners.d.ts +18 -0
  214. package/dist/drivers/host-runners.js +45 -0
  215. package/dist/drivers/jsonrpc.d.ts +58 -0
  216. package/dist/drivers/jsonrpc.js +180 -0
  217. package/dist/drivers/native/claude-normalize.d.ts +46 -0
  218. package/dist/drivers/native/claude-normalize.js +106 -0
  219. package/dist/drivers/native/claude-stream.d.ts +29 -0
  220. package/dist/drivers/native/claude-stream.js +456 -0
  221. package/dist/drivers/native/codex-app-server.d.ts +26 -0
  222. package/dist/drivers/native/codex-app-server.js +407 -0
  223. package/dist/drivers/native/codex-normalize.d.ts +38 -0
  224. package/dist/drivers/native/codex-normalize.js +124 -0
  225. package/dist/drivers/native/oneshot.d.ts +28 -0
  226. package/dist/drivers/native/oneshot.js +312 -0
  227. package/dist/drivers/permissions.d.ts +40 -0
  228. package/dist/drivers/permissions.js +92 -0
  229. package/dist/drivers/pids.d.ts +32 -0
  230. package/dist/drivers/pids.js +93 -0
  231. package/dist/drivers/pool.d.ts +28 -0
  232. package/dist/drivers/pool.js +96 -0
  233. package/dist/drivers/probe.d.ts +47 -0
  234. package/dist/drivers/probe.js +172 -0
  235. package/dist/drivers/process.d.ts +48 -0
  236. package/dist/drivers/process.js +100 -0
  237. package/dist/drivers/runner.d.ts +61 -0
  238. package/dist/drivers/runner.js +388 -0
  239. package/dist/drivers/store.d.ts +49 -0
  240. package/dist/drivers/store.js +91 -0
  241. package/dist/drivers/turn.d.ts +41 -0
  242. package/dist/drivers/turn.js +99 -0
  243. package/dist/drivers/types.d.ts +122 -0
  244. package/dist/drivers/types.js +11 -0
  245. package/dist/git/info.d.ts +75 -0
  246. package/dist/git/info.js +191 -0
  247. package/dist/hooks/protocol.js +6 -1
  248. package/dist/hooks/types.d.ts +10 -1
  249. package/dist/hooks/types.js +2 -0
  250. package/dist/host/api-impl.d.ts +7 -0
  251. package/dist/host/api-impl.js +15 -0
  252. package/dist/host/types.d.ts +24 -2
  253. package/dist/host/types.js +4 -0
  254. package/dist/index.d.ts +3 -0
  255. package/dist/index.js +1 -0
  256. package/dist/modes/acp/acp-events.d.ts +46 -0
  257. package/dist/modes/acp/acp-events.js +233 -0
  258. package/dist/modes/acp/acp-mode.d.ts +17 -0
  259. package/dist/modes/acp/acp-mode.js +47 -0
  260. package/dist/modes/acp/acp-server.d.ts +79 -0
  261. package/dist/modes/acp/acp-server.js +315 -0
  262. package/dist/modes/commands-core.d.ts +7 -1
  263. package/dist/modes/commands-core.js +55 -0
  264. package/dist/modes/image-input.d.ts +12 -4
  265. package/dist/modes/image-input.js +22 -5
  266. package/dist/modes/interactive/agent-panels.d.ts +14 -0
  267. package/dist/modes/interactive/agent-panels.js +103 -0
  268. package/dist/modes/interactive/agent-ui.d.ts +73 -0
  269. package/dist/modes/interactive/agent-ui.js +234 -0
  270. package/dist/modes/interactive/approval-dialog.d.ts +21 -4
  271. package/dist/modes/interactive/approval-dialog.js +98 -20
  272. package/dist/modes/interactive/approval-merge.d.ts +41 -0
  273. package/dist/modes/interactive/approval-merge.js +89 -0
  274. package/dist/modes/interactive/clipboard-paste.d.ts +18 -0
  275. package/dist/modes/interactive/clipboard-paste.js +28 -0
  276. package/dist/modes/interactive/commands.d.ts +9 -1
  277. package/dist/modes/interactive/commands.js +19 -0
  278. package/dist/modes/interactive/double-esc.d.ts +20 -0
  279. package/dist/modes/interactive/double-esc.js +34 -0
  280. package/dist/modes/interactive/event-notices.d.ts +32 -0
  281. package/dist/modes/interactive/event-notices.js +79 -0
  282. package/dist/modes/interactive/external-editor.d.ts +16 -0
  283. package/dist/modes/interactive/external-editor.js +39 -0
  284. package/dist/modes/interactive/interactive-mode.d.ts +14 -1
  285. package/dist/modes/interactive/interactive-mode.js +134 -136
  286. package/dist/modes/interactive/key-dispatch.d.ts +16 -2
  287. package/dist/modes/interactive/key-dispatch.js +49 -1
  288. package/dist/modes/interactive/line/line-mode.d.ts +2 -1
  289. package/dist/modes/interactive/line/line-mode.js +22 -5
  290. package/dist/modes/interactive/line/line-render.d.ts +2 -1
  291. package/dist/modes/interactive/line/line-render.js +40 -4
  292. package/dist/modes/interactive/message-view.d.ts +1 -1
  293. package/dist/modes/interactive/message-view.js +24 -2
  294. package/dist/modes/interactive/panels.d.ts +18 -1
  295. package/dist/modes/interactive/panels.js +19 -5
  296. package/dist/modes/interactive/plan-command.d.ts +40 -0
  297. package/dist/modes/interactive/plan-command.js +129 -0
  298. package/dist/modes/interactive/plan-dialog.d.ts +98 -0
  299. package/dist/modes/interactive/plan-dialog.js +290 -0
  300. package/dist/modes/interactive/plan-flow.d.ts +34 -0
  301. package/dist/modes/interactive/plan-flow.js +98 -0
  302. package/dist/modes/interactive/rewind-command.d.ts +31 -0
  303. package/dist/modes/interactive/rewind-command.js +106 -0
  304. package/dist/modes/interactive/rewind-flow.d.ts +37 -0
  305. package/dist/modes/interactive/rewind-flow.js +151 -0
  306. package/dist/modes/interactive/rewind-list.d.ts +36 -0
  307. package/dist/modes/interactive/rewind-list.js +123 -0
  308. package/dist/modes/interactive/rewind-panel.d.ts +77 -0
  309. package/dist/modes/interactive/rewind-panel.js +309 -0
  310. package/dist/modes/interactive/rewind-text.d.ts +40 -0
  311. package/dist/modes/interactive/rewind-text.js +139 -0
  312. package/dist/modes/interactive/session-events.d.ts +24 -0
  313. package/dist/modes/interactive/session-events.js +96 -0
  314. package/dist/modes/interactive/status-area.d.ts +73 -0
  315. package/dist/modes/interactive/status-area.js +190 -0
  316. package/dist/modes/interactive/status-bar.d.ts +99 -11
  317. package/dist/modes/interactive/status-bar.js +273 -90
  318. package/dist/modes/interactive/status-line.d.ts +33 -0
  319. package/dist/modes/interactive/status-line.js +113 -0
  320. package/dist/modes/interactive/subagent-view.d.ts +56 -0
  321. package/dist/modes/interactive/subagent-view.js +154 -0
  322. package/dist/modes/interactive/tasks-report.d.ts +27 -0
  323. package/dist/modes/interactive/tasks-report.js +114 -0
  324. package/dist/modes/interactive/tool-view.d.ts +12 -2
  325. package/dist/modes/interactive/tool-view.js +34 -4
  326. package/dist/modes/print/print-mode.d.ts +13 -4
  327. package/dist/modes/print/print-mode.js +56 -12
  328. package/dist/modes/rpc/commands.d.ts +9 -0
  329. package/dist/modes/rpc/commands.js +44 -0
  330. package/dist/modes/rpc/rpc-mode.js +7 -1
  331. package/dist/modes/session-report.d.ts +11 -0
  332. package/dist/modes/session-report.js +48 -1
  333. package/dist/permissions/auto-safe.d.ts +5 -0
  334. package/dist/permissions/auto-safe.js +18 -0
  335. package/dist/permissions/classifier.d.ts +4 -0
  336. package/dist/permissions/classifier.js +2 -0
  337. package/dist/permissions/modes.js +1 -1
  338. package/dist/permissions/pipeline.d.ts +43 -4
  339. package/dist/permissions/pipeline.js +114 -9
  340. package/dist/permissions/readonly-bash.d.ts +30 -0
  341. package/dist/permissions/readonly-bash.js +118 -0
  342. package/dist/permissions/types.d.ts +42 -0
  343. package/dist/plan/compose.d.ts +9 -0
  344. package/dist/plan/compose.js +19 -0
  345. package/dist/plan/controller.d.ts +71 -0
  346. package/dist/plan/controller.js +27 -0
  347. package/dist/plan/done-markers.d.ts +17 -0
  348. package/dist/plan/done-markers.js +51 -0
  349. package/dist/plan/extract.d.ts +29 -0
  350. package/dist/plan/extract.js +160 -0
  351. package/dist/plan/prompts.d.ts +36 -0
  352. package/dist/plan/prompts.js +89 -0
  353. package/dist/plan/store.d.ts +37 -0
  354. package/dist/plan/store.js +90 -0
  355. package/dist/rpc.d.ts +58 -2
  356. package/dist/rpc.js +7 -0
  357. package/dist/sandbox/bash.d.ts +74 -0
  358. package/dist/sandbox/bash.js +126 -0
  359. package/dist/sandbox/detect.d.ts +48 -0
  360. package/dist/sandbox/detect.js +149 -0
  361. package/dist/sandbox/index.d.ts +5 -0
  362. package/dist/sandbox/index.js +5 -0
  363. package/dist/sandbox/profile.d.ts +33 -0
  364. package/dist/sandbox/profile.js +76 -0
  365. package/dist/sandbox/wrap.d.ts +29 -0
  366. package/dist/sandbox/wrap.js +117 -0
  367. package/dist/sdk.d.ts +33 -2
  368. package/dist/sdk.js +24 -2
  369. package/dist/session/types.d.ts +3 -1
  370. package/dist/session/types.js +1 -0
  371. package/dist/skills/builtin.d.ts +31 -0
  372. package/dist/skills/builtin.js +109 -0
  373. package/dist/skills/discover.d.ts +2 -1
  374. package/dist/skills/index-prompt.js +5 -8
  375. package/dist/tools/background-jobs.d.ts +71 -0
  376. package/dist/tools/background-jobs.js +198 -0
  377. package/dist/tools/bash.d.ts +53 -1
  378. package/dist/tools/bash.js +158 -7
  379. package/dist/tools/clipboard-image.d.ts +44 -0
  380. package/dist/tools/clipboard-image.js +148 -0
  381. package/dist/tools/edit.d.ts +2 -0
  382. package/dist/tools/edit.js +18 -3
  383. package/dist/tools/image-file.d.ts +38 -3
  384. package/dist/tools/image-file.js +81 -10
  385. package/dist/tools/image-resize.d.ts +58 -0
  386. package/dist/tools/image-resize.js +97 -0
  387. package/dist/tools/presets.d.ts +7 -2
  388. package/dist/tools/presets.js +11 -4
  389. package/dist/tools/read.d.ts +5 -2
  390. package/dist/tools/read.js +13 -10
  391. package/dist/tools/registry.d.ts +7 -1
  392. package/dist/tools/registry.js +27 -4
  393. package/dist/tools/task-ctl.d.ts +22 -0
  394. package/dist/tools/task-ctl.js +116 -0
  395. package/dist/tools/task.d.ts +22 -10
  396. package/dist/tools/task.js +66 -26
  397. package/dist/tools/todo.d.ts +22 -2
  398. package/dist/tools/todo.js +58 -14
  399. package/dist/tools/truncate.d.ts +15 -0
  400. package/dist/tools/truncate.js +25 -0
  401. package/dist/tools/types.d.ts +113 -0
  402. package/dist/tools/types.js +5 -0
  403. package/dist/tools/write.js +3 -0
  404. package/dist/tui/glyphs.d.ts +4 -0
  405. package/dist/tui/glyphs.js +4 -0
  406. package/dist/tui/keybindings.d.ts +5 -0
  407. package/dist/tui/keybindings.js +5 -0
  408. package/docs/acp.md +78 -0
  409. package/docs/agents.md +250 -0
  410. package/docs/codemode.md +12 -8
  411. package/docs/hooks.md +26 -22
  412. package/docs/permissions.md +77 -13
  413. package/docs/plan.md +107 -0
  414. package/docs/providers.md +228 -52
  415. package/docs/rewind-plan.md +181 -0
  416. package/docs/rpc.md +92 -5
  417. package/docs/sandbox.md +215 -0
  418. package/docs/session-format.md +41 -21
  419. package/docs/sessions.md +41 -1
  420. package/docs/tui-design.md +751 -0
  421. package/docs/tui.md +125 -6
  422. package/package.json +13 -2
@@ -1,157 +1,287 @@
1
1
  /**
2
- * 子 Agent(设计 §5.2 task、D14):`ToolContext.spawnSubagent` 的实现,供 B3 的 task 工具调用。[B2]
2
+ * 子 Agent(设计 §5.2 task、D14;第五波 docs/wave5-plan.md §7,D22–D24):`ToolContext.spawnSubagent`
3
+ * 的实现与 ama 自己的 runner(`AmaRunner`)。[B2 → W5-G]
3
4
  *
4
- * - 同进程新会话:独立 JSONL(头的 parentSession 指回父文件;父为内存会话则子也在内存),首条
5
- * `custom{customType:"ama.task"}` 记父 toolCallId。
6
- * - 深度 ≤ 1(子会话 depth 1、无 spawnSubagent);并发 ≤ 4(排队等待)。
7
- * - 工具子集缺省 = 父的活动集,总是去掉 task;继承父的权限管线、Hook 与系统提示静态部分;
8
- * broker 包一层,请求带 `context{depth, parentToolCallId}`,审批事件转发到父会话。
9
- * - 父 abort 级联;结果 = 子的最后助手文本 + 用量 + 子会话文件。
10
- * - [W3-C1b] 子会话有自己的缓存控制器(统计独立、未命中不进父链,`warmSubagents` 为 false 时
11
- * 不保温);结果带 `cache{hitRate, reBilledTokens}`,并汇总进父会话的「子任务」统计。
5
+ * - `runSubagent`:交给会话的任务注册表(subagent-registry.ts)——类型解析、并发池、前台 / 后台、
6
+ * 续聊、结果上限、事件都在那里;这里只提供「起一个 ama 子会话」的 runner。
7
+ * - 子会话:同进程新会话,独立 JSONL(头的 parentSession 指回父文件;父为内存会话则子也在内存),
8
+ * 首条 `custom{ama.task}` 记父 toolCallId 与 taskId;深度 ≤ 1(depth 1、无 spawnSubagent)。
9
+ * - **工具表与父字节一致**(D23):活动集 = 父活动集,`task` / `task_ctl` 保留在表里、运行时按深度
10
+ * 拒绝,子会话首请求能命中父的 tools + system 前缀;角色说明进系统提示末位 `role` 节。只有类型
11
+ * 声明了 `tools` / `disallowed-tools`(或调用参数给了 `tools`)时工具表才不同。
12
+ * - 只读类型(`permission-mode: plan`):子会话用一条 plan 模式的权限管线(规则同父),ask 一律转
13
+ * deny——写类工具与识别不了的 bash 被拒且不弹审批;`inherit` 共用父的管线(不会比父宽)。
14
+ * - 轮数耗尽且最后停在工具结果上:以 `toolChoice:"none"` 再跑一轮要最终报告,状态 `max_turns`。
15
+ * - broker 包一层,请求带 `context{depth, parentToolCallId, taskId}`,审批事件转发到父会话;
16
+ * [RW-B] 父的检查点钩子(worktree 里运行时不记);[W3-C1b] 子会话命中与重计费汇总进父。
12
17
  */
13
18
  import { AmaError } from "../errors.js";
19
+ import { PermissionPipeline } from "../permissions/pipeline.js";
14
20
  import { SessionManager } from "../session/manager.js";
21
+ import { agentRole } from "../agents/builtin.js";
15
22
  import { ZERO_USAGE } from "./loop.js";
16
- export const DEFAULT_SUBAGENT_CONCURRENCY = 4;
23
+ import { DEFAULT_SUBAGENT_CONCURRENCY, SubagentPool, TASK_CUSTOM_TYPE, subagentRegistryFor, } from "./subagent-registry.js";
24
+ export { DEFAULT_SUBAGENT_CONCURRENCY, SubagentPool, TASK_CUSTOM_TYPE };
17
25
  export const DEFAULT_SUBAGENT_MAX_TURNS = 30;
18
- export const TASK_CUSTOM_TYPE = "ama.task";
19
- /** 计数信号量。 */
20
- export class SubagentPool {
21
- limit;
22
- running = 0;
23
- waiters = [];
24
- constructor(limit) {
25
- this.limit = limit;
26
- }
27
- async acquire(signal) {
28
- while (this.running >= this.limit) {
29
- if (signal.aborted)
30
- throw new AmaError("aborted", "aborted");
31
- await new Promise((resolve) => this.waiters.push(resolve));
32
- }
33
- this.running++;
34
- }
35
- release() {
36
- this.running--;
37
- this.waiters.shift()?.();
38
- }
39
- }
40
- /** 子会话的 broker:请求带上发起方上下文(对话框标 `[task]`),其余原样交给父链。 */
26
+ /** 子会话里保留在工具表、运行时拒绝的名字(深度 ≤ 1)。 */
27
+ export const PARENT_ONLY_TOOLS = ["task", "task_ctl"];
28
+ export const FINAL_REPORT_PROMPT = "You have reached the turn limit for this task. Do not call any tools. Reply now with your " +
29
+ "final report: what you did, key findings, and what is left unfinished.";
30
+ /** 子会话的 broker:请求带上发起方上下文(对话框标 `[task:<agent>]`),其余原样交给父链。 */
41
31
  function brokersForChild(brokers, context) {
42
32
  return (brokers ?? []).map((broker) => ({
43
33
  ask: (request, signal) => broker.ask({ ...request, context }, signal),
44
34
  }));
45
35
  }
36
+ /**
37
+ * 只读子会话的权限管线:plan 模式、规则同父;ask 一律转 deny(只读类型不弹审批)。
38
+ * 父管线不是 `PermissionPipeline`(宿主 / SDK 自带实现)时退化为「只放行 read 类」。
39
+ */
40
+ export function readOnlyPermission(parent, cwd) {
41
+ const base = parent instanceof PermissionPipeline ? parent : undefined;
42
+ const inner = new PermissionPipeline({
43
+ mode: "plan",
44
+ rules: parent?.rules ?? [],
45
+ cwd: base?.cwd ?? cwd,
46
+ ...(parent?.projectRoot === undefined ? {} : { projectRoot: parent.projectRoot }),
47
+ // 沿用父的 plan.bash(deny 更严时照样 deny;ask 由下面统一转 deny)
48
+ ...(base === undefined ? {} : { planBash: base.planBash }),
49
+ });
50
+ const denied = "Read-only sub-agent: this call is not allowed (it would modify files or run a non-read-only command).";
51
+ return {
52
+ get mode() {
53
+ return "plan";
54
+ },
55
+ setMode: () => undefined,
56
+ get rules() {
57
+ return inner.rules;
58
+ },
59
+ check: (input) => {
60
+ const verdict = inner.check(input);
61
+ return verdict.decision === "ask"
62
+ ? { ...verdict, decision: "deny", message: verdict.message ?? denied }
63
+ : verdict;
64
+ },
65
+ rememberForSession: () => undefined,
66
+ ...(parent?.projectRoot === undefined ? {} : { projectRoot: parent.projectRoot }),
67
+ };
68
+ }
46
69
  function failed(text) {
47
- return { text, usage: { ...ZERO_USAGE }, stopReason: "error", isError: true };
70
+ return { text, usage: { ...ZERO_USAGE }, stopReason: "error", isError: true, status: "failed" };
48
71
  }
49
- export async function runSubagent(parent, request, pool, createChild) {
72
+ export async function runSubagent(parent, request, _pool, createChild) {
50
73
  if (parent.depth > 0)
51
74
  return failed("subagents cannot spawn subagents");
52
- await pool.acquire(request.signal);
53
- try {
54
- const base = parent.childBase();
55
- let model = base.model;
56
- if (request.model !== undefined) {
57
- const lookup = parent.options.providers.findModel(request.model);
58
- if (!lookup.ok)
59
- return failed(`unknown model ${request.model}`);
60
- model = lookup.model;
61
- }
62
- const parentFile = parent.manager.file();
63
- const headerOptions = parentFile === undefined ? {} : { parentSession: parentFile };
64
- const dir = parent.manager.directory();
65
- const childManager = dir === undefined
66
- ? SessionManager.inMemory(parent.cwd, headerOptions)
67
- : SessionManager.create(dir, parent.cwd, headerOptions);
68
- childManager.append({
69
- type: "custom",
70
- customType: TASK_CUSTOM_TYPE,
71
- data: {
72
- parentToolCallId: request.parentToolCallId,
73
- description: request.description,
74
- parentSession: parentFile,
75
- },
76
- });
77
- const available = new Set((parent.options.tools ?? []).map((tool) => tool.name));
78
- const names = (request.tools ?? base.activeTools ?? [...available]).filter((name) => name !== "task" && available.has(name));
79
- const child = createChild({
80
- ...parent.options,
81
- ...base,
82
- sessionManager: childManager,
83
- model,
84
- thinkingLevel: request.thinkingLevel ?? base.thinkingLevel ?? "off",
85
- activeTools: names,
86
- brokers: brokersForChild(parent.options.brokers, {
87
- depth: parent.depth + 1,
88
- parentToolCallId: request.parentToolCallId,
89
- }),
75
+ const registry = subagentRegistryFor(parent);
76
+ return registry.run(request, (spec) => createAmaRunner(parent, spec, createChild));
77
+ }
78
+ /** 活动集:缺省 = 父活动集(含 task / task_ctl,工具表对齐);白名单 / 黑名单时按名过滤。 */
79
+ function childToolNames(parent, spec, base) {
80
+ const available = new Set((parent.options.tools ?? []).map((tool) => tool.name));
81
+ const all = [...(base ?? available)].filter((name) => available.has(name));
82
+ const allow = spec.request.tools ?? spec.agent.tools;
83
+ if (allow !== undefined)
84
+ return allow.filter((name) => available.has(name) && !PARENT_ONLY_TOOLS.includes(name));
85
+ const deny = spec.agent.disallowedTools;
86
+ if (deny !== undefined)
87
+ return all.filter((name) => !deny.includes(name) && !PARENT_ONLY_TOOLS.includes(name));
88
+ return all;
89
+ }
90
+ /** ama 自己的子会话 runner(同进程)。 */
91
+ export function createAmaRunner(parent, spec, createChild) {
92
+ return {
93
+ id: "ama",
94
+ start: (request) => startAmaChild(parent, spec, createChild, request),
95
+ };
96
+ }
97
+ function childManager(parent, spec) {
98
+ if (spec.resumeFile !== undefined)
99
+ return SessionManager.open(spec.resumeFile);
100
+ const parentFile = parent.manager.file();
101
+ const header = parentFile === undefined ? {} : { parentSession: parentFile };
102
+ const dir = parent.manager.directory();
103
+ const manager = dir === undefined
104
+ ? SessionManager.inMemory(spec.cwd, header)
105
+ : SessionManager.create(dir, spec.cwd, header);
106
+ manager.append({
107
+ type: "custom",
108
+ customType: TASK_CUSTOM_TYPE,
109
+ data: {
110
+ taskId: spec.taskId,
111
+ agent: spec.agent.name,
112
+ parentToolCallId: spec.request.parentToolCallId,
113
+ description: spec.request.description,
114
+ parentSession: parentFile,
115
+ },
116
+ });
117
+ // 立即落盘:subagent_start 带上子会话文件,续聊 / resume 靠它重开
118
+ if (dir !== undefined)
119
+ manager.flush();
120
+ return manager;
121
+ }
122
+ async function startAmaChild(parent, spec, createChild, run) {
123
+ const base = parent.childBase();
124
+ let model = base.model;
125
+ if (spec.modelRef !== undefined) {
126
+ const lookup = parent.options.providers.findModel(spec.modelRef);
127
+ if (!lookup.ok)
128
+ throw new AmaError("model_not_found", `unknown model ${spec.modelRef}`);
129
+ model = lookup.model;
130
+ }
131
+ const manager = childManager(parent, spec);
132
+ const checkpointHooks = spec.isolated ? undefined : parent.checkpointHooks?.();
133
+ let finalRound = false;
134
+ const finalRoundExtension = () => ({
135
+ id: "ama.subagent-final-round",
136
+ wrapStream: (stream) => (m, context, options) => stream(m, context, finalRound ? { ...options, toolChoice: "none" } : options),
137
+ });
138
+ const maxTurns = spec.request.maxTurns ?? spec.agent.maxTurns ?? DEFAULT_SUBAGENT_MAX_TURNS;
139
+ const options = {
140
+ ...parent.options,
141
+ ...base,
142
+ system: { ...base.system, role: agentRole(spec.agent) },
143
+ sessionManager: manager,
144
+ model,
145
+ thinkingLevel: spec.request.thinkingLevel ?? spec.agent.thinking ?? base.thinkingLevel ?? "off",
146
+ activeTools: childToolNames(parent, spec, base.activeTools),
147
+ brokers: brokersForChild(parent.options.brokers, {
90
148
  depth: parent.depth + 1,
91
- maxTurns: request.maxTurns ?? DEFAULT_SUBAGENT_MAX_TURNS,
92
- subagents: false,
93
- });
94
- const onAbort = () => void child.abort();
95
- request.signal.addEventListener("abort", onAbort, { once: true });
96
- const unsubscribe = child.subscribe((event) => {
97
- if (event.type === "tool_execution_start")
98
- request.onUpdate?.(`[task] ${event.toolName}`);
99
- else if (event.type === "permission_request" || event.type === "permission_resolved")
100
- parent.emit?.(event);
101
- });
149
+ parentToolCallId: spec.request.parentToolCallId,
150
+ taskId: spec.taskId,
151
+ }),
152
+ depth: parent.depth + 1,
153
+ maxTurns,
154
+ subagents: false,
155
+ extensions: [...(parent.options.extensions ?? []), finalRoundExtension],
156
+ };
157
+ delete options.checkpointHooks;
158
+ if (checkpointHooks !== undefined)
159
+ options.checkpointHooks = checkpointHooks;
160
+ if (spec.agent.permissionMode === "plan")
161
+ options.permission = readOnlyPermission(parent.options.permission, spec.cwd);
162
+ const child = createChild(options);
163
+ let turns = 0;
164
+ let toolUse = false;
165
+ const unsubscribe = child.subscribe((event) => {
166
+ if (event.type === "tool_execution_start" && event.parentToolCallId === undefined)
167
+ run.onEvent({ type: "tool", toolName: event.toolName, status: "started" });
168
+ else if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta")
169
+ run.onEvent({ type: "text", delta: event.assistantMessageEvent.delta });
170
+ else if (event.type === "turn_end") {
171
+ turns++;
172
+ toolUse = event.toolResults.length > 0;
173
+ const { input, output, cacheRead, cacheWrite, total } = child.getStats().tokens;
174
+ run.onEvent({
175
+ type: "usage",
176
+ usage: { input, output, cacheRead, cacheWrite, totalTokens: total },
177
+ });
178
+ run.onEvent({ type: "turn", turn: turns });
179
+ }
180
+ else if (event.type === "permission_request" || event.type === "permission_resolved")
181
+ parent.emit(event);
182
+ });
183
+ const onAbort = () => void child.abort();
184
+ run.signal.addEventListener("abort", onAbort, { once: true });
185
+ let billed = { cacheRead: 0, prompt: 0, reBilled: 0 };
186
+ const runOnce = async (prompt) => {
187
+ const startTurns = turns;
102
188
  let error;
103
189
  try {
104
- if (request.signal.aborted)
190
+ if (run.signal.aborted)
105
191
  throw new AmaError("aborted", "aborted");
106
- await child.prompt(request.prompt);
192
+ await child.prompt(prompt);
107
193
  }
108
194
  catch (caught) {
109
195
  error = caught instanceof Error ? caught.message : String(caught);
110
196
  }
111
- finally {
112
- request.signal.removeEventListener("abort", onAbort);
113
- unsubscribe();
197
+ const exhausted = error === undefined && !run.signal.aborted && turns - startTurns >= maxTurns && toolUse;
198
+ if (exhausted) {
199
+ finalRound = true;
200
+ options.maxTurns = 1;
201
+ try {
202
+ await child.prompt(FINAL_REPORT_PROMPT);
203
+ }
204
+ catch (caught) {
205
+ error = caught instanceof Error ? caught.message : String(caught);
206
+ }
207
+ finally {
208
+ finalRound = false;
209
+ options.maxTurns = maxTurns;
210
+ }
114
211
  }
115
- const stats = child.getStats();
116
- const last = child.manager
117
- .branch()
118
- .findLast((entry) => entry.type === "message" && entry.message.role === "assistant");
119
- const stopReason = error !== undefined
120
- ? "error"
121
- : last?.type === "message" && last.message.role === "assistant"
122
- ? last.message.stopReason
123
- : "stop";
124
- const result = {
125
- text: child.getLastAssistantText() ?? error ?? "",
126
- usage: {
127
- input: stats.tokens.input,
128
- output: stats.tokens.output,
129
- cacheRead: stats.tokens.cacheRead,
130
- cacheWrite: stats.tokens.cacheWrite,
131
- totalTokens: stats.tokens.total,
132
- },
133
- stopReason,
134
- isError: error !== undefined || stopReason === "error" || stopReason === "aborted",
135
- };
136
- const cache = stats.cache;
137
- if (cache !== undefined) {
138
- result.cache = { reBilledTokens: cache.reBilledTokens };
139
- if (cache.hitRate !== undefined)
140
- result.cache.hitRate = cache.hitRate;
141
- // 不报缓存的子会话不进命中率分母(同父会话口径)
142
- const reported = cache.reporting === "reported";
143
- const { input, cacheRead, cacheWrite } = stats.tokens;
144
- parent.cache?.addSubagent(reported
145
- ? { cacheRead, prompt: input + cacheRead + cacheWrite }
146
- : { cacheRead: 0, prompt: 0 }, cache.reBilledTokens);
147
- }
148
- const childFile = childManager.file();
149
- if (childFile !== undefined)
150
- result.sessionFile = childFile;
151
- await child.dispose();
212
+ const result = collect(child, error, exhausted, run.signal.aborted);
213
+ billed = addCache(parent, child.getStats(), billed);
214
+ const file = manager.file();
215
+ if (file !== undefined)
216
+ result.sessionFile = file;
152
217
  return result;
218
+ };
219
+ let current = runOnce(run.prompt);
220
+ const handle = {
221
+ id: manager.id,
222
+ model: `${model.provider}/${model.id}`,
223
+ ...(manager.file() === undefined ? {} : { sessionFile: manager.file() }),
224
+ send: async (text) => {
225
+ current = runOnce(text);
226
+ },
227
+ wait: () => current,
228
+ stop: () => child.abort(),
229
+ dispose: async () => {
230
+ run.signal.removeEventListener("abort", onAbort);
231
+ unsubscribe();
232
+ await child.dispose();
233
+ },
234
+ };
235
+ return handle;
236
+ }
237
+ function collect(child, error, exhausted, aborted) {
238
+ const stats = child.getStats();
239
+ const last = child.manager
240
+ .branch()
241
+ .findLast((entry) => entry.type === "message" && entry.message.role === "assistant");
242
+ const stopReason = error !== undefined
243
+ ? "error"
244
+ : last?.type === "message" && last.message.role === "assistant"
245
+ ? last.message.stopReason
246
+ : "stop";
247
+ const isError = error !== undefined || stopReason === "error" || stopReason === "aborted";
248
+ const result = {
249
+ text: child.getLastAssistantText() ?? error ?? "",
250
+ usage: {
251
+ input: stats.tokens.input,
252
+ output: stats.tokens.output,
253
+ cacheRead: stats.tokens.cacheRead,
254
+ cacheWrite: stats.tokens.cacheWrite,
255
+ totalTokens: stats.tokens.total,
256
+ },
257
+ stopReason,
258
+ isError,
259
+ status: aborted || stopReason === "aborted"
260
+ ? "aborted"
261
+ : isError
262
+ ? "failed"
263
+ : exhausted
264
+ ? "max_turns"
265
+ : "completed",
266
+ };
267
+ if (stats.cache !== undefined) {
268
+ result.cache = { reBilledTokens: stats.cache.reBilledTokens };
269
+ if (stats.cache.hitRate !== undefined)
270
+ result.cache.hitRate = stats.cache.hitRate;
153
271
  }
154
- finally {
155
- pool.release();
156
- }
272
+ return result;
273
+ }
274
+ /** 子会话命中与重计费按增量汇总进父(续聊不重复计)。 */
275
+ function addCache(parent, stats, before) {
276
+ const cache = stats.cache;
277
+ if (cache === undefined)
278
+ return before;
279
+ // 不报缓存的子会话不进命中率分母(同父会话口径)
280
+ const reported = cache.reporting === "reported";
281
+ const { input, cacheRead, cacheWrite } = stats.tokens;
282
+ const now = reported
283
+ ? { cacheRead, prompt: input + cacheRead + cacheWrite, reBilled: cache.reBilledTokens }
284
+ : { cacheRead: 0, prompt: 0, reBilled: cache.reBilledTokens };
285
+ parent.cache?.addSubagent({ cacheRead: now.cacheRead - before.cacheRead, prompt: now.prompt - before.prompt }, now.reBilled - before.reBilled);
286
+ return now;
157
287
  }
@@ -8,13 +8,20 @@
8
8
  * - `runHookWithEvents`:调 HookDispatcher(公共字段按本会话的 depth / sessionId / sessionFile 覆盖),
9
9
  * 逐条发 hook_executed;Hook 自身出错记 warning、按无决策处理。
10
10
  */
11
- import type { Model, ModelThinkingLevel } from "../ai/types.js";
11
+ import type { Model, ModelRef, ModelThinkingLevel, ProviderRegistryApi } from "../ai/types.js";
12
12
  import type { HookEvent, HookEventPayload, HookOutcome } from "../hooks/types.js";
13
- import type { AgentMessage } from "../session/types.js";
13
+ import type { AgentMessage, SessionEntry } from "../session/types.js";
14
14
  import type { ToolDefinition } from "../tools/types.js";
15
+ import type { SessionManager } from "../session/manager.js";
15
16
  import type { SessionCore } from "./session-core.js";
17
+ import type { SessionEvent } from "./types.js";
16
18
  import { type SystemPromptInput } from "./system-prompt.js";
17
- export declare function persistMessage(core: SessionCore, message: AgentMessage): void;
19
+ export declare function persistMessage(core: SessionCore, message: AgentMessage): SessionEntry | undefined;
18
20
  export declare function recordModelState(core: SessionCore, model: Model, thinkingLevel: ModelThinkingLevel): void;
21
+ /** 落一条 model_change,返回模型引用(`setModel` 发 model_changed 用)。 */
22
+ export declare function appendModelChange(core: SessionCore, model: Model): ModelRef;
23
+ export declare function findModelOrThrow(providers: ProviderRegistryApi, ref: string): Model;
19
24
  export declare function syncSystemMessage(core: SessionCore, input: Omit<SystemPromptInput, "tools" | "cwd">, tools: readonly ToolDefinition[]): void;
20
25
  export declare function runHookWithEvents(core: Pick<SessionCore, "options" | "emit" | "log" | "depth" | "manager">, event: HookEvent, payload: HookEventPayload, signal?: AbortSignal): Promise<HookOutcome | undefined>;
26
+ /** session_start 事件(bootstrap / SDK 在会话就绪后发一次)。 */
27
+ export declare function sessionStartEvent(manager: SessionManager, reason: "startup" | "resume" | "new" | "fork"): SessionEvent;
@@ -8,6 +8,8 @@
8
8
  * - `runHookWithEvents`:调 HookDispatcher(公共字段按本会话的 depth / sessionId / sessionFile 覆盖),
9
9
  * 逐条发 hook_executed;Hook 自身出错记 warning、按无决策处理。
10
10
  */
11
+ import { modelRefOf } from "../ai/providers/channels.js";
12
+ import { AmaError } from "../errors.js";
11
13
  import { assembleSections, currentSystemState, definedSections, diffSystem, toolDecls, } from "./system-prompt.js";
12
14
  export function persistMessage(core, message) {
13
15
  if (message.role === "custom") {
@@ -19,11 +21,12 @@ export function persistMessage(core, message) {
19
21
  };
20
22
  if (message.details !== undefined)
21
23
  input.details = message.details;
22
- core.appendEntry(input);
24
+ return core.appendEntry(input);
23
25
  }
24
26
  else if (message.role !== "compactionSummary" && message.role !== "branchSummary") {
25
- core.appendEntry({ type: "message", message });
27
+ return core.appendEntry({ type: "message", message });
26
28
  }
29
+ return undefined;
27
30
  }
28
31
  export function recordModelState(core, model, thinkingLevel) {
29
32
  let provider;
@@ -40,17 +43,30 @@ export function recordModelState(core, model, thinkingLevel) {
40
43
  thinking = entry.thinkingLevel;
41
44
  }
42
45
  if (provider !== model.provider || modelId !== model.id || channel !== model.channel) {
43
- core.appendEntry({
44
- type: "model_change",
45
- provider: model.provider,
46
- modelId: model.id,
47
- ...(model.channel !== undefined ? { channel: model.channel } : {}),
48
- });
46
+ appendModelChange(core, model);
49
47
  }
50
48
  if (thinking !== thinkingLevel) {
51
49
  core.appendEntry({ type: "thinking_level_change", thinkingLevel });
52
50
  }
53
51
  }
52
+ /** 落一条 model_change,返回模型引用(`setModel` 发 model_changed 用)。 */
53
+ export function appendModelChange(core, model) {
54
+ const next = modelRefOf(model);
55
+ core.appendEntry({
56
+ type: "model_change",
57
+ provider: next.provider,
58
+ modelId: next.id,
59
+ ...(next.channel !== undefined ? { channel: next.channel } : {}),
60
+ });
61
+ return next;
62
+ }
63
+ export function findModelOrThrow(providers, ref) {
64
+ const lookup = providers.findModel(ref);
65
+ if (!lookup.ok) {
66
+ throw new AmaError("model_not_found", `model ${ref} not found`, { detail: lookup.candidates });
67
+ }
68
+ return lookup.model;
69
+ }
54
70
  export function syncSystemMessage(core, input, tools) {
55
71
  recordModelState(core, core.model(), core.thinkingLevel());
56
72
  const sections = definedSections(assembleSections({ ...input, tools, cwd: core.cwd }));
@@ -109,3 +125,16 @@ export async function runHookWithEvents(core, event, payload, signal) {
109
125
  return undefined;
110
126
  }
111
127
  }
128
+ /** session_start 事件(bootstrap / SDK 在会话就绪后发一次)。 */
129
+ export function sessionStartEvent(manager, reason) {
130
+ const event = {
131
+ type: "session_start",
132
+ sessionId: manager.id,
133
+ cwd: manager.cwd,
134
+ reason,
135
+ };
136
+ const file = manager.file();
137
+ if (file !== undefined)
138
+ event.sessionFile = file;
139
+ return event;
140
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * 会话遥测:输出速率与首 token 延迟(docs/wave5-plan.md §1.3,D2)。[W5-A]
3
+ *
4
+ * 以 `SessionExtension.wrapStream` 包一层流,只观察不改事件:
5
+ * - 只统计 `purpose: "turn"`(缺省即 turn);summary / warm / probe / classify 原样透传、不计入;
6
+ * - 首 token = 首个 `text_delta` / `thinking_delta` / `toolcall_start`(`ttftMs = firstTokenAt − requestAt`);
7
+ * - 流式中按增量字符估算输出 token(CJK / 假名 / 谚文每字 1,其余 / 4,与 `compaction/estimate.ts`
8
+ * 同口径,不逐块取整),瞬时速率取最近 2 s 滑动窗口;请求结束改用 `usage.output`(含 reasoning);
9
+ * - `tps = outputTokens / (doneAt − firstTokenAt)`;会话均速 = Σoutput / Σ(done − firstToken),只计有首
10
+ * token、非 error 且生成时长 ≥ 250 ms 的请求(更短的整块到达,速率无意义,`tps` 留空);
11
+ * - 流式中经 `emit` 发 `telemetry_tick`:首个在首 token 后 ≥ 500 ms,之后两次间隔 ≥ 500 ms(≤ 2 Hz,
12
+ * 只由增量驱动、不起计时器);
13
+ * `ticks: false`(`ui.animation: false`)时不发,界面在 message_end 时刷新。
14
+ *
15
+ * 数据从 `getStats().telemetry` 取(`contributeStats`):进行中的请求出了首 token 后 `last` 即指向它(只有
16
+ * `requestAt / firstTokenAt / ttftMs`),结束后补齐 `doneAt / outputTokens / tps`;`sessionStartedAt` 是扩展创建(本进程打开会话)的时刻。
17
+ */
18
+ import type { SessionExtension, SessionExtensionFactory } from "./session-extensions.js";
19
+ import type { SessionEvent } from "./types.js";
20
+ import type { SessionTelemetry } from "./types-w5.js";
21
+ export declare const TELEMETRY_TICK_MS = 500;
22
+ export declare const TELEMETRY_WINDOW_MS = 2000;
23
+ export interface TelemetryDeps {
24
+ now?(): number;
25
+ /** 发 `telemetry_tick`(缺省不发)。 */
26
+ emit?(event: SessionEvent): void;
27
+ /** false:不发 tick(`ui.animation: false`)。缺省 true。 */
28
+ ticks?: boolean;
29
+ }
30
+ export type TelemetryExtension = SessionExtension & {
31
+ snapshot(): SessionTelemetry;
32
+ };
33
+ /** 一段增量文本的 token 估算(不取整,逐块累加不放大)。 */
34
+ export declare function deltaTokens(text: string): number;
35
+ export declare function createTelemetryExtension(deps?: TelemetryDeps): TelemetryExtension;
36
+ /** 组装表用的工厂:只装主会话(depth 0);`ui.animation: false` 不发 tick。 */
37
+ export declare function telemetryFactory(ui?: {
38
+ animation?: boolean;
39
+ }): SessionExtensionFactory;