@qjp88995/agent-runtime 0.0.0-stage → 0.1.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 (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 +55 -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,108 @@
1
+ import { z } from 'zod';
2
+
3
+ import {
4
+ isToolNamed,
5
+ TODO_FORMER_NAMES,
6
+ TODO_TOOL_NAME,
7
+ } from '../tools/builtin-names.js';
8
+
9
+ /**
10
+ * Agent 的待办清单 —— `Todo` 工具(原 `TodoWrite`)的入参形状,前后端共用。
11
+ *
12
+ * ## 它没有存储层,这是有意的
13
+ *
14
+ * 清单**不落业务表、不加 DDL、后端不持任何状态**:`Todo` 是纯记账工具,
15
+ * 一次调用把**整份清单**原样写进这次 tool-call 的入参,那条 `chat_message`
16
+ * 行就是它唯一的存放处。于是「当前清单」= 历史里最后一次 `Todo` 的入参,
17
+ * 前端按这个纯函数派生(`latestTodoList`)。
18
+ *
19
+ * 这么定的直接好处是它自动搭上了上下文预算那套机制:裁剪只把 tool-result 的
20
+ * **正文**换成存根、**tool-call 的入参原封不动**(见
21
+ * `parts-to-model-messages.ts`),所以清单被裁进阴影区之后模型照样看得见。
22
+ * 反过来,若把清单存去别处,就得再造一条「压缩之后把它送回上下文」的路
23
+ * —— Claude Code 正是因为存在会话文件里才必须那么做。
24
+ *
25
+ * ## 全量替换,没有增量
26
+ *
27
+ * 每次调用给的都是完整清单,改一条状态也要把五条一起发回来。少一个 patch
28
+ * 语义就少一整类「服务端与模型各持半份、谁也不知道对方改了什么」的 bug,
29
+ * 而代价(重发几十个 token)在这个体量下不值一提。**也正因为是全量,
30
+ * 才不需要一个读取工具**:最新一份就在模型自己上一次的入参里。
31
+ */
32
+
33
+ /**
34
+ * 一条待办的三态。
35
+ *
36
+ * 刻意只有三个:`pending` 还没开始、`in_progress` 正在做、`completed` 做完了。
37
+ * 「阻塞中」「已放弃」这类第四态每次都有人想加,但模型表达它们的地方是对话正文
38
+ * (说清为什么卡住),不是这个枚举——多一个状态就多一处界面要渲染、多一条
39
+ * 模型要判断的规则,而它换回来的信息,一句话本来就说得更清楚。
40
+ */
41
+ export const TODO_STATUSES = ['pending', 'in_progress', 'completed'] as const;
42
+ export type TodoStatus = (typeof TODO_STATUSES)[number];
43
+
44
+ /**
45
+ * 单条待办。**只有正文与状态两个字段**。
46
+ *
47
+ * 刻意不要 Claude Code 那个 `activeForm`(同一件事的进行时说法,「加工具」→
48
+ * 「正在加工具」):那是终端底部那行 spinner 逼出来的字段——一行的地方放不下
49
+ * 整份清单,只能显示当前这条的进行时。我们的界面上进行中那条本来就带着描边
50
+ * 待在清单里,不缺这个提示,而多一个字段就是多一份模型每次都要写对的东西。
51
+ */
52
+ export const TodoItemSchema = z.object({
53
+ /**
54
+ * 一句话说清这一步要做什么。
55
+ *
56
+ * 200 字符上限是**拒绝**不是截断:清单是拿来扫的,一条写成一段的待办在面板
57
+ * 里会挤掉其余全部,而截断会把「做什么」最关键的后半句吃掉、还看不出被吃过。
58
+ */
59
+ content: z.string().trim().min(1).max(200),
60
+ status: z.enum(TODO_STATUSES),
61
+ });
62
+ export type TodoItem = z.infer<typeof TodoItemSchema>;
63
+
64
+ /**
65
+ * 整份清单。**顺序原样保留**——那是任务的依赖顺序(先定 schema 才谈得上写
66
+ * 实现),工具与后端一律不重排。界面按状态分组显示是另一层的取舍,且只重排
67
+ * 组、不动组内(见 portal / web 的待办面板)。
68
+ *
69
+ * 50 条上限同样是拒绝:真拆到 50 步的任务,缺的是再拆一层子任务(或派个子
70
+ * Agent),不是更长的清单。
71
+ */
72
+ export const TodoListSchema = z.array(TodoItemSchema).max(50);
73
+
74
+ /**
75
+ * 从一次 `Todo` 调用的入参里取出清单。
76
+ *
77
+ * **必须走 zod 而不是 `as`**,且有两处**都会正常发生**、必须落到 null 的情形:
78
+ *
79
+ * 1. **参数还在流式生成**:`tool-call` 事件要等整个 step 的流消费完才发,在那
80
+ * 之前入参是半截的(甚至是 `undefined`)。
81
+ * 2. **历史形状变过**:老会话里存的是当时那一版的入参。
82
+ *
83
+ * 两者都返回 null,由调用方决定怎么办——面板的做法是**继续用上一份**而不是
84
+ * 清空,否则每更新一次待办,面板就会闪一下空白再长回来。
85
+ */
86
+ export function parseTodoInput(input: unknown): TodoItem[] | null {
87
+ if (input === null || typeof input !== 'object') return null;
88
+ const raw = (input as Record<string, unknown>).todos;
89
+ const parsed = TodoListSchema.safeParse(raw);
90
+ return parsed.success ? parsed.data : null;
91
+ }
92
+
93
+ /**
94
+ * 当前清单 = 历史里最后一次 `Todo` 调用的入参(现名或旧名都认)。`calls` 按发生顺序给;
95
+ * 最后一次解析不了(还在流式生成 / 老形状)就往前找上一份——面板**继续用上一份**而不是
96
+ * 清空,否则每更新一次待办就闪一下空白。一次都没有返回 null。
97
+ */
98
+ export function latestTodoList(
99
+ calls: ReadonlyArray<{ toolName: string; input: unknown }>
100
+ ): TodoItem[] | null {
101
+ for (let i = calls.length - 1; i >= 0; i--) {
102
+ const c = calls[i];
103
+ if (!isToolNamed(c.toolName, TODO_TOOL_NAME, TODO_FORMER_NAMES)) continue;
104
+ const items = parseTodoInput(c.input);
105
+ if (items) return items;
106
+ }
107
+ return null;
108
+ }
@@ -0,0 +1,221 @@
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
+
51
+ import type { TurnHookRegistry } from '../hooks/turn-hook.registry.js';
52
+ import {
53
+ type ObservePhase,
54
+ type PreToolUseResult,
55
+ type TurnContext,
56
+ type TurnHookImpl,
57
+ type TurnHookMeta,
58
+ turnStateOf,
59
+ } from '../hooks/turn-hook.types.js';
60
+ import type { MessageHub } from '../loop/message-hub.js';
61
+ import type { WakeChannel } from '../ports/coordination.js';
62
+ import { TODO_REMINDER_KIND } from '../schema/index.js';
63
+ import { TODO_TOOL_NAME } from '../tools/builtin-names.js';
64
+ import { parseTodoInput, type TodoItem } from './todo-schema.js';
65
+
66
+ /** 两半共用的 `turnState` 键(见文件头「两半合一个扩展」)。 */
67
+ export const TODO_SETTLE_STATE_KEY = 'todo-settle';
68
+
69
+ interface TodoSettleState {
70
+ /** 本轮最后一次 `Todo` 的入参(原样,解析放到收尾时做)。 */
71
+ lastInput: unknown;
72
+ }
73
+
74
+ /**
75
+ * 记账半:记下本轮最后一次 `Todo` 的入参。
76
+ *
77
+ * **记在发起处、不看结果**:被拒绝的那次(两条 in_progress)同样记——它的清单里
78
+ * 必然有没做完的,收尾时会因此提醒,而模型正该借这一轮把清单修好。
79
+ */
80
+ export const TODO_SETTLE_TRACK_META: TurnHookMeta = {
81
+ name: 'todo-settle-track',
82
+ point: 'preToolUse',
83
+ tools: [TODO_TOOL_NAME],
84
+ order: 20,
85
+ onError: 'open',
86
+ };
87
+
88
+ export class TodoSettleTrackHook implements TurnHookImpl {
89
+ preToolUse(
90
+ ctx: TurnContext,
91
+ _toolName: string,
92
+ input: unknown
93
+ ): Promise<PreToolUseResult> {
94
+ const state = turnStateOf<TodoSettleState>(
95
+ ctx,
96
+ TODO_SETTLE_STATE_KEY,
97
+ () => ({ lastInput: undefined })
98
+ );
99
+ state.lastInput = input;
100
+ return Promise.resolve({ action: 'continue' });
101
+ }
102
+ }
103
+
104
+ /**
105
+ * 投递半:收尾时清单里还有没做完的就投提醒、唤醒。
106
+ *
107
+ * 投递用 `MessageHub.post` + `WakeChannel.wake`,与子 Agent 回投同一条路
108
+ * (`SubagentSessions.finalizeIfIdle`);本轮此刻还持有会话锁,wake 只是让 loop 在
109
+ * 释放锁后的那次自查里看到有货。
110
+ */
111
+ export const TODO_SETTLE_REMINDER_META: TurnHookMeta = {
112
+ name: 'todo-settle-reminder',
113
+ point: 'observe',
114
+ order: 20,
115
+ onError: 'open',
116
+ };
117
+
118
+ export class TodoSettleReminderHook implements TurnHookImpl {
119
+ constructor(
120
+ private readonly hub: MessageHub,
121
+ private readonly waker: Pick<WakeChannel, 'wake'>
122
+ ) {}
123
+
124
+ async observe(ctx: TurnContext, phase: ObservePhase): Promise<void> {
125
+ if (phase !== 'replied') return;
126
+ if (ctx.depth !== 0) return;
127
+ const state = ctx.turnState.get(TODO_SETTLE_STATE_KEY) as
128
+ TodoSettleState | undefined;
129
+ if (!state) return;
130
+ const digest = digestTodos(state.lastInput);
131
+ if (digest.unfinished.length === 0) return;
132
+ if (!hasProgressSinceReminder(ctx, digest.completed)) return;
133
+
134
+ await this.hub.post({
135
+ sessionId: ctx.sessionId,
136
+ kind: 'system_reminder',
137
+ sourceKind: 'system',
138
+ // `completed` 随行落进 metadata,回应这条提醒的那一轮据此判「有没有推进」
139
+ // (闸门 2)。前端只读 `kind`。
140
+ source: {
141
+ kind: TODO_REMINDER_KIND,
142
+ completed: digest.completed,
143
+ total: digest.total,
144
+ },
145
+ parts: [{ type: 'text', text: renderTodoSettleReminder(digest) }],
146
+ });
147
+ await this.waker.wake(ctx.sessionId);
148
+ }
149
+ }
150
+
151
+ export interface TodoDigest {
152
+ total: number;
153
+ completed: number;
154
+ /** 没做完的(进行中 + 未开始),保持清单原序。 */
155
+ unfinished: TodoItem[];
156
+ /** 正在做的那条;零条合法。 */
157
+ active: TodoItem | null;
158
+ }
159
+
160
+ /** 一份入参的三个数;形状对不上(半截、老版本)按空清单处理。 */
161
+ export function digestTodos(input: unknown): TodoDigest {
162
+ const items = parseTodoInput(input) ?? [];
163
+ const unfinished = items.filter(t => t.status !== 'completed');
164
+ return {
165
+ total: items.length,
166
+ completed: items.length - unfinished.length,
167
+ unfinished,
168
+ active: items.find(t => t.status === 'in_progress') ?? null,
169
+ };
170
+ }
171
+
172
+ /**
173
+ * 闸门 2:这一轮不是在回应提醒 → 放行;是 → 只有完成数比提醒投出时大才放行。
174
+ *
175
+ * 提醒行的 `completed` 缺失(老数据、别处投的)按「没推进」处理——方向是宁可
176
+ * 少催一次,也不在拿不到判据时无限催。
177
+ */
178
+ export function hasProgressSinceReminder(
179
+ ctx: Pick<TurnContext, 'inbound'>,
180
+ completedNow: number
181
+ ): boolean {
182
+ const reminder = ctx.inbound
183
+ .map(m => m.metadata)
184
+ .find(md => md?.kind === TODO_REMINDER_KIND);
185
+ if (!reminder) return true;
186
+ const before = reminder.completed;
187
+ return typeof before === 'number' && completedNow > before;
188
+ }
189
+
190
+ /**
191
+ * 提醒文案。**说三件事**:还剩几条(点名进行中那条)、直接接着做别问要不要继续、
192
+ * 做完的要置 completed;再给一条出路——确实在等用户就说清在等什么、别动清单。
193
+ * 只说前三件的话,模型会为了「服从」把一条确实要等用户的事硬做下去或标成完成。
194
+ * 末句挡住最常见的画蛇添足:先把刚交付的正文复述一遍。
195
+ */
196
+ export function renderTodoSettleReminder(digest: TodoDigest): string {
197
+ const active = digest.active
198
+ ? `,其中「${digest.active.content}」仍是 in_progress`
199
+ : '';
200
+ return (
201
+ `这一轮回复已经结束,但待办清单里还有 ${digest.unfinished.length} 条没做完` +
202
+ `(共 ${digest.total} 条)${active}。` +
203
+ '列了清单就意味着要连续做完它:如果不需要用户提供信息或做决定,直接接着做' +
204
+ '下一条,不要停下来问「要不要继续」;做完的条目用 Todo 置 completed' +
205
+ '(用正文交付的也算做完),其余条目原样带上。' +
206
+ '如果确实在等用户答复,说清在等什么即可,不必更新清单。' +
207
+ '不要复述已经交付的内容。'
208
+ );
209
+ }
210
+
211
+ /** 把待办推进提醒的两半挂到注册表上(runtime 的通用扩展,宿主可以不挂)。 */
212
+ export function registerTodoSettleHooks(
213
+ hooks: TurnHookRegistry,
214
+ deps: { hub: MessageHub; wake: Pick<WakeChannel, 'wake'> }
215
+ ): void {
216
+ hooks.register(TODO_SETTLE_TRACK_META, new TodoSettleTrackHook());
217
+ hooks.register(
218
+ TODO_SETTLE_REMINDER_META,
219
+ new TodoSettleReminderHook(deps.hub, deps.wake)
220
+ );
221
+ }
@@ -0,0 +1,134 @@
1
+ import { z } from 'zod';
2
+
3
+ import { AgentTool } from '../tools/agent-tool.base.js';
4
+ import { TODO_FORMER_NAMES, TODO_TOOL_NAME } from '../tools/builtin-names.js';
5
+ import type { ToolMeta } from '../tools/tool-meta.js';
6
+ import type { ToolRegistry } from '../tools/tool-registry.js';
7
+ import { toolError, type ToolOut } from '../tools/tool-result.js';
8
+ import {
9
+ type TodoItem,
10
+ TodoListSchema,
11
+ type TodoStatus,
12
+ } from './todo-schema.js';
13
+
14
+ const InputSchema = z.object({
15
+ todos: TodoListSchema.describe(
16
+ '完整的待办清单,按执行顺序排列。每次都要给全份——本次入参会整份取代上一份。'
17
+ ),
18
+ });
19
+ type Input = z.infer<typeof InputSchema>;
20
+
21
+ interface Out {
22
+ todos: TodoItem[];
23
+ }
24
+
25
+ /** 状态 → 回执里的说法。清单本身的顺序不动,这只是计数时的分组名。 */
26
+ const STATUS_LABELS: Record<TodoStatus, string> = {
27
+ in_progress: '进行中',
28
+ pending: '未开始',
29
+ completed: '已完成',
30
+ };
31
+
32
+ /**
33
+ * 待办清单记账工具的登记信息。
34
+ *
35
+ * **它没有 service、不写任何表、没有副作用**——这次调用的入参就是清单本身的
36
+ * 存放处(判据全文见 `todo-schema.ts`)。所以 `run()` 里除了
37
+ * 一道守卫之外无事可做,这不是没写完。
38
+ *
39
+ * 它同时是第一个声明 `accounting: true` 的工具:记账不算「做了别的事」,
40
+ * 夹在两次相同调用中间不该打断重复调用链的计数(见 `runtime/loop-reminder.ts`)。
41
+ */
42
+ export const TODO_TOOL_META: ToolMeta = {
43
+ name: TODO_TOOL_NAME,
44
+ formerNames: TODO_FORMER_NAMES,
45
+ description:
46
+ '把当前任务拆成一份待办清单,并在推进过程中随时更新它。多步骤、要跨很多次' +
47
+ '工具调用才能收尾的活儿用它记账:既让你自己不丢步骤,用户也能在界面上看到' +
48
+ '进度。**每次都要发完整清单**——只改一条的状态也要把其余各条一并带上,' +
49
+ '本次入参会整份取代上一份。' +
50
+ '**列清单之前先把要用户拍板的事问清**(范围、粒度、口径这类),或者自己定' +
51
+ '一个合理默认并写明;不要开工之后做到一半再回头问。' +
52
+ '**一条一条来**:开始做某一条时把它置 in_progress,这一条的正文写完就立刻' +
53
+ '再调一次把它置 completed、把下一条置 in_progress,然后才写下一条——' +
54
+ '不要把几条的内容写在同一段正文里再一起改状态;同一时刻至多一条 in_progress。' +
55
+ '**列了清单就意味着你会连续做完它**:做完一条紧接着做下一条,不要每完成' +
56
+ '一条就停下来问「要不要继续」——只有需要用户提供信息或做决定时才停,并说清' +
57
+ '在等什么。**结束回复之前必须结账**:正文交付的条目,正文写完就算做完,' +
58
+ '收尾前把它置 completed,不要留到用户下一句话再改。' +
59
+ '三两步就能答完的请求不必用它,为此记账反而更慢。',
60
+ category: 'system',
61
+ // 纯记账、零副作用 → 对重复调用链透明(见 `ToolMeta.accounting`)。
62
+ accounting: true,
63
+ };
64
+
65
+ /** 待办清单记账工具(原名见 `TODO_FORMER_NAMES`)。 */
66
+ export class TodoTool extends AgentTool<Input, Out> {
67
+ readonly inputSchema = InputSchema;
68
+
69
+ protected run(input: Input): Promise<ToolOut<Out>> {
70
+ const running = input.todos.filter(t => t.status === 'in_progress');
71
+ // 至多一条「进行中」。**拒绝而不是替它挑一条**:多条并行进行中在界面上会让
72
+ // 「现在做到哪了」这个问题失去唯一答案,而模型实际上就是一次做一件事。
73
+ // 反过来**零条是合法的**——全部做完的那一次,以及刚列出计划还没动手的那
74
+ // 一次,都没有进行中的条目,把它也拦掉会逼出一条假的 in_progress。
75
+ if (running.length > 1) {
76
+ return Promise.resolve(
77
+ toolError(
78
+ `同一时刻至多一条待办可以是 in_progress,这次给了 ${running.length} 条:` +
79
+ `${running.map(t => t.content).join('、')}。` +
80
+ '挑一条正在做的置 in_progress,其余退回 pending。'
81
+ )
82
+ );
83
+ }
84
+ return Promise.resolve({ kind: 'ok', todos: input.todos });
85
+ }
86
+
87
+ /**
88
+ * 回执**只给一行计数,不复述整份清单**。
89
+ *
90
+ * 清单原文就在这次调用的入参里,模型下一步照样看得见;把它在输出里再抄一遍
91
+ * 是纯粹的重复计费。而这条回执本身还会在裁剪时被换成存根(入参不会),
92
+ * 所以复述的那份清单是活不过裁剪的那一份。
93
+ */
94
+ protected render(out: { kind: 'ok' } & Out): string {
95
+ if (out.todos.length === 0) {
96
+ return '待办清单已清空。';
97
+ }
98
+ const counts = new Map<TodoStatus, number>();
99
+ for (const t of out.todos) {
100
+ counts.set(t.status, (counts.get(t.status) ?? 0) + 1);
101
+ }
102
+ // 按 STATUS_LABELS 的键序(进行中 → 未开始 → 已完成)报,且**零的那档不报**
103
+ // ——「已完成 0 条」是噪音,而没有进行中的条目本就是合法状态。
104
+ const parts = (Object.keys(STATUS_LABELS) as TodoStatus[])
105
+ .filter(s => (counts.get(s) ?? 0) > 0)
106
+ .map(s => `${STATUS_LABELS[s]} ${counts.get(s) ?? 0}`);
107
+ const summary = `待办清单已更新,共 ${out.todos.length} 条(${parts.join(' / ')})。`;
108
+ // 有进行中的那条就顺带提一句结账。**放在回执里而不是只写在 description**:
109
+ // 模型读这句话的时刻恰好是它要动手做这条的前一刻,而 description 在几十轮
110
+ // 之前的 system prompt 里。真正的兜底在收尾时(`extensions/todo-settle.hook.ts`),
111
+ // 这句是零成本的那一层——它管用一次,就省下一整轮换轮。
112
+ const running = out.todos.find(t => t.status === 'in_progress');
113
+ if (!running) return summary;
114
+ const remaining = out.todos.filter(t => t.status === 'pending').length;
115
+ // 还有没开始的就顺带说「接着做别问」:模型最常见的走样是做完一条停下来问
116
+ // 「要不要继续」(会话 621632d1),而它读这句话的时刻正是决定做完这条之后
117
+ // 干什么的时刻。
118
+ const next =
119
+ remaining > 0
120
+ ? `更新完再写下一条(还有 ${remaining} 条没开始),一条一条来,不要停下来问要不要继续。`
121
+ : '';
122
+ return (
123
+ `${summary}「${running.content}」进行中——只写这一条的内容,写完立刻` +
124
+ `再调一次 Todo 把它置 completed(用正文交付的也算做完)。${next}`
125
+ );
126
+ }
127
+ }
128
+
129
+ /** 登记 `Todo`。 */
130
+ export function registerTodoTool(tools: ToolRegistry): TodoTool {
131
+ const tool = new TodoTool();
132
+ tools.register(TODO_TOOL_META, tool);
133
+ return tool;
134
+ }