@qjp88995/agent-runtime 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (477) hide show
  1. package/dist/agent-extensions.d.ts +30 -0
  2. package/dist/agent-extensions.d.ts.map +1 -0
  3. package/dist/agent-extensions.js +4 -0
  4. package/dist/agent-extensions.js.map +1 -0
  5. package/dist/builtins/ask-outcome.d.ts +49 -0
  6. package/dist/builtins/ask-outcome.d.ts.map +1 -0
  7. package/dist/builtins/ask-outcome.js +128 -0
  8. package/dist/builtins/ask-outcome.js.map +1 -0
  9. package/dist/builtins/ask-schema.d.ts +110 -0
  10. package/dist/builtins/ask-schema.d.ts.map +1 -0
  11. package/dist/builtins/ask-schema.js +124 -0
  12. package/dist/builtins/ask-schema.js.map +1 -0
  13. package/dist/builtins/ask.service.d.ts +210 -0
  14. package/dist/builtins/ask.service.d.ts.map +1 -0
  15. package/dist/builtins/ask.service.js +373 -0
  16. package/dist/builtins/ask.service.js.map +1 -0
  17. package/dist/builtins/ask.tool.d.ts +49 -0
  18. package/dist/builtins/ask.tool.d.ts.map +1 -0
  19. package/dist/builtins/ask.tool.js +109 -0
  20. package/dist/builtins/ask.tool.js.map +1 -0
  21. package/dist/builtins/index.d.ts +8 -0
  22. package/dist/builtins/index.d.ts.map +1 -0
  23. package/dist/builtins/index.js +8 -0
  24. package/dist/builtins/index.js.map +1 -0
  25. package/dist/builtins/todo-schema.d.ts +90 -0
  26. package/dist/builtins/todo-schema.d.ts.map +1 -0
  27. package/dist/builtins/todo-schema.js +97 -0
  28. package/dist/builtins/todo-schema.js.map +1 -0
  29. package/dist/builtins/todo-settle.hook.d.ts +110 -0
  30. package/dist/builtins/todo-settle.hook.d.ts.map +1 -0
  31. package/dist/builtins/todo-settle.hook.js +174 -0
  32. package/dist/builtins/todo-settle.hook.js.map +1 -0
  33. package/dist/builtins/todo.tool.d.ts +59 -0
  34. package/dist/builtins/todo.tool.d.ts.map +1 -0
  35. package/dist/builtins/todo.tool.js +107 -0
  36. package/dist/builtins/todo.tool.js.map +1 -0
  37. package/dist/context/context-budget-tracker.d.ts +185 -0
  38. package/dist/context/context-budget-tracker.d.ts.map +1 -0
  39. package/dist/context/context-budget-tracker.js +400 -0
  40. package/dist/context/context-budget-tracker.js.map +1 -0
  41. package/dist/context/context-budget.d.ts +48 -0
  42. package/dist/context/context-budget.d.ts.map +1 -0
  43. package/dist/context/context-budget.js +89 -0
  44. package/dist/context/context-budget.js.map +1 -0
  45. package/dist/context/index.d.ts +3 -0
  46. package/dist/context/index.d.ts.map +1 -0
  47. package/dist/context/index.js +3 -0
  48. package/dist/context/index.js.map +1 -0
  49. package/dist/extensions/repeat-call.hook.d.ts +32 -0
  50. package/dist/extensions/repeat-call.hook.d.ts.map +1 -0
  51. package/dist/extensions/repeat-call.hook.js +54 -0
  52. package/dist/extensions/repeat-call.hook.js.map +1 -0
  53. package/dist/hooks/index.d.ts +3 -0
  54. package/dist/hooks/index.d.ts.map +1 -0
  55. package/dist/hooks/index.js +3 -0
  56. package/dist/hooks/index.js.map +1 -0
  57. package/dist/hooks/turn-hook.registry.d.ts +51 -0
  58. package/dist/hooks/turn-hook.registry.d.ts.map +1 -0
  59. package/dist/hooks/turn-hook.registry.js +233 -0
  60. package/dist/hooks/turn-hook.registry.js.map +1 -0
  61. package/dist/hooks/turn-hook.types.d.ts +179 -0
  62. package/dist/hooks/turn-hook.types.d.ts.map +1 -0
  63. package/dist/hooks/turn-hook.types.js +48 -0
  64. package/dist/hooks/turn-hook.types.js.map +1 -0
  65. package/dist/images/byte-cache.d.ts +24 -0
  66. package/dist/images/byte-cache.d.ts.map +1 -0
  67. package/dist/images/byte-cache.js +51 -0
  68. package/dist/images/byte-cache.js.map +1 -0
  69. package/dist/images/delivery.d.ts +115 -0
  70. package/dist/images/delivery.d.ts.map +1 -0
  71. package/dist/images/delivery.js +321 -0
  72. package/dist/images/delivery.js.map +1 -0
  73. package/dist/images/index.d.ts +5 -0
  74. package/dist/images/index.d.ts.map +1 -0
  75. package/dist/images/index.js +5 -0
  76. package/dist/images/index.js.map +1 -0
  77. package/dist/images/prompt.d.ts +151 -0
  78. package/dist/images/prompt.d.ts.map +1 -0
  79. package/dist/images/prompt.js +172 -0
  80. package/dist/images/prompt.js.map +1 -0
  81. package/dist/images/vendor-files.d.ts +93 -0
  82. package/dist/images/vendor-files.d.ts.map +1 -0
  83. package/dist/images/vendor-files.js +156 -0
  84. package/dist/images/vendor-files.js.map +1 -0
  85. package/dist/in-process/conversation-store.d.ts +64 -0
  86. package/dist/in-process/conversation-store.d.ts.map +1 -0
  87. package/dist/in-process/conversation-store.js +222 -0
  88. package/dist/in-process/conversation-store.js.map +1 -0
  89. package/dist/in-process/coordination.d.ts +54 -0
  90. package/dist/in-process/coordination.d.ts.map +1 -0
  91. package/dist/in-process/coordination.js +137 -0
  92. package/dist/in-process/coordination.js.map +1 -0
  93. package/dist/in-process/image-source.d.ts +15 -0
  94. package/dist/in-process/image-source.d.ts.map +1 -0
  95. package/dist/in-process/image-source.js +27 -0
  96. package/dist/in-process/image-source.js.map +1 -0
  97. package/dist/in-process/index.d.ts +36 -0
  98. package/dist/in-process/index.d.ts.map +1 -0
  99. package/dist/in-process/index.js +37 -0
  100. package/dist/in-process/index.js.map +1 -0
  101. package/dist/in-process/question-store.d.ts +28 -0
  102. package/dist/in-process/question-store.d.ts.map +1 -0
  103. package/dist/in-process/question-store.js +122 -0
  104. package/dist/in-process/question-store.js.map +1 -0
  105. package/dist/in-process/run-store.d.ts +36 -0
  106. package/dist/in-process/run-store.d.ts.map +1 -0
  107. package/dist/in-process/run-store.js +81 -0
  108. package/dist/in-process/run-store.js.map +1 -0
  109. package/dist/in-process/session-store.d.ts +33 -0
  110. package/dist/in-process/session-store.d.ts.map +1 -0
  111. package/dist/in-process/session-store.js +93 -0
  112. package/dist/in-process/session-store.js.map +1 -0
  113. package/dist/in-process/stream-bus.d.ts +52 -0
  114. package/dist/in-process/stream-bus.d.ts.map +1 -0
  115. package/dist/in-process/stream-bus.js +200 -0
  116. package/dist/in-process/stream-bus.js.map +1 -0
  117. package/dist/in-process/vendor-file-cache.d.ts +11 -0
  118. package/dist/in-process/vendor-file-cache.d.ts.map +1 -0
  119. package/dist/in-process/vendor-file-cache.js +47 -0
  120. package/dist/in-process/vendor-file-cache.js.map +1 -0
  121. package/dist/index.d.ts +21 -0
  122. package/dist/index.d.ts.map +1 -0
  123. package/dist/index.js +21 -0
  124. package/dist/index.js.map +1 -0
  125. package/dist/loop/active-tick.registry.d.ts +31 -0
  126. package/dist/loop/active-tick.registry.d.ts.map +1 -0
  127. package/dist/loop/active-tick.registry.js +45 -0
  128. package/dist/loop/active-tick.registry.js.map +1 -0
  129. package/dist/loop/index.d.ts +6 -0
  130. package/dist/loop/index.d.ts.map +1 -0
  131. package/dist/loop/index.js +6 -0
  132. package/dist/loop/index.js.map +1 -0
  133. package/dist/loop/loop-driver.d.ts +127 -0
  134. package/dist/loop/loop-driver.d.ts.map +1 -0
  135. package/dist/loop/loop-driver.js +199 -0
  136. package/dist/loop/loop-driver.js.map +1 -0
  137. package/dist/loop/message-hub.d.ts +236 -0
  138. package/dist/loop/message-hub.d.ts.map +1 -0
  139. package/dist/loop/message-hub.js +439 -0
  140. package/dist/loop/message-hub.js.map +1 -0
  141. package/dist/loop/orphan-run.sweeper.d.ts +79 -0
  142. package/dist/loop/orphan-run.sweeper.d.ts.map +1 -0
  143. package/dist/loop/orphan-run.sweeper.js +145 -0
  144. package/dist/loop/orphan-run.sweeper.js.map +1 -0
  145. package/dist/loop/root-host.d.ts +51 -0
  146. package/dist/loop/root-host.d.ts.map +1 -0
  147. package/dist/loop/root-host.js +65 -0
  148. package/dist/loop/root-host.js.map +1 -0
  149. package/dist/ports/context-store.d.ts +69 -0
  150. package/dist/ports/context-store.d.ts.map +1 -0
  151. package/dist/ports/context-store.js +2 -0
  152. package/dist/ports/context-store.js.map +1 -0
  153. package/dist/ports/conversation-store.d.ts +144 -0
  154. package/dist/ports/conversation-store.d.ts.map +1 -0
  155. package/dist/ports/conversation-store.js +2 -0
  156. package/dist/ports/conversation-store.js.map +1 -0
  157. package/dist/ports/coordination.d.ts +76 -0
  158. package/dist/ports/coordination.d.ts.map +1 -0
  159. package/dist/ports/coordination.js +12 -0
  160. package/dist/ports/coordination.js.map +1 -0
  161. package/dist/ports/image-source.d.ts +26 -0
  162. package/dist/ports/image-source.d.ts.map +1 -0
  163. package/dist/ports/image-source.js +2 -0
  164. package/dist/ports/image-source.js.map +1 -0
  165. package/dist/ports/index.d.ts +11 -0
  166. package/dist/ports/index.d.ts.map +1 -0
  167. package/dist/ports/index.js +4 -0
  168. package/dist/ports/index.js.map +1 -0
  169. package/dist/ports/logger.d.ts +14 -0
  170. package/dist/ports/logger.d.ts.map +1 -0
  171. package/dist/ports/logger.js +23 -0
  172. package/dist/ports/logger.js.map +1 -0
  173. package/dist/ports/question-store.d.ts +91 -0
  174. package/dist/ports/question-store.d.ts.map +1 -0
  175. package/dist/ports/question-store.js +8 -0
  176. package/dist/ports/question-store.js.map +1 -0
  177. package/dist/ports/run-store.d.ts +66 -0
  178. package/dist/ports/run-store.d.ts.map +1 -0
  179. package/dist/ports/run-store.js +2 -0
  180. package/dist/ports/run-store.js.map +1 -0
  181. package/dist/ports/session-store.d.ts +72 -0
  182. package/dist/ports/session-store.d.ts.map +1 -0
  183. package/dist/ports/session-store.js +9 -0
  184. package/dist/ports/session-store.js.map +1 -0
  185. package/dist/ports/stream-bus.d.ts +52 -0
  186. package/dist/ports/stream-bus.d.ts.map +1 -0
  187. package/dist/ports/stream-bus.js +2 -0
  188. package/dist/ports/stream-bus.js.map +1 -0
  189. package/dist/ports/vendor-file-cache.d.ts +46 -0
  190. package/dist/ports/vendor-file-cache.d.ts.map +1 -0
  191. package/dist/ports/vendor-file-cache.js +2 -0
  192. package/dist/ports/vendor-file-cache.js.map +1 -0
  193. package/dist/schema/agent-event.d.ts +35 -0
  194. package/dist/schema/agent-event.d.ts.map +1 -0
  195. package/dist/schema/agent-event.js +46 -0
  196. package/dist/schema/agent-event.js.map +1 -0
  197. package/dist/schema/agent-run.d.ts +23 -0
  198. package/dist/schema/agent-run.d.ts.map +1 -0
  199. package/dist/schema/agent-run.js +37 -0
  200. package/dist/schema/agent-run.js.map +1 -0
  201. package/dist/schema/index.d.ts +4 -0
  202. package/dist/schema/index.d.ts.map +1 -0
  203. package/dist/schema/index.js +4 -0
  204. package/dist/schema/index.js.map +1 -0
  205. package/dist/schema/message-part.d.ts +73 -0
  206. package/dist/schema/message-part.d.ts.map +1 -0
  207. package/dist/schema/message-part.js +90 -0
  208. package/dist/schema/message-part.js.map +1 -0
  209. package/dist/subagent/delegate.tool.d.ts +145 -0
  210. package/dist/subagent/delegate.tool.d.ts.map +1 -0
  211. package/dist/subagent/delegate.tool.js +329 -0
  212. package/dist/subagent/delegate.tool.js.map +1 -0
  213. package/dist/subagent/index.d.ts +10 -0
  214. package/dist/subagent/index.d.ts.map +1 -0
  215. package/dist/subagent/index.js +10 -0
  216. package/dist/subagent/index.js.map +1 -0
  217. package/dist/subagent/milestone-body.d.ts +82 -0
  218. package/dist/subagent/milestone-body.d.ts.map +1 -0
  219. package/dist/subagent/milestone-body.js +112 -0
  220. package/dist/subagent/milestone-body.js.map +1 -0
  221. package/dist/subagent/output-scan.d.ts +14 -0
  222. package/dist/subagent/output-scan.d.ts.map +1 -0
  223. package/dist/subagent/output-scan.js +41 -0
  224. package/dist/subagent/output-scan.js.map +1 -0
  225. package/dist/subagent/registry-spawn-policy.d.ts +32 -0
  226. package/dist/subagent/registry-spawn-policy.d.ts.map +1 -0
  227. package/dist/subagent/registry-spawn-policy.js +48 -0
  228. package/dist/subagent/registry-spawn-policy.js.map +1 -0
  229. package/dist/subagent/roster-block.d.ts +45 -0
  230. package/dist/subagent/roster-block.d.ts.map +1 -0
  231. package/dist/subagent/roster-block.js +69 -0
  232. package/dist/subagent/roster-block.js.map +1 -0
  233. package/dist/subagent/situation-block.d.ts +16 -0
  234. package/dist/subagent/situation-block.d.ts.map +1 -0
  235. package/dist/subagent/situation-block.js +71 -0
  236. package/dist/subagent/situation-block.js.map +1 -0
  237. package/dist/subagent/spawn-guards.d.ts +32 -0
  238. package/dist/subagent/spawn-guards.d.ts.map +1 -0
  239. package/dist/subagent/spawn-guards.js +39 -0
  240. package/dist/subagent/spawn-guards.js.map +1 -0
  241. package/dist/subagent/subagent-registry.d.ts +150 -0
  242. package/dist/subagent/subagent-registry.d.ts.map +1 -0
  243. package/dist/subagent/subagent-registry.js +167 -0
  244. package/dist/subagent/subagent-registry.js.map +1 -0
  245. package/dist/subagent/subagent-sessions.d.ts +213 -0
  246. package/dist/subagent/subagent-sessions.d.ts.map +1 -0
  247. package/dist/subagent/subagent-sessions.js +295 -0
  248. package/dist/subagent/subagent-sessions.js.map +1 -0
  249. package/dist/testing/contracts.d.ts +37 -0
  250. package/dist/testing/contracts.d.ts.map +1 -0
  251. package/dist/testing/contracts.js +607 -0
  252. package/dist/testing/contracts.js.map +1 -0
  253. package/dist/testing/index.d.ts +5 -0
  254. package/dist/testing/index.d.ts.map +1 -0
  255. package/dist/testing/index.js +5 -0
  256. package/dist/testing/index.js.map +1 -0
  257. package/dist/testing/stub.d.ts +28 -0
  258. package/dist/testing/stub.d.ts.map +1 -0
  259. package/dist/testing/stub.js +3 -0
  260. package/dist/testing/stub.js.map +1 -0
  261. package/dist/tools/agent-tool.base.d.ts +186 -0
  262. package/dist/tools/agent-tool.base.d.ts.map +1 -0
  263. package/dist/tools/agent-tool.base.js +243 -0
  264. package/dist/tools/agent-tool.base.js.map +1 -0
  265. package/dist/tools/agent-tool.interface.d.ts +95 -0
  266. package/dist/tools/agent-tool.interface.d.ts.map +1 -0
  267. package/dist/tools/agent-tool.interface.js +2 -0
  268. package/dist/tools/agent-tool.interface.js.map +1 -0
  269. package/dist/tools/builtin-names.d.ts +18 -0
  270. package/dist/tools/builtin-names.d.ts.map +1 -0
  271. package/dist/tools/builtin-names.js +20 -0
  272. package/dist/tools/builtin-names.js.map +1 -0
  273. package/dist/tools/index.d.ts +9 -0
  274. package/dist/tools/index.d.ts.map +1 -0
  275. package/dist/tools/index.js +6 -0
  276. package/dist/tools/index.js.map +1 -0
  277. package/dist/tools/tool-definition.d.ts +18 -0
  278. package/dist/tools/tool-definition.d.ts.map +1 -0
  279. package/dist/tools/tool-definition.js +77 -0
  280. package/dist/tools/tool-definition.js.map +1 -0
  281. package/dist/tools/tool-meta.d.ts +55 -0
  282. package/dist/tools/tool-meta.d.ts.map +1 -0
  283. package/dist/tools/tool-meta.js +2 -0
  284. package/dist/tools/tool-meta.js.map +1 -0
  285. package/dist/tools/tool-registry.d.ts +190 -0
  286. package/dist/tools/tool-registry.d.ts.map +1 -0
  287. package/dist/tools/tool-registry.js +379 -0
  288. package/dist/tools/tool-registry.js.map +1 -0
  289. package/dist/tools/tool-result.d.ts +41 -0
  290. package/dist/tools/tool-result.d.ts.map +1 -0
  291. package/dist/tools/tool-result.js +19 -0
  292. package/dist/tools/tool-result.js.map +1 -0
  293. package/dist/tools/tool-wire.d.ts +24 -0
  294. package/dist/tools/tool-wire.d.ts.map +1 -0
  295. package/dist/tools/tool-wire.js +2 -0
  296. package/dist/tools/tool-wire.js.map +1 -0
  297. package/dist/turn/agent-runtime.d.ts +31 -0
  298. package/dist/turn/agent-runtime.d.ts.map +1 -0
  299. package/dist/turn/agent-runtime.js +30 -0
  300. package/dist/turn/agent-runtime.js.map +1 -0
  301. package/dist/turn/chunk-projection.d.ts +32 -0
  302. package/dist/turn/chunk-projection.d.ts.map +1 -0
  303. package/dist/turn/chunk-projection.js +62 -0
  304. package/dist/turn/chunk-projection.js.map +1 -0
  305. package/dist/turn/compaction.d.ts +48 -0
  306. package/dist/turn/compaction.d.ts.map +1 -0
  307. package/dist/turn/compaction.js +89 -0
  308. package/dist/turn/compaction.js.map +1 -0
  309. package/dist/turn/context-overflow.d.ts +11 -0
  310. package/dist/turn/context-overflow.d.ts.map +1 -0
  311. package/dist/turn/context-overflow.js +53 -0
  312. package/dist/turn/context-overflow.js.map +1 -0
  313. package/dist/turn/context-pressure.d.ts +100 -0
  314. package/dist/turn/context-pressure.d.ts.map +1 -0
  315. package/dist/turn/context-pressure.js +21 -0
  316. package/dist/turn/context-pressure.js.map +1 -0
  317. package/dist/turn/events-to-steps.d.ts +8 -0
  318. package/dist/turn/events-to-steps.d.ts.map +1 -0
  319. package/dist/turn/events-to-steps.js +64 -0
  320. package/dist/turn/events-to-steps.js.map +1 -0
  321. package/dist/turn/index.d.ts +17 -0
  322. package/dist/turn/index.d.ts.map +1 -0
  323. package/dist/turn/index.js +16 -0
  324. package/dist/turn/index.js.map +1 -0
  325. package/dist/turn/json-preview.d.ts +22 -0
  326. package/dist/turn/json-preview.d.ts.map +1 -0
  327. package/dist/turn/json-preview.js +34 -0
  328. package/dist/turn/json-preview.js.map +1 -0
  329. package/dist/turn/json-string-field.d.ts +30 -0
  330. package/dist/turn/json-string-field.d.ts.map +1 -0
  331. package/dist/turn/json-string-field.js +125 -0
  332. package/dist/turn/json-string-field.js.map +1 -0
  333. package/dist/turn/loop-reminder.d.ts +79 -0
  334. package/dist/turn/loop-reminder.d.ts.map +1 -0
  335. package/dist/turn/loop-reminder.js +0 -0
  336. package/dist/turn/loop-reminder.js.map +1 -0
  337. package/dist/turn/nul-safe.d.ts +21 -0
  338. package/dist/turn/nul-safe.d.ts.map +1 -0
  339. package/dist/turn/nul-safe.js +23 -0
  340. package/dist/turn/nul-safe.js.map +1 -0
  341. package/dist/turn/parts-from-events.d.ts +71 -0
  342. package/dist/turn/parts-from-events.d.ts.map +1 -0
  343. package/dist/turn/parts-from-events.js +217 -0
  344. package/dist/turn/parts-from-events.js.map +1 -0
  345. package/dist/turn/parts-to-model-messages.d.ts +158 -0
  346. package/dist/turn/parts-to-model-messages.d.ts.map +1 -0
  347. package/dist/turn/parts-to-model-messages.js +334 -0
  348. package/dist/turn/parts-to-model-messages.js.map +1 -0
  349. package/dist/turn/pending-work.d.ts +10 -0
  350. package/dist/turn/pending-work.d.ts.map +1 -0
  351. package/dist/turn/pending-work.js +14 -0
  352. package/dist/turn/pending-work.js.map +1 -0
  353. package/dist/turn/provider-error.d.ts +45 -0
  354. package/dist/turn/provider-error.d.ts.map +1 -0
  355. package/dist/turn/provider-error.js +154 -0
  356. package/dist/turn/provider-error.js.map +1 -0
  357. package/dist/turn/tool-input-preview.d.ts +94 -0
  358. package/dist/turn/tool-input-preview.d.ts.map +1 -0
  359. package/dist/turn/tool-input-preview.js +143 -0
  360. package/dist/turn/tool-input-preview.js.map +1 -0
  361. package/dist/turn/tool-input-progress.d.ts +47 -0
  362. package/dist/turn/tool-input-progress.d.ts.map +1 -0
  363. package/dist/turn/tool-input-progress.js +50 -0
  364. package/dist/turn/tool-input-progress.js.map +1 -0
  365. package/dist/turn/turn-envelope.d.ts +184 -0
  366. package/dist/turn/turn-envelope.d.ts.map +1 -0
  367. package/dist/turn/turn-envelope.js +2 -0
  368. package/dist/turn/turn-envelope.js.map +1 -0
  369. package/dist/turn/turn-journal.d.ts +49 -0
  370. package/dist/turn/turn-journal.d.ts.map +1 -0
  371. package/dist/turn/turn-journal.js +51 -0
  372. package/dist/turn/turn-journal.js.map +1 -0
  373. package/dist/turn/turn-run.d.ts +487 -0
  374. package/dist/turn/turn-run.d.ts.map +1 -0
  375. package/dist/turn/turn-run.js +1167 -0
  376. package/dist/turn/turn-run.js.map +1 -0
  377. package/dist/turn/usage.d.ts +27 -0
  378. package/dist/turn/usage.d.ts.map +1 -0
  379. package/dist/turn/usage.js +51 -0
  380. package/dist/turn/usage.js.map +1 -0
  381. package/package.json +59 -3
  382. package/src/agent-extensions.ts +33 -0
  383. package/src/builtins/ask-outcome.ts +168 -0
  384. package/src/builtins/ask-schema.ts +186 -0
  385. package/src/builtins/ask.service.ts +482 -0
  386. package/src/builtins/ask.tool.ts +138 -0
  387. package/src/builtins/index.ts +25 -0
  388. package/src/builtins/todo-schema.ts +108 -0
  389. package/src/builtins/todo-settle.hook.ts +221 -0
  390. package/src/builtins/todo.tool.ts +134 -0
  391. package/src/context/context-budget-tracker.ts +519 -0
  392. package/src/context/context-budget.ts +124 -0
  393. package/src/context/index.ts +17 -0
  394. package/src/extensions/repeat-call.hook.ts +77 -0
  395. package/src/hooks/index.ts +19 -0
  396. package/src/hooks/turn-hook.registry.ts +307 -0
  397. package/src/hooks/turn-hook.types.ts +210 -0
  398. package/src/images/byte-cache.ts +61 -0
  399. package/src/images/delivery.ts +508 -0
  400. package/src/images/index.ts +35 -0
  401. package/src/images/prompt.ts +289 -0
  402. package/src/images/vendor-files.ts +235 -0
  403. package/src/in-process/conversation-store.ts +304 -0
  404. package/src/in-process/coordination.ts +177 -0
  405. package/src/in-process/image-source.ts +29 -0
  406. package/src/in-process/index.ts +52 -0
  407. package/src/in-process/question-store.ts +155 -0
  408. package/src/in-process/run-store.ts +115 -0
  409. package/src/in-process/session-store.ts +118 -0
  410. package/src/in-process/stream-bus.ts +244 -0
  411. package/src/in-process/vendor-file-cache.ts +67 -0
  412. package/src/index.ts +28 -0
  413. package/src/loop/active-tick.registry.ts +49 -0
  414. package/src/loop/index.ts +25 -0
  415. package/src/loop/loop-driver.ts +275 -0
  416. package/src/loop/message-hub.ts +532 -0
  417. package/src/loop/orphan-run.sweeper.ts +204 -0
  418. package/src/loop/root-host.ts +119 -0
  419. package/src/ports/context-store.ts +71 -0
  420. package/src/ports/conversation-store.ts +165 -0
  421. package/src/ports/coordination.ts +81 -0
  422. package/src/ports/image-source.ts +26 -0
  423. package/src/ports/index.ts +56 -0
  424. package/src/ports/logger.ts +34 -0
  425. package/src/ports/question-store.ts +117 -0
  426. package/src/ports/run-store.ts +69 -0
  427. package/src/ports/session-store.ts +80 -0
  428. package/src/ports/stream-bus.ts +59 -0
  429. package/src/ports/vendor-file-cache.ts +54 -0
  430. package/src/schema/agent-event.ts +69 -0
  431. package/src/schema/agent-run.ts +44 -0
  432. package/src/schema/index.ts +25 -0
  433. package/src/schema/message-part.ts +100 -0
  434. package/src/subagent/delegate.tool.ts +476 -0
  435. package/src/subagent/index.ts +63 -0
  436. package/src/subagent/milestone-body.ts +144 -0
  437. package/src/subagent/output-scan.ts +56 -0
  438. package/src/subagent/registry-spawn-policy.ts +85 -0
  439. package/src/subagent/roster-block.ts +103 -0
  440. package/src/subagent/situation-block.ts +83 -0
  441. package/src/subagent/spawn-guards.ts +54 -0
  442. package/src/subagent/subagent-registry.ts +283 -0
  443. package/src/subagent/subagent-sessions.ts +496 -0
  444. package/src/testing/contracts.ts +882 -0
  445. package/src/testing/index.ts +14 -0
  446. package/src/testing/stub.ts +28 -0
  447. package/src/tools/agent-tool.base.ts +361 -0
  448. package/src/tools/agent-tool.interface.ts +101 -0
  449. package/src/tools/builtin-names.ts +26 -0
  450. package/src/tools/index.ts +39 -0
  451. package/src/tools/tool-definition.ts +93 -0
  452. package/src/tools/tool-meta.ts +60 -0
  453. package/src/tools/tool-registry.ts +513 -0
  454. package/src/tools/tool-result.ts +45 -0
  455. package/src/tools/tool-wire.ts +24 -0
  456. package/src/turn/agent-runtime.ts +43 -0
  457. package/src/turn/chunk-projection.ts +81 -0
  458. package/src/turn/compaction.ts +103 -0
  459. package/src/turn/context-overflow.ts +54 -0
  460. package/src/turn/context-pressure.ts +114 -0
  461. package/src/turn/events-to-steps.ts +73 -0
  462. package/src/turn/index.ts +71 -0
  463. package/src/turn/json-preview.ts +36 -0
  464. package/src/turn/json-string-field.ts +134 -0
  465. package/src/turn/loop-reminder.ts +0 -0
  466. package/src/turn/nul-safe.ts +22 -0
  467. package/src/turn/parts-from-events.ts +248 -0
  468. package/src/turn/parts-to-model-messages.ts +428 -0
  469. package/src/turn/pending-work.ts +14 -0
  470. package/src/turn/provider-error.ts +160 -0
  471. package/src/turn/tool-input-preview.ts +223 -0
  472. package/src/turn/tool-input-progress.ts +76 -0
  473. package/src/turn/turn-envelope.ts +185 -0
  474. package/src/turn/turn-journal.ts +102 -0
  475. package/src/turn/turn-run.ts +1479 -0
  476. package/src/turn/usage.ts +56 -0
  477. package/README.md +0 -3
@@ -0,0 +1,109 @@
1
+ import { AgentTool } from '../tools/agent-tool.base.js';
2
+ import { ASK_FORMER_NAMES, ASK_TOOL_NAME } from '../tools/builtin-names.js';
3
+ import { toolError } from '../tools/tool-result.js';
4
+ import { renderOutcomeResult } from './ask-outcome.js';
5
+ import { AskInputSchema } from './ask-schema.js';
6
+ /** `Ask` 的登记信息。 */
7
+ export const ASK_TOOL_META = {
8
+ name: ASK_TOOL_NAME,
9
+ formerNames: ASK_FORMER_NAMES,
10
+ description: '向用户提一到四个选择题,并**等用户回答后返回**。用在两种时候:动手之前缺一个' +
11
+ '只有用户能定的决定(方向、取舍、范围);或者你有几个方案,需要用户挑。' +
12
+ '每题 2–4 个互斥选项;界面会自动附一个「其他」让用户自由输入,不要自己写。' +
13
+ '**给了 `defaultOption` 的题用户可以跳过**(按它算,结果里会标明这一题不是用户' +
14
+ '亲手选的);你没法替用户猜的事不要给默认项,那一题就是必答。' +
15
+ '你有倾向时把推荐的选项放第一个,并在它的 label 末尾写「(推荐)」。' +
16
+ '用户回答之前你说不了话——要对用户说的(为什么问、各选项的背景)写在调用之前' +
17
+ '的正文里。用户也可能不点选项、改为直接打字回复,那时返回值会告诉你,他的话在' +
18
+ '紧随其后的那条消息里。' +
19
+ '`timeoutSeconds`:只在「用户不在也该接着干」且默认项安全、事后能改时才给' +
20
+ '(风格、篇幅这类偏好),到点按每一题的 `defaultOption` 继续。会覆盖或删除' +
21
+ '用户的东西、对外发送、或无法撤销的决定**不要给超时**,一直等到用户回答。' +
22
+ '不要用它问自己能查到的事(先用工具查);不要问「要不要继续」「这样可以吗」' +
23
+ '这类客套确认;一次把要问的问全(最多 4 题),不要连着问好几次。',
24
+ // 每个 agent 都有;端不端上桌由宿主按 `AskService.availableFor` 摘(`excludeTools`)。
25
+ category: 'system',
26
+ };
27
+ /**
28
+ * 向用户提问,**等到有了结局再返回**(原名见 `ASK_FORMER_NAMES`)。
29
+ *
30
+ * 同步工具:这一轮不结束,模型拿到回答接着干。为什么不做成「问完本轮就结束、
31
+ * 回答再唤醒下一轮」,见 `AskService` 的类注释。
32
+ *
33
+ * 等待由服务负责(`waitForOutcome`);`ctx.abortSignal` 是「用户中止 ∪ 本工具超时」
34
+ * 的合成信号,两种情形服务都会把问题作废再返回。
35
+ */
36
+ export class AskTool extends AgentTool {
37
+ questions;
38
+ // 交叉校验(限时必须有默认项、默认项必须是选项之一)写在 schema 上;类型标注
39
+ // 只为满足基类的 `z.ZodType<TInput>`(`multiSelect` 有缺省值,入参类型比出参宽)。
40
+ inputSchema = AskInputSchema;
41
+ /**
42
+ * 比服务里的等待上限多留两分钟:上限到点由服务把问题**作废**并正常返回一句话,
43
+ * 不该让基类的超时抢先把它变成一条「工具执行超时」的错误。
44
+ */
45
+ timeoutMs;
46
+ constructor(questions) {
47
+ super();
48
+ this.questions = questions;
49
+ this.timeoutMs = (questions.maxWaitSeconds + 120) * 1000;
50
+ }
51
+ async run(raw, ctx) {
52
+ // 自己再 parse 一次:不假定入参跑过 schema 上那几条交叉校验,而它们每一条都
53
+ // 对应一个「落了行才发现问不下去」的问题。
54
+ const parsed = AskInputSchema.safeParse(raw);
55
+ if (!parsed.success) {
56
+ return toolError(`入参不合法:${parsed.error.issues
57
+ .map(i => `${i.path.join('.')}:${i.message}`)
58
+ .join(';')}`);
59
+ }
60
+ const asked = await this.questions.ask({
61
+ sessionId: ctx.sessionId,
62
+ runId: ctx.runId,
63
+ toolCallId: ctx.toolCallId,
64
+ request: parsed.data,
65
+ });
66
+ if (!asked.ok)
67
+ return toolError(asked.message);
68
+ const settled = await this.questions.waitForOutcome(asked.question.id, ctx.abortSignal);
69
+ return {
70
+ kind: 'ok',
71
+ questionId: asked.question.id,
72
+ text: renderOutcomeResult(settled
73
+ ? {
74
+ status: settled.status,
75
+ questions: settled.questions,
76
+ answers: settled.answers,
77
+ waitedSeconds: parsed.data.timeoutSeconds ?? null,
78
+ }
79
+ : // 那一行没了(会话被删):按作废说。
80
+ {
81
+ status: 'cancelled',
82
+ questions: parsed.data.questions,
83
+ answers: null,
84
+ waitedSeconds: null,
85
+ }),
86
+ };
87
+ }
88
+ render(out) {
89
+ return out.text;
90
+ }
91
+ /** 界面按它把那一行问题对到这张工具卡上。 */
92
+ persistRef(out) {
93
+ return out.kind === 'ok' ? { questionId: out.questionId } : undefined;
94
+ }
95
+ /**
96
+ * 钉住,不许上下文裁剪换成存根:这是一两句话的**用户决定**,裁掉之后模型无从
97
+ * 重新得知,只会按自己的猜测往下写、或把同一个问题再问一遍。
98
+ */
99
+ persistPinned(out) {
100
+ return out.kind === 'ok';
101
+ }
102
+ }
103
+ /** 登记 `Ask`。 */
104
+ export function registerAskTool(tools, service) {
105
+ const tool = new AskTool(service);
106
+ tools.register(ASK_TOOL_META, tool);
107
+ return tool;
108
+ }
109
+ //# sourceMappingURL=ask.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ask.tool.js","sourceRoot":"","sources":["../../src/builtins/ask.tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export { ASK_MAX_WAIT_SECONDS, ASK_POLL_INTERVAL_MS, ASK_TIMEOUT_MAX_DEFAULT, ASK_TIMEOUT_MIN_DEFAULT, AskAnswerError, type AskOutcome, AskService, type AskServiceDeps, type SettledQuestion, toQuestionWire, } from './ask.service.js';
2
+ export { ASK_TOOL_META, AskTool, registerAskTool } from './ask.tool.js';
3
+ export { type AnswerValidation, defaultAnswers, describeWait, type QuestionOutcome, renderOutcomeResult, validateAnswers, } from './ask-outcome.js';
4
+ export * from './ask-schema.js';
5
+ export { registerTodoTool, TODO_TOOL_META, TodoTool } from './todo.tool.js';
6
+ export * from './todo-schema.js';
7
+ export * from './todo-settle.hook.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/builtins/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,uBAAuB,EACvB,uBAAuB,EACvB,cAAc,EACd,KAAK,UAAU,EACf,UAAU,EACV,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,cAAc,GACf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACxE,OAAO,EACL,KAAK,gBAAgB,EACrB,cAAc,EACd,YAAY,EACZ,KAAK,eAAe,EACpB,mBAAmB,EACnB,eAAe,GAChB,MAAM,kBAAkB,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC5E,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC"}
@@ -0,0 +1,8 @@
1
+ export { ASK_MAX_WAIT_SECONDS, ASK_POLL_INTERVAL_MS, ASK_TIMEOUT_MAX_DEFAULT, ASK_TIMEOUT_MIN_DEFAULT, AskAnswerError, AskService, toQuestionWire, } from './ask.service.js';
2
+ export { ASK_TOOL_META, AskTool, registerAskTool } from './ask.tool.js';
3
+ export { defaultAnswers, describeWait, renderOutcomeResult, validateAnswers, } from './ask-outcome.js';
4
+ export * from './ask-schema.js';
5
+ export { registerTodoTool, TODO_TOOL_META, TodoTool } from './todo.tool.js';
6
+ export * from './todo-schema.js';
7
+ export * from './todo-settle.hook.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/builtins/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,uBAAuB,EACvB,uBAAuB,EACvB,cAAc,EAEd,UAAU,EAGV,cAAc,GACf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACxE,OAAO,EAEL,cAAc,EACd,YAAY,EAEZ,mBAAmB,EACnB,eAAe,GAChB,MAAM,kBAAkB,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC5E,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC"}
@@ -0,0 +1,90 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Agent 的待办清单 —— `Todo` 工具(原 `TodoWrite`)的入参形状,前后端共用。
4
+ *
5
+ * ## 它没有存储层,这是有意的
6
+ *
7
+ * 清单**不落业务表、不加 DDL、后端不持任何状态**:`Todo` 是纯记账工具,
8
+ * 一次调用把**整份清单**原样写进这次 tool-call 的入参,那条 `chat_message`
9
+ * 行就是它唯一的存放处。于是「当前清单」= 历史里最后一次 `Todo` 的入参,
10
+ * 前端按这个纯函数派生(`latestTodoList`)。
11
+ *
12
+ * 这么定的直接好处是它自动搭上了上下文预算那套机制:裁剪只把 tool-result 的
13
+ * **正文**换成存根、**tool-call 的入参原封不动**(见
14
+ * `parts-to-model-messages.ts`),所以清单被裁进阴影区之后模型照样看得见。
15
+ * 反过来,若把清单存去别处,就得再造一条「压缩之后把它送回上下文」的路
16
+ * —— Claude Code 正是因为存在会话文件里才必须那么做。
17
+ *
18
+ * ## 全量替换,没有增量
19
+ *
20
+ * 每次调用给的都是完整清单,改一条状态也要把五条一起发回来。少一个 patch
21
+ * 语义就少一整类「服务端与模型各持半份、谁也不知道对方改了什么」的 bug,
22
+ * 而代价(重发几十个 token)在这个体量下不值一提。**也正因为是全量,
23
+ * 才不需要一个读取工具**:最新一份就在模型自己上一次的入参里。
24
+ */
25
+ /**
26
+ * 一条待办的三态。
27
+ *
28
+ * 刻意只有三个:`pending` 还没开始、`in_progress` 正在做、`completed` 做完了。
29
+ * 「阻塞中」「已放弃」这类第四态每次都有人想加,但模型表达它们的地方是对话正文
30
+ * (说清为什么卡住),不是这个枚举——多一个状态就多一处界面要渲染、多一条
31
+ * 模型要判断的规则,而它换回来的信息,一句话本来就说得更清楚。
32
+ */
33
+ export declare const TODO_STATUSES: readonly ["pending", "in_progress", "completed"];
34
+ export type TodoStatus = (typeof TODO_STATUSES)[number];
35
+ /**
36
+ * 单条待办。**只有正文与状态两个字段**。
37
+ *
38
+ * 刻意不要 Claude Code 那个 `activeForm`(同一件事的进行时说法,「加工具」→
39
+ * 「正在加工具」):那是终端底部那行 spinner 逼出来的字段——一行的地方放不下
40
+ * 整份清单,只能显示当前这条的进行时。我们的界面上进行中那条本来就带着描边
41
+ * 待在清单里,不缺这个提示,而多一个字段就是多一份模型每次都要写对的东西。
42
+ */
43
+ export declare const TodoItemSchema: z.ZodObject<{
44
+ content: z.ZodString;
45
+ status: z.ZodEnum<{
46
+ pending: "pending";
47
+ completed: "completed";
48
+ in_progress: "in_progress";
49
+ }>;
50
+ }, z.core.$strip>;
51
+ export type TodoItem = z.infer<typeof TodoItemSchema>;
52
+ /**
53
+ * 整份清单。**顺序原样保留**——那是任务的依赖顺序(先定 schema 才谈得上写
54
+ * 实现),工具与后端一律不重排。界面按状态分组显示是另一层的取舍,且只重排
55
+ * 组、不动组内(见 portal / web 的待办面板)。
56
+ *
57
+ * 50 条上限同样是拒绝:真拆到 50 步的任务,缺的是再拆一层子任务(或派个子
58
+ * Agent),不是更长的清单。
59
+ */
60
+ export declare const TodoListSchema: z.ZodArray<z.ZodObject<{
61
+ content: z.ZodString;
62
+ status: z.ZodEnum<{
63
+ pending: "pending";
64
+ completed: "completed";
65
+ in_progress: "in_progress";
66
+ }>;
67
+ }, z.core.$strip>>;
68
+ /**
69
+ * 从一次 `Todo` 调用的入参里取出清单。
70
+ *
71
+ * **必须走 zod 而不是 `as`**,且有两处**都会正常发生**、必须落到 null 的情形:
72
+ *
73
+ * 1. **参数还在流式生成**:`tool-call` 事件要等整个 step 的流消费完才发,在那
74
+ * 之前入参是半截的(甚至是 `undefined`)。
75
+ * 2. **历史形状变过**:老会话里存的是当时那一版的入参。
76
+ *
77
+ * 两者都返回 null,由调用方决定怎么办——面板的做法是**继续用上一份**而不是
78
+ * 清空,否则每更新一次待办,面板就会闪一下空白再长回来。
79
+ */
80
+ export declare function parseTodoInput(input: unknown): TodoItem[] | null;
81
+ /**
82
+ * 当前清单 = 历史里最后一次 `Todo` 调用的入参(现名或旧名都认)。`calls` 按发生顺序给;
83
+ * 最后一次解析不了(还在流式生成 / 老形状)就往前找上一份——面板**继续用上一份**而不是
84
+ * 清空,否则每更新一次待办就闪一下空白。一次都没有返回 null。
85
+ */
86
+ export declare function latestTodoList(calls: ReadonlyArray<{
87
+ toolName: string;
88
+ input: unknown;
89
+ }>): TodoItem[] | null;
90
+ //# sourceMappingURL=todo-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"todo-schema.d.ts","sourceRoot":"","sources":["../../src/builtins/todo-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAQxB;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,kDAAmD,CAAC;AAC9E,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAExD;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc;;;;;;;iBASzB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc;;;;;;;kBAAkC,CAAC;AAE9D;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ,EAAE,GAAG,IAAI,CAKhE;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,aAAa,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC,GACzD,QAAQ,EAAE,GAAG,IAAI,CAQnB"}
@@ -0,0 +1,97 @@
1
+ import { z } from 'zod';
2
+ import { isToolNamed, TODO_FORMER_NAMES, TODO_TOOL_NAME, } from '../tools/builtin-names.js';
3
+ /**
4
+ * Agent 的待办清单 —— `Todo` 工具(原 `TodoWrite`)的入参形状,前后端共用。
5
+ *
6
+ * ## 它没有存储层,这是有意的
7
+ *
8
+ * 清单**不落业务表、不加 DDL、后端不持任何状态**:`Todo` 是纯记账工具,
9
+ * 一次调用把**整份清单**原样写进这次 tool-call 的入参,那条 `chat_message`
10
+ * 行就是它唯一的存放处。于是「当前清单」= 历史里最后一次 `Todo` 的入参,
11
+ * 前端按这个纯函数派生(`latestTodoList`)。
12
+ *
13
+ * 这么定的直接好处是它自动搭上了上下文预算那套机制:裁剪只把 tool-result 的
14
+ * **正文**换成存根、**tool-call 的入参原封不动**(见
15
+ * `parts-to-model-messages.ts`),所以清单被裁进阴影区之后模型照样看得见。
16
+ * 反过来,若把清单存去别处,就得再造一条「压缩之后把它送回上下文」的路
17
+ * —— Claude Code 正是因为存在会话文件里才必须那么做。
18
+ *
19
+ * ## 全量替换,没有增量
20
+ *
21
+ * 每次调用给的都是完整清单,改一条状态也要把五条一起发回来。少一个 patch
22
+ * 语义就少一整类「服务端与模型各持半份、谁也不知道对方改了什么」的 bug,
23
+ * 而代价(重发几十个 token)在这个体量下不值一提。**也正因为是全量,
24
+ * 才不需要一个读取工具**:最新一份就在模型自己上一次的入参里。
25
+ */
26
+ /**
27
+ * 一条待办的三态。
28
+ *
29
+ * 刻意只有三个:`pending` 还没开始、`in_progress` 正在做、`completed` 做完了。
30
+ * 「阻塞中」「已放弃」这类第四态每次都有人想加,但模型表达它们的地方是对话正文
31
+ * (说清为什么卡住),不是这个枚举——多一个状态就多一处界面要渲染、多一条
32
+ * 模型要判断的规则,而它换回来的信息,一句话本来就说得更清楚。
33
+ */
34
+ export const TODO_STATUSES = ['pending', 'in_progress', 'completed'];
35
+ /**
36
+ * 单条待办。**只有正文与状态两个字段**。
37
+ *
38
+ * 刻意不要 Claude Code 那个 `activeForm`(同一件事的进行时说法,「加工具」→
39
+ * 「正在加工具」):那是终端底部那行 spinner 逼出来的字段——一行的地方放不下
40
+ * 整份清单,只能显示当前这条的进行时。我们的界面上进行中那条本来就带着描边
41
+ * 待在清单里,不缺这个提示,而多一个字段就是多一份模型每次都要写对的东西。
42
+ */
43
+ export const TodoItemSchema = z.object({
44
+ /**
45
+ * 一句话说清这一步要做什么。
46
+ *
47
+ * 200 字符上限是**拒绝**不是截断:清单是拿来扫的,一条写成一段的待办在面板
48
+ * 里会挤掉其余全部,而截断会把「做什么」最关键的后半句吃掉、还看不出被吃过。
49
+ */
50
+ content: z.string().trim().min(1).max(200),
51
+ status: z.enum(TODO_STATUSES),
52
+ });
53
+ /**
54
+ * 整份清单。**顺序原样保留**——那是任务的依赖顺序(先定 schema 才谈得上写
55
+ * 实现),工具与后端一律不重排。界面按状态分组显示是另一层的取舍,且只重排
56
+ * 组、不动组内(见 portal / web 的待办面板)。
57
+ *
58
+ * 50 条上限同样是拒绝:真拆到 50 步的任务,缺的是再拆一层子任务(或派个子
59
+ * Agent),不是更长的清单。
60
+ */
61
+ export const TodoListSchema = z.array(TodoItemSchema).max(50);
62
+ /**
63
+ * 从一次 `Todo` 调用的入参里取出清单。
64
+ *
65
+ * **必须走 zod 而不是 `as`**,且有两处**都会正常发生**、必须落到 null 的情形:
66
+ *
67
+ * 1. **参数还在流式生成**:`tool-call` 事件要等整个 step 的流消费完才发,在那
68
+ * 之前入参是半截的(甚至是 `undefined`)。
69
+ * 2. **历史形状变过**:老会话里存的是当时那一版的入参。
70
+ *
71
+ * 两者都返回 null,由调用方决定怎么办——面板的做法是**继续用上一份**而不是
72
+ * 清空,否则每更新一次待办,面板就会闪一下空白再长回来。
73
+ */
74
+ export function parseTodoInput(input) {
75
+ if (input === null || typeof input !== 'object')
76
+ return null;
77
+ const raw = input.todos;
78
+ const parsed = TodoListSchema.safeParse(raw);
79
+ return parsed.success ? parsed.data : null;
80
+ }
81
+ /**
82
+ * 当前清单 = 历史里最后一次 `Todo` 调用的入参(现名或旧名都认)。`calls` 按发生顺序给;
83
+ * 最后一次解析不了(还在流式生成 / 老形状)就往前找上一份——面板**继续用上一份**而不是
84
+ * 清空,否则每更新一次待办就闪一下空白。一次都没有返回 null。
85
+ */
86
+ export function latestTodoList(calls) {
87
+ for (let i = calls.length - 1; i >= 0; i--) {
88
+ const c = calls[i];
89
+ if (!isToolNamed(c.toolName, TODO_TOOL_NAME, TODO_FORMER_NAMES))
90
+ continue;
91
+ const items = parseTodoInput(c.input);
92
+ if (items)
93
+ return items;
94
+ }
95
+ return null;
96
+ }
97
+ //# sourceMappingURL=todo-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"todo-schema.js","sourceRoot":"","sources":["../../src/builtins/todo-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,cAAc,GACf,MAAM,2BAA2B,CAAC;AAEnC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,SAAS,EAAE,aAAa,EAAE,WAAW,CAAU,CAAC;AAG9E;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IACrC;;;;;OAKG;IACH,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IAC1C,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC;CAC9B,CAAC,CAAC;AAGH;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAE9D;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC7D,MAAM,GAAG,GAAI,KAAiC,CAAC,KAAK,CAAC;IACrD,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC7C,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC5B,KAA0D;IAE1D,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACnB,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,EAAE,cAAc,EAAE,iBAAiB,CAAC;YAAE,SAAS;QAC1E,MAAM,KAAK,GAAG,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;IAC1B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * 待办推进提醒:一轮结束时清单里还有没做完的条目,就投一条提醒、换一轮让模型
3
+ * 接着做(或至少把账结掉)。
4
+ *
5
+ * **它治的是模型的工作方式,不是逻辑错误**(2026-09-07 真库取证,会话
6
+ * `ad03599a` 与 `621632d1`):模型列完清单后把某条置 in_progress、用正文把这条
7
+ * 做完,然后**停下来问「要不要继续」**——既不把它翻成 completed,也不接着做
8
+ * 下一条,两件事都要等用户下一句话。前端面板是「最后一次 Todo 入参」的
9
+ * 纯函数,只能照着显示;用户看到的就是「待办不会自己更新」「列了清单还是要
10
+ * 一步一步催」。
11
+ *
12
+ * ## 为什么是换一轮,而不是在本轮内多跑一步
13
+ *
14
+ * 提醒必须以 user 行进上下文(红线「模型看得见的一切都必须能从库里重建」),而
15
+ * 一条 user 行插在**正在跑的这一轮中间**,落库顺序就是错的:assistant 行的 seq
16
+ * 是它首次落库时取的,提醒行必然排在整条 assistant 行**之后**,刷新后模型的
17
+ * 回应会显示在提醒前面。「轮内插 user 行」那套切段机制正是因此被整块拆掉的
18
+ * (见 `TurnHost.hasPendingInbox`)。走 inbox + 换轮,顺序天然正确,新 runId /
19
+ * 新 assistant 行 / SSE 全由既有的 re-wake 白拿——本文件因此**零内核改动**,只是
20
+ * `observe('replied')` 上的一个事后动作。
21
+ *
22
+ * ## 两半合一个扩展
23
+ *
24
+ * 一个 hook 类只能挂一个 point(`hooks.register` 的 meta 是单数),而这件事
25
+ * 要看两处:`preToolUse` 记本轮最后一次 `Todo` 的入参,`observe` 在收尾时
26
+ * 判断并投递。两个类共用 `turnState` 里的**同一个槽**(键 `TODO_SETTLE_STATE_KEY`
27
+ * ——`turnStateOf` 那条「键用插件自己的 name」的规矩在这里让位于「一个扩展一个
28
+ * 槽」,两半的 name 各不相同、槽只有一个)。
29
+ *
30
+ * ## 三道闸门(改反了要么来回催、要么催不动)
31
+ *
32
+ * 1. **本轮写过清单才提醒**:从没写过、或上一轮遗留的未完成本轮没碰,都不管。
33
+ * 后者没有更好的判据——再催一次的收益比不上把每一轮都变成两轮的代价。
34
+ * 2. **回应提醒的那一轮只有「有推进」才再催**:提醒里带着投出时的完成数
35
+ * (`metadata.completed`),本轮收尾时完成数比它大才允许再投。最初的版本是
36
+ * 「回应提醒的那轮一律不催」,真机上模型被催着做完一条后**又**停下来问,第二次
37
+ * 提醒就被挡掉了(会话 `621632d1`)。改成按推进判:模型每被催一次至少多做完
38
+ * 一条,清单至多 50 条,所以有界;模型答「确实在等用户」而不动清单,完成数
39
+ * 不涨,立刻停催——没有死循环的口子。
40
+ * 3. **只管根会话**(`depth === 0`):子会话收尾后父会立刻拿它最后一条 assistant
41
+ * 行当终态(`finalizeIfIdle`),再往它 inbox 投东西会多出一轮、多出一份回执。
42
+ *
43
+ * 只在 `replied`(正常收尾)上投:中断与失败的一轮,模型没把话说完,清单状态本
44
+ * 来就说不上「做没做完」。
45
+ *
46
+ * **接受的代价**:模型合法地停下来等用户(用户明说「先只做第一步」、或它真需要
47
+ * 一个决定)时,也会收到一次提醒并回一句「在等你」——一次换轮、一条标记、一句话。
48
+ * 换来的是「列了清单就会做完」这条用户可以依赖的默契。
49
+ */
50
+ import type { TurnHookRegistry } from '../hooks/turn-hook.registry.js';
51
+ import { type ObservePhase, type PreToolUseResult, type TurnContext, type TurnHookImpl, type TurnHookMeta } from '../hooks/turn-hook.types.js';
52
+ import type { MessageHub } from '../loop/message-hub.js';
53
+ import type { WakeChannel } from '../ports/coordination.js';
54
+ import { type TodoItem } from './todo-schema.js';
55
+ /** 两半共用的 `turnState` 键(见文件头「两半合一个扩展」)。 */
56
+ export declare const TODO_SETTLE_STATE_KEY = "todo-settle";
57
+ /**
58
+ * 记账半:记下本轮最后一次 `Todo` 的入参。
59
+ *
60
+ * **记在发起处、不看结果**:被拒绝的那次(两条 in_progress)同样记——它的清单里
61
+ * 必然有没做完的,收尾时会因此提醒,而模型正该借这一轮把清单修好。
62
+ */
63
+ export declare const TODO_SETTLE_TRACK_META: TurnHookMeta;
64
+ export declare class TodoSettleTrackHook implements TurnHookImpl {
65
+ preToolUse(ctx: TurnContext, _toolName: string, input: unknown): Promise<PreToolUseResult>;
66
+ }
67
+ /**
68
+ * 投递半:收尾时清单里还有没做完的就投提醒、唤醒。
69
+ *
70
+ * 投递用 `MessageHub.post` + `WakeChannel.wake`,与子 Agent 回投同一条路
71
+ * (`SubagentSessions.finalizeIfIdle`);本轮此刻还持有会话锁,wake 只是让 loop 在
72
+ * 释放锁后的那次自查里看到有货。
73
+ */
74
+ export declare const TODO_SETTLE_REMINDER_META: TurnHookMeta;
75
+ export declare class TodoSettleReminderHook implements TurnHookImpl {
76
+ private readonly hub;
77
+ private readonly waker;
78
+ constructor(hub: MessageHub, waker: Pick<WakeChannel, 'wake'>);
79
+ observe(ctx: TurnContext, phase: ObservePhase): Promise<void>;
80
+ }
81
+ export interface TodoDigest {
82
+ total: number;
83
+ completed: number;
84
+ /** 没做完的(进行中 + 未开始),保持清单原序。 */
85
+ unfinished: TodoItem[];
86
+ /** 正在做的那条;零条合法。 */
87
+ active: TodoItem | null;
88
+ }
89
+ /** 一份入参的三个数;形状对不上(半截、老版本)按空清单处理。 */
90
+ export declare function digestTodos(input: unknown): TodoDigest;
91
+ /**
92
+ * 闸门 2:这一轮不是在回应提醒 → 放行;是 → 只有完成数比提醒投出时大才放行。
93
+ *
94
+ * 提醒行的 `completed` 缺失(老数据、别处投的)按「没推进」处理——方向是宁可
95
+ * 少催一次,也不在拿不到判据时无限催。
96
+ */
97
+ export declare function hasProgressSinceReminder(ctx: Pick<TurnContext, 'inbound'>, completedNow: number): boolean;
98
+ /**
99
+ * 提醒文案。**说三件事**:还剩几条(点名进行中那条)、直接接着做别问要不要继续、
100
+ * 做完的要置 completed;再给一条出路——确实在等用户就说清在等什么、别动清单。
101
+ * 只说前三件的话,模型会为了「服从」把一条确实要等用户的事硬做下去或标成完成。
102
+ * 末句挡住最常见的画蛇添足:先把刚交付的正文复述一遍。
103
+ */
104
+ export declare function renderTodoSettleReminder(digest: TodoDigest): string;
105
+ /** 把待办推进提醒的两半挂到注册表上(runtime 的通用扩展,宿主可以不挂)。 */
106
+ export declare function registerTodoSettleHooks(hooks: TurnHookRegistry, deps: {
107
+ hub: MessageHub;
108
+ wake: Pick<WakeChannel, 'wake'>;
109
+ }): void;
110
+ //# sourceMappingURL=todo-settle.hook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"todo-settle.hook.d.ts","sourceRoot":"","sources":["../../src/builtins/todo-settle.hook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,YAAY,EAElB,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAG5D,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjE,0CAA0C;AAC1C,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AAOnD;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,EAAE,YAMpC,CAAC;AAEF,qBAAa,mBAAoB,YAAW,YAAY;IACtD,UAAU,CACR,GAAG,EAAE,WAAW,EAChB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,gBAAgB,CAAC;CAS7B;AAED;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,EAAE,YAKvC,CAAC;AAEF,qBAAa,sBAAuB,YAAW,YAAY;IAEvD,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,KAAK;gBADL,GAAG,EAAE,UAAU,EACf,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC;IAG7C,OAAO,CAAC,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;CAyBpE;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,8BAA8B;IAC9B,UAAU,EAAE,QAAQ,EAAE,CAAC;IACvB,mBAAmB;IACnB,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;CACzB;AAED,oCAAoC;AACpC,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,CAStD;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,EACjC,YAAY,EAAE,MAAM,GACnB,OAAO,CAOT;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAanE;AAED,8CAA8C;AAC9C,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,gBAAgB,EACvB,IAAI,EAAE;IAAE,GAAG,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAA;CAAE,GACzD,IAAI,CAMN"}
@@ -0,0 +1,174 @@
1
+ /**
2
+ * 待办推进提醒:一轮结束时清单里还有没做完的条目,就投一条提醒、换一轮让模型
3
+ * 接着做(或至少把账结掉)。
4
+ *
5
+ * **它治的是模型的工作方式,不是逻辑错误**(2026-09-07 真库取证,会话
6
+ * `ad03599a` 与 `621632d1`):模型列完清单后把某条置 in_progress、用正文把这条
7
+ * 做完,然后**停下来问「要不要继续」**——既不把它翻成 completed,也不接着做
8
+ * 下一条,两件事都要等用户下一句话。前端面板是「最后一次 Todo 入参」的
9
+ * 纯函数,只能照着显示;用户看到的就是「待办不会自己更新」「列了清单还是要
10
+ * 一步一步催」。
11
+ *
12
+ * ## 为什么是换一轮,而不是在本轮内多跑一步
13
+ *
14
+ * 提醒必须以 user 行进上下文(红线「模型看得见的一切都必须能从库里重建」),而
15
+ * 一条 user 行插在**正在跑的这一轮中间**,落库顺序就是错的:assistant 行的 seq
16
+ * 是它首次落库时取的,提醒行必然排在整条 assistant 行**之后**,刷新后模型的
17
+ * 回应会显示在提醒前面。「轮内插 user 行」那套切段机制正是因此被整块拆掉的
18
+ * (见 `TurnHost.hasPendingInbox`)。走 inbox + 换轮,顺序天然正确,新 runId /
19
+ * 新 assistant 行 / SSE 全由既有的 re-wake 白拿——本文件因此**零内核改动**,只是
20
+ * `observe('replied')` 上的一个事后动作。
21
+ *
22
+ * ## 两半合一个扩展
23
+ *
24
+ * 一个 hook 类只能挂一个 point(`hooks.register` 的 meta 是单数),而这件事
25
+ * 要看两处:`preToolUse` 记本轮最后一次 `Todo` 的入参,`observe` 在收尾时
26
+ * 判断并投递。两个类共用 `turnState` 里的**同一个槽**(键 `TODO_SETTLE_STATE_KEY`
27
+ * ——`turnStateOf` 那条「键用插件自己的 name」的规矩在这里让位于「一个扩展一个
28
+ * 槽」,两半的 name 各不相同、槽只有一个)。
29
+ *
30
+ * ## 三道闸门(改反了要么来回催、要么催不动)
31
+ *
32
+ * 1. **本轮写过清单才提醒**:从没写过、或上一轮遗留的未完成本轮没碰,都不管。
33
+ * 后者没有更好的判据——再催一次的收益比不上把每一轮都变成两轮的代价。
34
+ * 2. **回应提醒的那一轮只有「有推进」才再催**:提醒里带着投出时的完成数
35
+ * (`metadata.completed`),本轮收尾时完成数比它大才允许再投。最初的版本是
36
+ * 「回应提醒的那轮一律不催」,真机上模型被催着做完一条后**又**停下来问,第二次
37
+ * 提醒就被挡掉了(会话 `621632d1`)。改成按推进判:模型每被催一次至少多做完
38
+ * 一条,清单至多 50 条,所以有界;模型答「确实在等用户」而不动清单,完成数
39
+ * 不涨,立刻停催——没有死循环的口子。
40
+ * 3. **只管根会话**(`depth === 0`):子会话收尾后父会立刻拿它最后一条 assistant
41
+ * 行当终态(`finalizeIfIdle`),再往它 inbox 投东西会多出一轮、多出一份回执。
42
+ *
43
+ * 只在 `replied`(正常收尾)上投:中断与失败的一轮,模型没把话说完,清单状态本
44
+ * 来就说不上「做没做完」。
45
+ *
46
+ * **接受的代价**:模型合法地停下来等用户(用户明说「先只做第一步」、或它真需要
47
+ * 一个决定)时,也会收到一次提醒并回一句「在等你」——一次换轮、一条标记、一句话。
48
+ * 换来的是「列了清单就会做完」这条用户可以依赖的默契。
49
+ */
50
+ import { turnStateOf, } from '../hooks/turn-hook.types.js';
51
+ import { TODO_REMINDER_KIND } from '../schema/index.js';
52
+ import { TODO_TOOL_NAME } from '../tools/builtin-names.js';
53
+ import { parseTodoInput } from './todo-schema.js';
54
+ /** 两半共用的 `turnState` 键(见文件头「两半合一个扩展」)。 */
55
+ export const TODO_SETTLE_STATE_KEY = 'todo-settle';
56
+ /**
57
+ * 记账半:记下本轮最后一次 `Todo` 的入参。
58
+ *
59
+ * **记在发起处、不看结果**:被拒绝的那次(两条 in_progress)同样记——它的清单里
60
+ * 必然有没做完的,收尾时会因此提醒,而模型正该借这一轮把清单修好。
61
+ */
62
+ export const TODO_SETTLE_TRACK_META = {
63
+ name: 'todo-settle-track',
64
+ point: 'preToolUse',
65
+ tools: [TODO_TOOL_NAME],
66
+ order: 20,
67
+ onError: 'open',
68
+ };
69
+ export class TodoSettleTrackHook {
70
+ preToolUse(ctx, _toolName, input) {
71
+ const state = turnStateOf(ctx, TODO_SETTLE_STATE_KEY, () => ({ lastInput: undefined }));
72
+ state.lastInput = input;
73
+ return Promise.resolve({ action: 'continue' });
74
+ }
75
+ }
76
+ /**
77
+ * 投递半:收尾时清单里还有没做完的就投提醒、唤醒。
78
+ *
79
+ * 投递用 `MessageHub.post` + `WakeChannel.wake`,与子 Agent 回投同一条路
80
+ * (`SubagentSessions.finalizeIfIdle`);本轮此刻还持有会话锁,wake 只是让 loop 在
81
+ * 释放锁后的那次自查里看到有货。
82
+ */
83
+ export const TODO_SETTLE_REMINDER_META = {
84
+ name: 'todo-settle-reminder',
85
+ point: 'observe',
86
+ order: 20,
87
+ onError: 'open',
88
+ };
89
+ export class TodoSettleReminderHook {
90
+ hub;
91
+ waker;
92
+ constructor(hub, waker) {
93
+ this.hub = hub;
94
+ this.waker = waker;
95
+ }
96
+ async observe(ctx, phase) {
97
+ if (phase !== 'replied')
98
+ return;
99
+ if (ctx.depth !== 0)
100
+ return;
101
+ const state = ctx.turnState.get(TODO_SETTLE_STATE_KEY);
102
+ if (!state)
103
+ return;
104
+ const digest = digestTodos(state.lastInput);
105
+ if (digest.unfinished.length === 0)
106
+ return;
107
+ if (!hasProgressSinceReminder(ctx, digest.completed))
108
+ return;
109
+ await this.hub.post({
110
+ sessionId: ctx.sessionId,
111
+ kind: 'system_reminder',
112
+ sourceKind: 'system',
113
+ // `completed` 随行落进 metadata,回应这条提醒的那一轮据此判「有没有推进」
114
+ // (闸门 2)。前端只读 `kind`。
115
+ source: {
116
+ kind: TODO_REMINDER_KIND,
117
+ completed: digest.completed,
118
+ total: digest.total,
119
+ },
120
+ parts: [{ type: 'text', text: renderTodoSettleReminder(digest) }],
121
+ });
122
+ await this.waker.wake(ctx.sessionId);
123
+ }
124
+ }
125
+ /** 一份入参的三个数;形状对不上(半截、老版本)按空清单处理。 */
126
+ export function digestTodos(input) {
127
+ const items = parseTodoInput(input) ?? [];
128
+ const unfinished = items.filter(t => t.status !== 'completed');
129
+ return {
130
+ total: items.length,
131
+ completed: items.length - unfinished.length,
132
+ unfinished,
133
+ active: items.find(t => t.status === 'in_progress') ?? null,
134
+ };
135
+ }
136
+ /**
137
+ * 闸门 2:这一轮不是在回应提醒 → 放行;是 → 只有完成数比提醒投出时大才放行。
138
+ *
139
+ * 提醒行的 `completed` 缺失(老数据、别处投的)按「没推进」处理——方向是宁可
140
+ * 少催一次,也不在拿不到判据时无限催。
141
+ */
142
+ export function hasProgressSinceReminder(ctx, completedNow) {
143
+ const reminder = ctx.inbound
144
+ .map(m => m.metadata)
145
+ .find(md => md?.kind === TODO_REMINDER_KIND);
146
+ if (!reminder)
147
+ return true;
148
+ const before = reminder.completed;
149
+ return typeof before === 'number' && completedNow > before;
150
+ }
151
+ /**
152
+ * 提醒文案。**说三件事**:还剩几条(点名进行中那条)、直接接着做别问要不要继续、
153
+ * 做完的要置 completed;再给一条出路——确实在等用户就说清在等什么、别动清单。
154
+ * 只说前三件的话,模型会为了「服从」把一条确实要等用户的事硬做下去或标成完成。
155
+ * 末句挡住最常见的画蛇添足:先把刚交付的正文复述一遍。
156
+ */
157
+ export function renderTodoSettleReminder(digest) {
158
+ const active = digest.active
159
+ ? `,其中「${digest.active.content}」仍是 in_progress`
160
+ : '';
161
+ return (`这一轮回复已经结束,但待办清单里还有 ${digest.unfinished.length} 条没做完` +
162
+ `(共 ${digest.total} 条)${active}。` +
163
+ '列了清单就意味着要连续做完它:如果不需要用户提供信息或做决定,直接接着做' +
164
+ '下一条,不要停下来问「要不要继续」;做完的条目用 Todo 置 completed' +
165
+ '(用正文交付的也算做完),其余条目原样带上。' +
166
+ '如果确实在等用户答复,说清在等什么即可,不必更新清单。' +
167
+ '不要复述已经交付的内容。');
168
+ }
169
+ /** 把待办推进提醒的两半挂到注册表上(runtime 的通用扩展,宿主可以不挂)。 */
170
+ export function registerTodoSettleHooks(hooks, deps) {
171
+ hooks.register(TODO_SETTLE_TRACK_META, new TodoSettleTrackHook());
172
+ hooks.register(TODO_SETTLE_REMINDER_META, new TodoSettleReminderHook(deps.hub, deps.wake));
173
+ }
174
+ //# sourceMappingURL=todo-settle.hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"todo-settle.hook.js","sourceRoot":"","sources":["../../src/builtins/todo-settle.hook.ts"],"names":[],"mappings":"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"}