@m4ike1/ion-agent-core 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 (370) hide show
  1. package/README.md +622 -0
  2. package/dist/agent-loop.d.ts +24 -0
  3. package/dist/agent-loop.d.ts.map +1 -0
  4. package/dist/agent-loop.js +560 -0
  5. package/dist/agent-loop.js.map +1 -0
  6. package/dist/agent.d.ts +122 -0
  7. package/dist/agent.d.ts.map +1 -0
  8. package/dist/agent.js +422 -0
  9. package/dist/agent.js.map +1 -0
  10. package/dist/harness/agent-harness.d.ts +716 -0
  11. package/dist/harness/agent-harness.d.ts.map +1 -0
  12. package/dist/harness/agent-harness.js +6 -0
  13. package/dist/harness/agent-harness.js.map +1 -0
  14. package/dist/harness/compaction/branch-summarization.d.ts +68 -0
  15. package/dist/harness/compaction/branch-summarization.d.ts.map +1 -0
  16. package/dist/harness/compaction/branch-summarization.js +176 -0
  17. package/dist/harness/compaction/branch-summarization.js.map +1 -0
  18. package/dist/harness/compaction/compaction.d.ts +126 -0
  19. package/dist/harness/compaction/compaction.d.ts.map +1 -0
  20. package/dist/harness/compaction/compaction.js +560 -0
  21. package/dist/harness/compaction/compaction.js.map +1 -0
  22. package/dist/harness/compaction/utils.d.ts +25 -0
  23. package/dist/harness/compaction/utils.d.ts.map +1 -0
  24. package/dist/harness/compaction/utils.js +120 -0
  25. package/dist/harness/compaction/utils.js.map +1 -0
  26. package/dist/harness/config.d.ts +9 -0
  27. package/dist/harness/config.d.ts.map +1 -0
  28. package/dist/harness/config.js +35 -0
  29. package/dist/harness/config.js.map +1 -0
  30. package/dist/harness/context.d.ts +9 -0
  31. package/dist/harness/context.d.ts.map +1 -0
  32. package/dist/harness/context.js +13 -0
  33. package/dist/harness/context.js.map +1 -0
  34. package/dist/harness/env/nodejs.d.ts +43 -0
  35. package/dist/harness/env/nodejs.d.ts.map +1 -0
  36. package/dist/harness/env/nodejs.js +865 -0
  37. package/dist/harness/env/nodejs.js.map +1 -0
  38. package/dist/harness/events.d.ts +25 -0
  39. package/dist/harness/events.d.ts.map +1 -0
  40. package/dist/harness/events.js +250 -0
  41. package/dist/harness/events.js.map +1 -0
  42. package/dist/harness/execution/assistant.d.ts +42 -0
  43. package/dist/harness/execution/assistant.d.ts.map +1 -0
  44. package/dist/harness/execution/assistant.js +82 -0
  45. package/dist/harness/execution/assistant.js.map +1 -0
  46. package/dist/harness/execution/effect-gate.d.ts +22 -0
  47. package/dist/harness/execution/effect-gate.d.ts.map +1 -0
  48. package/dist/harness/execution/effect-gate.js +49 -0
  49. package/dist/harness/execution/effect-gate.js.map +1 -0
  50. package/dist/harness/execution/tools.d.ts +67 -0
  51. package/dist/harness/execution/tools.d.ts.map +1 -0
  52. package/dist/harness/execution/tools.js +121 -0
  53. package/dist/harness/execution/tools.js.map +1 -0
  54. package/dist/harness/hooks.d.ts +38 -0
  55. package/dist/harness/hooks.d.ts.map +1 -0
  56. package/dist/harness/hooks.js +406 -0
  57. package/dist/harness/hooks.js.map +1 -0
  58. package/dist/harness/messages.d.ts +51 -0
  59. package/dist/harness/messages.d.ts.map +1 -0
  60. package/dist/harness/messages.js +102 -0
  61. package/dist/harness/messages.js.map +1 -0
  62. package/dist/harness/prompt-templates.d.ts +49 -0
  63. package/dist/harness/prompt-templates.d.ts.map +1 -0
  64. package/dist/harness/prompt-templates.js +225 -0
  65. package/dist/harness/prompt-templates.js.map +1 -0
  66. package/dist/harness/result.d.ts +133 -0
  67. package/dist/harness/result.d.ts.map +1 -0
  68. package/dist/harness/result.js +81 -0
  69. package/dist/harness/result.js.map +1 -0
  70. package/dist/harness/runtime/drive/boundary.d.ts +28 -0
  71. package/dist/harness/runtime/drive/boundary.d.ts.map +1 -0
  72. package/dist/harness/runtime/drive/boundary.js +173 -0
  73. package/dist/harness/runtime/drive/boundary.js.map +1 -0
  74. package/dist/harness/runtime/drive/checkpoint.d.ts +8 -0
  75. package/dist/harness/runtime/drive/checkpoint.d.ts.map +1 -0
  76. package/dist/harness/runtime/drive/checkpoint.js +133 -0
  77. package/dist/harness/runtime/drive/checkpoint.js.map +1 -0
  78. package/dist/harness/runtime/drive/deferred.d.ts +15 -0
  79. package/dist/harness/runtime/drive/deferred.d.ts.map +1 -0
  80. package/dist/harness/runtime/drive/deferred.js +179 -0
  81. package/dist/harness/runtime/drive/deferred.js.map +1 -0
  82. package/dist/harness/runtime/drive/generation.d.ts +8 -0
  83. package/dist/harness/runtime/drive/generation.d.ts.map +1 -0
  84. package/dist/harness/runtime/drive/generation.js +205 -0
  85. package/dist/harness/runtime/drive/generation.js.map +1 -0
  86. package/dist/harness/runtime/drive/reconcile.d.ts +5 -0
  87. package/dist/harness/runtime/drive/reconcile.d.ts.map +1 -0
  88. package/dist/harness/runtime/drive/reconcile.js +140 -0
  89. package/dist/harness/runtime/drive/reconcile.js.map +1 -0
  90. package/dist/harness/runtime/drive/recovery.d.ts +8 -0
  91. package/dist/harness/runtime/drive/recovery.d.ts.map +1 -0
  92. package/dist/harness/runtime/drive/recovery.js +85 -0
  93. package/dist/harness/runtime/drive/recovery.js.map +1 -0
  94. package/dist/harness/runtime/drive/response.d.ts +23 -0
  95. package/dist/harness/runtime/drive/response.d.ts.map +1 -0
  96. package/dist/harness/runtime/drive/response.js +394 -0
  97. package/dist/harness/runtime/drive/response.js.map +1 -0
  98. package/dist/harness/runtime/drive/retry.d.ts +4 -0
  99. package/dist/harness/runtime/drive/retry.d.ts.map +1 -0
  100. package/dist/harness/runtime/drive/retry.js +34 -0
  101. package/dist/harness/runtime/drive/retry.js.map +1 -0
  102. package/dist/harness/runtime/drive/structural.d.ts +32 -0
  103. package/dist/harness/runtime/drive/structural.d.ts.map +1 -0
  104. package/dist/harness/runtime/drive/structural.js +929 -0
  105. package/dist/harness/runtime/drive/structural.js.map +1 -0
  106. package/dist/harness/runtime/drive/terminal.d.ts +7 -0
  107. package/dist/harness/runtime/drive/terminal.d.ts.map +1 -0
  108. package/dist/harness/runtime/drive/terminal.js +49 -0
  109. package/dist/harness/runtime/drive/terminal.js.map +1 -0
  110. package/dist/harness/runtime/drive/tool-placement.d.ts +14 -0
  111. package/dist/harness/runtime/drive/tool-placement.d.ts.map +1 -0
  112. package/dist/harness/runtime/drive/tool-placement.js +244 -0
  113. package/dist/harness/runtime/drive/tool-placement.js.map +1 -0
  114. package/dist/harness/runtime/drive/tools.d.ts +6 -0
  115. package/dist/harness/runtime/drive/tools.d.ts.map +1 -0
  116. package/dist/harness/runtime/drive/tools.js +449 -0
  117. package/dist/harness/runtime/drive/tools.js.map +1 -0
  118. package/dist/harness/runtime/drive.d.ts +6 -0
  119. package/dist/harness/runtime/drive.d.ts.map +1 -0
  120. package/dist/harness/runtime/drive.js +93 -0
  121. package/dist/harness/runtime/drive.js.map +1 -0
  122. package/dist/harness/runtime/harness.d.ts +59 -0
  123. package/dist/harness/runtime/harness.d.ts.map +1 -0
  124. package/dist/harness/runtime/harness.js +311 -0
  125. package/dist/harness/runtime/harness.js.map +1 -0
  126. package/dist/harness/runtime/index.d.ts +2 -0
  127. package/dist/harness/runtime/index.d.ts.map +1 -0
  128. package/dist/harness/runtime/index.js +2 -0
  129. package/dist/harness/runtime/index.js.map +1 -0
  130. package/dist/harness/runtime/lane.d.ts +101 -0
  131. package/dist/harness/runtime/lane.d.ts.map +1 -0
  132. package/dist/harness/runtime/lane.js +1575 -0
  133. package/dist/harness/runtime/lane.js.map +1 -0
  134. package/dist/harness/runtime/progress.d.ts +15 -0
  135. package/dist/harness/runtime/progress.d.ts.map +1 -0
  136. package/dist/harness/runtime/progress.js +66 -0
  137. package/dist/harness/runtime/progress.js.map +1 -0
  138. package/dist/harness/runtime/reducer.d.ts +5 -0
  139. package/dist/harness/runtime/reducer.d.ts.map +1 -0
  140. package/dist/harness/runtime/reducer.js +240 -0
  141. package/dist/harness/runtime/reducer.js.map +1 -0
  142. package/dist/harness/runtime/restore.d.ts +24 -0
  143. package/dist/harness/runtime/restore.d.ts.map +1 -0
  144. package/dist/harness/runtime/restore.js +117 -0
  145. package/dist/harness/runtime/restore.js.map +1 -0
  146. package/dist/harness/runtime/transcript.d.ts +21 -0
  147. package/dist/harness/runtime/transcript.d.ts.map +1 -0
  148. package/dist/harness/runtime/transcript.js +72 -0
  149. package/dist/harness/runtime/transcript.js.map +1 -0
  150. package/dist/harness/runtime/types.d.ts +105 -0
  151. package/dist/harness/runtime/types.d.ts.map +1 -0
  152. package/dist/harness/runtime/types.js +61 -0
  153. package/dist/harness/runtime/types.js.map +1 -0
  154. package/dist/harness/session/commit.d.ts +53 -0
  155. package/dist/harness/session/commit.d.ts.map +1 -0
  156. package/dist/harness/session/commit.js +57 -0
  157. package/dist/harness/session/commit.js.map +1 -0
  158. package/dist/harness/session/context.d.ts +10 -0
  159. package/dist/harness/session/context.d.ts.map +1 -0
  160. package/dist/harness/session/context.js +49 -0
  161. package/dist/harness/session/context.js.map +1 -0
  162. package/dist/harness/session/fork-policy.d.ts +21 -0
  163. package/dist/harness/session/fork-policy.d.ts.map +1 -0
  164. package/dist/harness/session/fork-policy.js +55 -0
  165. package/dist/harness/session/fork-policy.js.map +1 -0
  166. package/dist/harness/session/fork.d.ts +16 -0
  167. package/dist/harness/session/fork.d.ts.map +1 -0
  168. package/dist/harness/session/fork.js +79 -0
  169. package/dist/harness/session/fork.js.map +1 -0
  170. package/dist/harness/session/in-memory-storage-state.d.ts +39 -0
  171. package/dist/harness/session/in-memory-storage-state.d.ts.map +1 -0
  172. package/dist/harness/session/in-memory-storage-state.js +276 -0
  173. package/dist/harness/session/in-memory-storage-state.js.map +1 -0
  174. package/dist/harness/session/index.d.ts +11 -0
  175. package/dist/harness/session/index.d.ts.map +1 -0
  176. package/dist/harness/session/index.js +9 -0
  177. package/dist/harness/session/index.js.map +1 -0
  178. package/dist/harness/session/jsonl/codec.d.ts +21 -0
  179. package/dist/harness/session/jsonl/codec.d.ts.map +1 -0
  180. package/dist/harness/session/jsonl/codec.js +45 -0
  181. package/dist/harness/session/jsonl/codec.js.map +1 -0
  182. package/dist/harness/session/jsonl/fork.d.ts +38 -0
  183. package/dist/harness/session/jsonl/fork.d.ts.map +1 -0
  184. package/dist/harness/session/jsonl/fork.js +264 -0
  185. package/dist/harness/session/jsonl/fork.js.map +1 -0
  186. package/dist/harness/session/jsonl/index.d.ts +4 -0
  187. package/dist/harness/session/jsonl/index.d.ts.map +1 -0
  188. package/dist/harness/session/jsonl/index.js +4 -0
  189. package/dist/harness/session/jsonl/index.js.map +1 -0
  190. package/dist/harness/session/jsonl/io.d.ts +14 -0
  191. package/dist/harness/session/jsonl/io.d.ts.map +1 -0
  192. package/dist/harness/session/jsonl/io.js +86 -0
  193. package/dist/harness/session/jsonl/io.js.map +1 -0
  194. package/dist/harness/session/jsonl/legacy-v3.d.ts +43 -0
  195. package/dist/harness/session/jsonl/legacy-v3.d.ts.map +1 -0
  196. package/dist/harness/session/jsonl/legacy-v3.js +462 -0
  197. package/dist/harness/session/jsonl/legacy-v3.js.map +1 -0
  198. package/dist/harness/session/jsonl/repo.d.ts +35 -0
  199. package/dist/harness/session/jsonl/repo.d.ts.map +1 -0
  200. package/dist/harness/session/jsonl/repo.js +301 -0
  201. package/dist/harness/session/jsonl/repo.js.map +1 -0
  202. package/dist/harness/session/jsonl/storage.d.ts +40 -0
  203. package/dist/harness/session/jsonl/storage.d.ts.map +1 -0
  204. package/dist/harness/session/jsonl/storage.js +200 -0
  205. package/dist/harness/session/jsonl/storage.js.map +1 -0
  206. package/dist/harness/session/jsonl/types.d.ts +39 -0
  207. package/dist/harness/session/jsonl/types.d.ts.map +1 -0
  208. package/dist/harness/session/jsonl/types.js +3 -0
  209. package/dist/harness/session/jsonl/types.js.map +1 -0
  210. package/dist/harness/session/memory.d.ts +48 -0
  211. package/dist/harness/session/memory.d.ts.map +1 -0
  212. package/dist/harness/session/memory.js +369 -0
  213. package/dist/harness/session/memory.js.map +1 -0
  214. package/dist/harness/session/mutation-line.d.ts +8 -0
  215. package/dist/harness/session/mutation-line.d.ts.map +1 -0
  216. package/dist/harness/session/mutation-line.js +21 -0
  217. package/dist/harness/session/mutation-line.js.map +1 -0
  218. package/dist/harness/session/session.d.ts +82 -0
  219. package/dist/harness/session/session.d.ts.map +1 -0
  220. package/dist/harness/session/session.js +361 -0
  221. package/dist/harness/session/session.js.map +1 -0
  222. package/dist/harness/session/testing/benchmark/datasets.d.ts +12 -0
  223. package/dist/harness/session/testing/benchmark/datasets.d.ts.map +1 -0
  224. package/dist/harness/session/testing/benchmark/datasets.js +24 -0
  225. package/dist/harness/session/testing/benchmark/datasets.js.map +1 -0
  226. package/dist/harness/session/testing/benchmark/session-repo.d.ts +42 -0
  227. package/dist/harness/session/testing/benchmark/session-repo.d.ts.map +1 -0
  228. package/dist/harness/session/testing/benchmark/session-repo.js +127 -0
  229. package/dist/harness/session/testing/benchmark/session-repo.js.map +1 -0
  230. package/dist/harness/session/testing/benchmark/storage.d.ts +25 -0
  231. package/dist/harness/session/testing/benchmark/storage.d.ts.map +1 -0
  232. package/dist/harness/session/testing/benchmark/storage.js +114 -0
  233. package/dist/harness/session/testing/benchmark/storage.js.map +1 -0
  234. package/dist/harness/session/testing/conformance/session-repo.d.ts +23 -0
  235. package/dist/harness/session/testing/conformance/session-repo.d.ts.map +1 -0
  236. package/dist/harness/session/testing/conformance/session-repo.js +809 -0
  237. package/dist/harness/session/testing/conformance/session-repo.js.map +1 -0
  238. package/dist/harness/session/testing/conformance/storage.d.ts +4 -0
  239. package/dist/harness/session/testing/conformance/storage.d.ts.map +1 -0
  240. package/dist/harness/session/testing/conformance/storage.js +600 -0
  241. package/dist/harness/session/testing/conformance/storage.js.map +1 -0
  242. package/dist/harness/session/testing/gating-storage.d.ts +26 -0
  243. package/dist/harness/session/testing/gating-storage.d.ts.map +1 -0
  244. package/dist/harness/session/testing/gating-storage.js +100 -0
  245. package/dist/harness/session/testing/gating-storage.js.map +1 -0
  246. package/dist/harness/session/testing/index.d.ts +10 -0
  247. package/dist/harness/session/testing/index.d.ts.map +1 -0
  248. package/dist/harness/session/testing/index.js +9 -0
  249. package/dist/harness/session/testing/index.js.map +1 -0
  250. package/dist/harness/session/testing/instrumented-storage.d.ts +11 -0
  251. package/dist/harness/session/testing/instrumented-storage.d.ts.map +1 -0
  252. package/dist/harness/session/testing/instrumented-storage.js +16 -0
  253. package/dist/harness/session/testing/instrumented-storage.js.map +1 -0
  254. package/dist/harness/session/testing/storage-decorator.d.ts +20 -0
  255. package/dist/harness/session/testing/storage-decorator.d.ts.map +1 -0
  256. package/dist/harness/session/testing/storage-decorator.js +41 -0
  257. package/dist/harness/session/testing/storage-decorator.js.map +1 -0
  258. package/dist/harness/session/testing/types.d.ts +12 -0
  259. package/dist/harness/session/testing/types.d.ts.map +1 -0
  260. package/dist/harness/session/testing/types.js +2 -0
  261. package/dist/harness/session/testing/types.js.map +1 -0
  262. package/dist/harness/session/types.d.ts +512 -0
  263. package/dist/harness/session/types.d.ts.map +1 -0
  264. package/dist/harness/session/types.js +9 -0
  265. package/dist/harness/session/types.js.map +1 -0
  266. package/dist/harness/session/values.d.ts +95 -0
  267. package/dist/harness/session/values.d.ts.map +1 -0
  268. package/dist/harness/session/values.js +81 -0
  269. package/dist/harness/session/values.js.map +1 -0
  270. package/dist/harness/skills.d.ts +46 -0
  271. package/dist/harness/skills.d.ts.map +1 -0
  272. package/dist/harness/skills.js +326 -0
  273. package/dist/harness/skills.js.map +1 -0
  274. package/dist/harness/system-prompt.d.ts +3 -0
  275. package/dist/harness/system-prompt.d.ts.map +1 -0
  276. package/dist/harness/system-prompt.js +30 -0
  277. package/dist/harness/system-prompt.js.map +1 -0
  278. package/dist/harness/telemetry.d.ts +1242 -0
  279. package/dist/harness/telemetry.d.ts.map +1 -0
  280. package/dist/harness/telemetry.js +527 -0
  281. package/dist/harness/telemetry.js.map +1 -0
  282. package/dist/harness/tools/bash.d.ts +27 -0
  283. package/dist/harness/tools/bash.d.ts.map +1 -0
  284. package/dist/harness/tools/bash.js +105 -0
  285. package/dist/harness/tools/bash.js.map +1 -0
  286. package/dist/harness/tools/edit-diff.d.ts +89 -0
  287. package/dist/harness/tools/edit-diff.d.ts.map +1 -0
  288. package/dist/harness/tools/edit-diff.js +386 -0
  289. package/dist/harness/tools/edit-diff.js.map +1 -0
  290. package/dist/harness/tools/edit.d.ts +19 -0
  291. package/dist/harness/tools/edit.d.ts.map +1 -0
  292. package/dist/harness/tools/edit.js +108 -0
  293. package/dist/harness/tools/edit.js.map +1 -0
  294. package/dist/harness/tools/file-mutation-queue.d.ts +5 -0
  295. package/dist/harness/tools/file-mutation-queue.d.ts.map +1 -0
  296. package/dist/harness/tools/file-mutation-queue.js +46 -0
  297. package/dist/harness/tools/file-mutation-queue.js.map +1 -0
  298. package/dist/harness/tools/image.d.ts +3 -0
  299. package/dist/harness/tools/image.d.ts.map +1 -0
  300. package/dist/harness/tools/image.js +106 -0
  301. package/dist/harness/tools/image.js.map +1 -0
  302. package/dist/harness/tools/index.d.ts +6 -0
  303. package/dist/harness/tools/index.d.ts.map +1 -0
  304. package/dist/harness/tools/index.js +5 -0
  305. package/dist/harness/tools/index.js.map +1 -0
  306. package/dist/harness/tools/path-utils.d.ts +5 -0
  307. package/dist/harness/tools/path-utils.d.ts.map +1 -0
  308. package/dist/harness/tools/path-utils.js +26 -0
  309. package/dist/harness/tools/path-utils.js.map +1 -0
  310. package/dist/harness/tools/read.d.ts +35 -0
  311. package/dist/harness/tools/read.d.ts.map +1 -0
  312. package/dist/harness/tools/read.js +108 -0
  313. package/dist/harness/tools/read.js.map +1 -0
  314. package/dist/harness/tools/tool-context.d.ts +6 -0
  315. package/dist/harness/tools/tool-context.d.ts.map +1 -0
  316. package/dist/harness/tools/tool-context.js +2 -0
  317. package/dist/harness/tools/tool-context.js.map +1 -0
  318. package/dist/harness/tools/write.d.ts +11 -0
  319. package/dist/harness/tools/write.d.ts.map +1 -0
  320. package/dist/harness/tools/write.js +31 -0
  321. package/dist/harness/tools/write.js.map +1 -0
  322. package/dist/harness/types.d.ts +305 -0
  323. package/dist/harness/types.d.ts.map +1 -0
  324. package/dist/harness/types.js +75 -0
  325. package/dist/harness/types.js.map +1 -0
  326. package/dist/harness/utils/adaptive-publisher.d.ts +24 -0
  327. package/dist/harness/utils/adaptive-publisher.d.ts.map +1 -0
  328. package/dist/harness/utils/adaptive-publisher.js +79 -0
  329. package/dist/harness/utils/adaptive-publisher.js.map +1 -0
  330. package/dist/harness/utils/output-capture.d.ts +31 -0
  331. package/dist/harness/utils/output-capture.d.ts.map +1 -0
  332. package/dist/harness/utils/output-capture.js +217 -0
  333. package/dist/harness/utils/output-capture.js.map +1 -0
  334. package/dist/harness/utils/shell-output.d.ts +29 -0
  335. package/dist/harness/utils/shell-output.d.ts.map +1 -0
  336. package/dist/harness/utils/shell-output.js +71 -0
  337. package/dist/harness/utils/shell-output.js.map +1 -0
  338. package/dist/harness/utils/truncate.d.ts +71 -0
  339. package/dist/harness/utils/truncate.d.ts.map +1 -0
  340. package/dist/harness/utils/truncate.js +296 -0
  341. package/dist/harness/utils/truncate.js.map +1 -0
  342. package/dist/harness/utils/usage.d.ts +4 -0
  343. package/dist/harness/utils/usage.d.ts.map +1 -0
  344. package/dist/harness/utils/usage.js +33 -0
  345. package/dist/harness/utils/usage.js.map +1 -0
  346. package/dist/index.d.ts +28 -0
  347. package/dist/index.d.ts.map +1 -0
  348. package/dist/index.js +26 -0
  349. package/dist/index.js.map +1 -0
  350. package/dist/node.d.ts +3 -0
  351. package/dist/node.d.ts.map +1 -0
  352. package/dist/node.js +3 -0
  353. package/dist/node.js.map +1 -0
  354. package/dist/proxy.d.ts +72 -0
  355. package/dist/proxy.d.ts.map +1 -0
  356. package/dist/proxy.js +310 -0
  357. package/dist/proxy.js.map +1 -0
  358. package/dist/search/index.d.ts +29 -0
  359. package/dist/search/index.d.ts.map +1 -0
  360. package/dist/search/index.js +2 -0
  361. package/dist/search/index.js.map +1 -0
  362. package/dist/stream-fn.d.ts +10 -0
  363. package/dist/stream-fn.d.ts.map +1 -0
  364. package/dist/stream-fn.js +17 -0
  365. package/dist/stream-fn.js.map +1 -0
  366. package/dist/types.d.ts +416 -0
  367. package/dist/types.d.ts.map +1 -0
  368. package/dist/types.js +2 -0
  369. package/dist/types.js.map +1 -0
  370. package/package.json +89 -0
package/README.md ADDED
@@ -0,0 +1,622 @@
1
+ # @m4ike1/ion-agent-core
2
+
3
+ Stateful agent runtime with tool execution and event streaming. Built on `@m4ike1/ion-ai`.
4
+
5
+ The `Agent` class owns the transcript, runs the prompt → LLM → tool loop, and emits
6
+ lifecycle events for UI updates. For details see
7
+ [docs/how-to.md](docs/how-to.md) (recipes) and
8
+ [docs/api-reference.md](docs/api-reference.md) (API dictionary).
9
+ The durable conversation/session harness in this package is specified separately in
10
+ [docs/harness.md](docs/harness.md).
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ npm install @m4ike1/ion-agent-core
16
+ ```
17
+
18
+ ### Entrypoints
19
+
20
+ ```typescript
21
+ import { Agent } from "@m4ike1/ion-agent-core"; // core runtime (Agent, agentLoop, streamProxy, types)
22
+ import { NodeExecutionEnv } from "@m4ike1/ion-agent-core/node"; // Node execution env + everything above
23
+ import type { ... } from "@m4ike1/ion-agent-core/harness/session"; // session layer
24
+ import type { ... } from "@m4ike1/ion-agent-core/harness/session/testing"; // session test helpers
25
+ import { reduceLaneSnapshot } from "@m4ike1/ion-agent-core/harness/runtime/reducer";
26
+ import type { ... } from "@m4ike1/ion-agent-core/harness/context";
27
+ import { NodeExecutionEnv } from "@m4ike1/ion-agent-core/harness/env/nodejs";
28
+ ```
29
+
30
+ ### SQLite session backends
31
+
32
+ The SQLite session backend and the `node:sqlite` adapter live in a separate package,
33
+ `@m4ike1/ion-session-backend-sqlite-node`, so the core package does not pull in
34
+ runtime builtins or native SQLite dependencies by default. The backend accepts a
35
+ runtime-specific SQLite factory, allowing other session backends to ship as their
36
+ own packages in the future.
37
+
38
+ ## Quick Start
39
+
40
+ ```typescript
41
+ import { Agent } from "@m4ike1/ion-agent-core";
42
+ import { createModels } from "@m4ike1/ion-ai";
43
+ import { anthropicProvider } from "@m4ike1/ion-ai/providers/anthropic";
44
+
45
+ const models = createModels();
46
+ models.setProvider(anthropicProvider());
47
+ const model = models.getModel("anthropic", "claude-sonnet-4-6");
48
+ if (!model) throw new Error("Model not found");
49
+
50
+ const agent = new Agent({
51
+ initialState: {
52
+ systemPrompt: "You are a helpful assistant.",
53
+ model,
54
+ },
55
+ streamFn: models.streamSimple.bind(models),
56
+ });
57
+
58
+ agent.subscribe((event) => {
59
+ if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
60
+ // Stream just the new text chunk
61
+ process.stdout.write(event.assistantMessageEvent.delta);
62
+ }
63
+ });
64
+
65
+ await agent.prompt("Hello!");
66
+ ```
67
+
68
+ `streamFn` defaults to the function installed via `setDefaultStreamFn()` when omitted.
69
+ `Models.streamSimple` satisfies the `StreamFn` contract: never throw for
70
+ request/model/runtime failures; encode failures in the returned stream as a final
71
+ `AssistantMessage` with `stopReason` `"error"` / `"aborted"`.
72
+
73
+ ## Experimental facet services
74
+
75
+ Transport-neutral facet-service primitives live in `@m4ike1/chord`. The agent core
76
+ does not export the service runtime.
77
+
78
+ ## Core Concepts
79
+
80
+ ### AgentMessage vs LLM Message
81
+
82
+ The agent works with `AgentMessage`, a flexible type that can include:
83
+
84
+ - Standard LLM messages (`user`, `assistant`, `toolResult`)
85
+ - Custom app-specific message types via declaration merging
86
+
87
+ LLMs only understand `user`, `assistant`, and `toolResult`. The `convertToLlm`
88
+ function bridges this gap by filtering and transforming messages before each LLM call.
89
+ The default `convertToLlm` passes through only `user` / `assistant` / `toolResult`.
90
+
91
+ ### Message Flow
92
+
93
+ ```text
94
+ AgentMessage[] → transformContext() → AgentMessage[] → convertToLlm() → Message[] → LLM
95
+ (optional) (required)
96
+ ```
97
+
98
+ 1. **transformContext**: Prune old messages, inject external context
99
+ 2. **convertToLlm**: Filter out UI-only messages, convert custom types to LLM format
100
+
101
+ Both hooks must not throw or reject; return a safe fallback instead. A throwing
102
+ `convertToLlm`, `shouldStopAfterTurn`, or `prepareNextTurn` interrupts the low-level
103
+ loop without producing a normal event sequence.
104
+
105
+ ## Event Flow
106
+
107
+ The agent emits events for UI updates. Understanding the event sequence helps build
108
+ responsive interfaces.
109
+
110
+ ### prompt() Event Sequence
111
+
112
+ When you call `prompt("Hello")`:
113
+
114
+ ```text
115
+ prompt("Hello")
116
+ ├─ agent_start
117
+ ├─ turn_start
118
+ ├─ message_start { message: userMessage } // Your prompt
119
+ ├─ message_end { message: userMessage }
120
+ ├─ message_start { message: assistantMessage } // LLM starts responding
121
+ ├─ message_update { message: partial... } // Streaming chunks
122
+ ├─ message_update { message: partial... }
123
+ ├─ message_end { message: assistantMessage } // Complete response
124
+ ├─ turn_end { message, toolResults: [] }
125
+ └─ agent_end { messages: [...] }
126
+ ```
127
+
128
+ ### With Tool Calls
129
+
130
+ If the assistant calls tools, the loop continues:
131
+
132
+ ```text
133
+ prompt("Read config.json")
134
+ ├─ agent_start
135
+ ├─ turn_start
136
+ ├─ message_start/end { userMessage }
137
+ ├─ message_start { assistantMessage with toolCall }
138
+ ├─ message_update...
139
+ ├─ message_end { assistantMessage }
140
+ ├─ tool_execution_start { toolCallId, toolName, args }
141
+ ├─ tool_execution_update { partialResult } // If tool streams
142
+ ├─ tool_execution_end { toolCallId, result }
143
+ ├─ message_start/end { toolResultMessage }
144
+ ├─ turn_end { message, toolResults: [toolResult] }
145
+ │
146
+ ├─ turn_start // Next turn
147
+ ├─ message_start { assistantMessage } // LLM responds to tool result
148
+ ├─ message_update...
149
+ ├─ message_end
150
+ ├─ turn_end
151
+ └─ agent_end
152
+ ```
153
+
154
+ Tool execution mode is configurable:
155
+
156
+ - `parallel` (default): preflight tool calls sequentially, execute allowed tools
157
+ concurrently, emit `tool_execution_end` as soon as each tool is finalized, then
158
+ emit toolResult messages and `turn_end.toolResults` in assistant source order
159
+ - `sequential`: execute tool calls one by one, matching the historical behavior
160
+
161
+ In parallel mode, tool completion events follow tool completion order, but persisted
162
+ toolResult messages still follow assistant source order.
163
+
164
+ The mode can be set globally via `toolExecution` in the agent config, or per-tool
165
+ via `executionMode` on `AgentTool`. If any tool call in a batch targets a tool with
166
+ `executionMode: "sequential"`, the entire batch executes sequentially regardless of
167
+ the global setting.
168
+
169
+ The `beforeToolCall` hook runs after `tool_execution_start` and validated argument
170
+ parsing. It can block execution and attach `terminate: true` to the blocked result.
171
+ The `afterToolCall` hook runs after tool execution finishes and before
172
+ `tool_execution_end` and final tool result message events are emitted.
173
+
174
+ Tools, blocked `beforeToolCall` results, and `afterToolCall` overrides can return
175
+ `terminate: true` to hint that the automatic follow-up LLM call should be skipped.
176
+ The loop only stops early when every finalized tool result in that batch sets
177
+ `terminate: true`. Mixed batches continue normally.
178
+
179
+ When you use the `Agent` class, assistant `message_end` processing is treated as a
180
+ barrier before tool preflight begins. That means `beforeToolCall` sees agent state
181
+ that already includes the assistant message that requested the tool call.
182
+
183
+ ### Truncated responses
184
+
185
+ If the assistant message ends with `stopReason: "length"` (output token limit hit),
186
+ no tool call in that message is executed: streamed tool-call arguments may be
187
+ silently truncated, so each call is reported as an error result and the model is
188
+ asked to re-issue the calls with complete arguments.
189
+
190
+ ### continue() Event Sequence
191
+
192
+ `continue()` resumes from existing context without adding a new message. Use it for
193
+ retries after errors.
194
+
195
+ ```typescript
196
+ // After an error, retry from current state
197
+ await agent.continue();
198
+ ```
199
+
200
+ The last message in context must be `user` or `toolResult` (not `assistant`).
201
+ If the last message is `assistant` but a steering or follow-up message is queued,
202
+ `continue()` runs the queued message instead of throwing.
203
+
204
+ ### Event Types
205
+
206
+ | Event | Description |
207
+ |-------|-------------|
208
+ | `agent_start` | Agent begins processing |
209
+ | `agent_end` | Final event for the run. Awaited subscribers for this event still count toward settlement |
210
+ | `turn_start` | New turn begins (one LLM call + tool executions) |
211
+ | `turn_end` | Turn completes with assistant message and tool results |
212
+ | `message_start` | Any message begins (user, assistant, toolResult) |
213
+ | `message_update` | **Assistant only.** Includes `assistantMessageEvent` with delta |
214
+ | `message_end` | Message completes |
215
+ | `tool_execution_start` | Tool begins |
216
+ | `tool_execution_update` | Tool streams progress |
217
+ | `tool_execution_end` | Tool completes |
218
+
219
+ `Agent.subscribe()` listeners are awaited in registration order and receive the
220
+ active run's `AbortSignal`. `agent_end` means no more loop events will be emitted,
221
+ but `await agent.waitForIdle()` and `await agent.prompt(...)` only settle after
222
+ awaited `agent_end` listeners finish. Raw `agentLoop()` / `agentLoopContinue()`
223
+ streams are observational only: they preserve event order but do not wait for your
224
+ async event handling to settle before later producer phases continue.
225
+
226
+ ## Agent Options
227
+
228
+ See [docs/api-reference.md](docs/api-reference.md) for the full field dictionary.
229
+ Common setup:
230
+
231
+ ```typescript
232
+ const agent = new Agent({
233
+ // Initial state
234
+ initialState: {
235
+ systemPrompt: "You are a helpful assistant.",
236
+ model,
237
+ thinkingLevel: "medium", // "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max"
238
+ tools: [readFileTool],
239
+ messages: [],
240
+ },
241
+
242
+ // Convert AgentMessage[] to LLM Message[] (required for custom message types)
243
+ convertToLlm: (messages) => messages.filter(...),
244
+
245
+ // Transform context before convertToLlm (for pruning, compaction)
246
+ transformContext: async (messages, signal) => pruneOldMessages(messages),
247
+
248
+ // Steering mode: "one-at-a-time" (default) or "all"
249
+ steeringMode: "one-at-a-time",
250
+
251
+ // Follow-up mode: "one-at-a-time" (default) or "all"
252
+ followUpMode: "one-at-a-time",
253
+
254
+ // Stream function (falls back to setDefaultStreamFn() when omitted)
255
+ streamFn: models.streamSimple.bind(models),
256
+
257
+ // Session ID for provider caching
258
+ sessionId: "session-123",
259
+
260
+ // Dynamic API key resolution (for expiring OAuth tokens)
261
+ getApiKey: async (provider) => refreshToken(),
262
+
263
+ // Tool execution mode: "parallel" (default) or "sequential"
264
+ toolExecution: "parallel",
265
+
266
+ // Preflight each tool call after args are validated. Can block execution.
267
+ beforeToolCall: async ({ toolCall, args, context }) => {
268
+ if (toolCall.name === "bash") {
269
+ return { block: true, reason: "bash is disabled", terminate: true };
270
+ }
271
+ },
272
+
273
+ // Postprocess each tool result before final tool events are emitted.
274
+ afterToolCall: async ({ toolCall, result, isError, context }) => {
275
+ if (toolCall.name === "notify_done" && !isError) {
276
+ return { terminate: true };
277
+ }
278
+ if (!isError) {
279
+ return { details: { ...result.details, audited: true } };
280
+ }
281
+ },
282
+
283
+ // Stop gracefully after a completed turn, before queued messages are polled.
284
+ shouldStopAfterTurn: async ({ context }, signal) => {
285
+ return shouldCompactBeforeNextTurn(context.messages);
286
+ },
287
+
288
+ // Replace context/model/thinking state before the next turn starts.
289
+ prepareNextTurnWithContext: async ({ context, message }) => undefined,
290
+
291
+ // Custom thinking budgets for token-based providers
292
+ thinkingBudgets: {
293
+ minimal: 128,
294
+ low: 512,
295
+ medium: 1024,
296
+ high: 2048,
297
+ },
298
+ });
299
+ ```
300
+
301
+ The `Agent` class accepts `shouldStopAfterTurn` in `AgentOptions`. Low-level loop
302
+ callers set the same hook in `AgentLoopConfig`. It runs after `turn_end` is emitted
303
+ and after the assistant response and any tool executions have completed normally.
304
+ If it returns `true`, the loop emits `agent_end` and exits before polling steering
305
+ or follow-up queues, and before starting another LLM call. It does not abort the
306
+ provider stream, does not cancel running tools, and does not alter the assistant
307
+ message stop reason. The `AgentOptions` callback also receives the active run's
308
+ `AbortSignal` as its second argument.
309
+
310
+ ## Agent State
311
+
312
+ ```typescript
313
+ interface AgentState {
314
+ systemPrompt: string;
315
+ model: Model<any>;
316
+ thinkingLevel: ThinkingLevel;
317
+ tools: AgentTool<any>[];
318
+ messages: AgentMessage[];
319
+ readonly isStreaming: boolean;
320
+ readonly streamingMessage?: AgentMessage;
321
+ readonly pendingToolCalls: ReadonlySet<string>;
322
+ readonly errorMessage?: string;
323
+ }
324
+ ```
325
+
326
+ Access state via `agent.state`.
327
+
328
+ Assigning `agent.state.tools = [...]` or `agent.state.messages = [...]` copies the
329
+ top-level array before storing it. Mutating the returned array mutates the current
330
+ agent state.
331
+
332
+ During streaming, `agent.state.streamingMessage` contains the current partial
333
+ assistant message.
334
+
335
+ `agent.state.isStreaming` remains `true` until the run fully settles, including
336
+ awaited `agent_end` subscribers. `agent.state.errorMessage` holds the error message
337
+ from the most recent failed or aborted assistant turn, if any.
338
+
339
+ ## Methods
340
+
341
+ ### Prompting
342
+
343
+ ```typescript
344
+ // Text prompt
345
+ await agent.prompt("Hello");
346
+
347
+ // With images
348
+ await agent.prompt("What's in this image?", [
349
+ { type: "image", data: base64Data, mimeType: "image/jpeg" }
350
+ ]);
351
+
352
+ // AgentMessage directly
353
+ await agent.prompt({ role: "user", content: [{ type: "text", text: "Hello" }], timestamp: Date.now() });
354
+
355
+ // Batch of messages
356
+ await agent.prompt([msg1, msg2]);
357
+
358
+ // Continue from current context (last message must be user or toolResult)
359
+ await agent.continue();
360
+ ```
361
+
362
+ Only one run at a time: `prompt()` / `continue()` throw while a run is active. Use
363
+ `steer()` / `followUp()` to queue messages, or wait for completion. `reset()`
364
+ throws while a run is active.
365
+
366
+ ### State Management
367
+
368
+ ```typescript
369
+ agent.state.systemPrompt = "New prompt";
370
+ agent.state.model = getModel("openai", "gpt-4o");
371
+ agent.state.thinkingLevel = "medium";
372
+ agent.state.tools = [myTool];
373
+ agent.toolExecution = "sequential";
374
+ agent.beforeToolCall = async ({ toolCall }) => undefined;
375
+ agent.afterToolCall = async ({ toolCall, result }) => undefined;
376
+ agent.shouldStopAfterTurn = async ({ context }) => shouldCompactBeforeNextTurn(context.messages);
377
+ agent.state.messages = newMessages; // top-level array is copied
378
+ agent.state.messages.push(message);
379
+ agent.reset(); // clears transcript, runtime state, and both queues
380
+ ```
381
+
382
+ ### Session and Thinking Budgets
383
+
384
+ ```typescript
385
+ agent.sessionId = "session-123";
386
+
387
+ agent.thinkingBudgets = {
388
+ minimal: 128,
389
+ low: 512,
390
+ medium: 1024,
391
+ high: 2048,
392
+ };
393
+ ```
394
+
395
+ ### Control
396
+
397
+ ```typescript
398
+ agent.abort(); // Cancel current operation
399
+ await agent.waitForIdle(); // Wait for completion (settles after awaited agent_end listeners)
400
+ agent.signal; // Active run AbortSignal, if any
401
+ agent.hasQueuedMessages(); // True when either queue still holds messages
402
+ ```
403
+
404
+ ### Events
405
+
406
+ ```typescript
407
+ const unsubscribe = agent.subscribe(async (event, signal) => {
408
+ if (event.type === "agent_end") {
409
+ // Final barrier work for the run
410
+ await flushSessionState(signal);
411
+ }
412
+ });
413
+ unsubscribe();
414
+ ```
415
+
416
+ ## Steering and Follow-up
417
+
418
+ Steering messages let you interrupt the agent while tools are running. Follow-up
419
+ messages let you queue work after the agent would otherwise stop.
420
+
421
+ ```typescript
422
+ agent.steeringMode = "one-at-a-time";
423
+ agent.followUpMode = "one-at-a-time";
424
+
425
+ // While agent is running tools
426
+ agent.steer({
427
+ role: "user",
428
+ content: [{ type: "text", text: "Stop! Do this instead." }],
429
+ timestamp: Date.now(),
430
+ });
431
+
432
+ // After the agent finishes its current work
433
+ agent.followUp({
434
+ role: "user",
435
+ content: [{ type: "text", text: "Also summarize the result." }],
436
+ timestamp: Date.now(),
437
+ });
438
+
439
+ const steeringMode = agent.steeringMode;
440
+ const followUpMode = agent.followUpMode;
441
+
442
+ agent.clearSteeringQueue();
443
+ agent.clearFollowUpQueue();
444
+ agent.clearAllQueues();
445
+ ```
446
+
447
+ Use clearSteeringQueue, clearFollowUpQueue, or clearAllQueues to drop queued messages.
448
+
449
+ When steering messages are detected after a turn completes:
450
+
451
+ 1. All tool calls from the current assistant message have already finished
452
+ 2. Steering messages are injected
453
+ 3. The LLM responds on the next turn
454
+
455
+ Follow-up messages are checked only when there are no more tool calls and no
456
+ steering messages. If any are queued, they are injected and another turn runs.
457
+
458
+ Queue modes: `"one-at-a-time"` (default) drains only the oldest queued message per
459
+ drain point; `"all"` drains every queued message at that point.
460
+
461
+ ## Custom Message Types
462
+
463
+ Extend `AgentMessage` via declaration merging:
464
+
465
+ ```typescript
466
+ declare module "@m4ike1/ion-agent-core" {
467
+ interface CustomAgentMessages {
468
+ notification: { role: "notification"; text: string; timestamp: number };
469
+ }
470
+ }
471
+
472
+ // Now valid
473
+ const msg: AgentMessage = { role: "notification", text: "Info", timestamp: Date.now() };
474
+ ```
475
+
476
+ Handle custom types in `convertToLlm`:
477
+
478
+ ```typescript
479
+ const agent = new Agent({
480
+ streamFn: models.streamSimple.bind(models),
481
+ convertToLlm: (messages) => messages.flatMap(m => {
482
+ if (m.role === "notification") return []; // Filter out
483
+ return [m];
484
+ }),
485
+ });
486
+ ```
487
+
488
+ ## Tools
489
+
490
+ Define tools using `AgentTool`:
491
+
492
+ ```typescript
493
+ import { Type } from "typebox";
494
+
495
+ const readFileTool: AgentTool = {
496
+ name: "read_file",
497
+ label: "Read File", // For UI display
498
+ description: "Read a file's contents",
499
+ parameters: Type.Object({
500
+ path: Type.String({ description: "File path" }),
501
+ }),
502
+ // Override execution mode for this tool (optional).
503
+ // "sequential" forces the entire batch to run one at a time.
504
+ // "parallel" allows concurrent execution with other tool calls.
505
+ // If omitted, the global toolExecution config applies.
506
+ executionMode: "sequential",
507
+ execute: async (toolCallId, params, signal, onUpdate) => {
508
+ const content = await fs.readFile(params.path, "utf-8");
509
+
510
+ // Optional: stream progress
511
+ onUpdate?.({ content: [{ type: "text", text: "Reading..." }], details: {} });
512
+
513
+ // Optional: add `terminate: true` here to skip the automatic follow-up LLM call
514
+ // when every finalized tool result in the batch does the same.
515
+ return {
516
+ content: [{ type: "text", text: content }],
517
+ details: { path: params.path, size: content.length },
518
+ };
519
+ },
520
+ };
521
+
522
+ agent.state.tools = [readFileTool];
523
+ ```
524
+
525
+ `AgentTool` also supports `prepareArguments` (compatibility shim normalizing raw
526
+ tool-call arguments to the schema before validation) and `replay` (`"never"` |
527
+ `"safe"`, recovery policy for a durable effect whose outcome is unknown).
528
+
529
+ ### Error Handling
530
+
531
+ **Throw an error** when a tool fails. Do not return error messages as content.
532
+
533
+ ```typescript
534
+ execute: async (toolCallId, params, signal, onUpdate) => {
535
+ if (!fs.existsSync(params.path)) {
536
+ throw new Error(`File not found: ${params.path}`);
537
+ }
538
+ // Return content only on success
539
+ return { content: [{ type: "text", text: "..." }] };
540
+ }
541
+ ```
542
+
543
+ Thrown errors are caught by the agent and reported to the LLM as tool errors with
544
+ `isError: true`.
545
+
546
+ Return `terminate: true` from `execute()`, a blocked `beforeToolCall`, or
547
+ `afterToolCall` to hint that the agent should stop after the current tool batch.
548
+ This only takes effect when every finalized tool result in the batch is
549
+ terminating. The hint is runtime-only; emitted `toolResult` transcript messages
550
+ remain standard LLM tool results.
551
+
552
+ ## Proxy Usage
553
+
554
+ For browser apps that proxy through a backend:
555
+
556
+ ```typescript
557
+ import { Agent, streamProxy } from "@m4ike1/ion-agent-core";
558
+
559
+ const agent = new Agent({
560
+ streamFn: (model, context, options) =>
561
+ streamProxy(model, context, {
562
+ ...options,
563
+ authToken: "...",
564
+ proxyUrl: "https://your-server.com",
565
+ }),
566
+ });
567
+ ```
568
+
569
+ `streamProxy` POSTs `{ model, context, options }` to `${proxyUrl}/api/stream` with a
570
+ `Bearer` auth token and reconstructs the assistant stream client-side. Only
571
+ serializable stream options are forwarded (temperature, samplingParams, maxTokens,
572
+ reasoning, cacheRetention, sessionId, headers, metadata, transport,
573
+ thinkingBudgets, maxRetryDelayMs).
574
+
575
+ ## Low-Level API
576
+
577
+ For direct control without the Agent class:
578
+
579
+ ```typescript
580
+ import { agentLoop, agentLoopContinue } from "@m4ike1/ion-agent-core";
581
+
582
+ const context: AgentContext = {
583
+ systemPrompt: "You are helpful.",
584
+ messages: [],
585
+ tools: [],
586
+ };
587
+
588
+ const config: AgentLoopConfig = {
589
+ model: getModel("openai", "gpt-4o"),
590
+ convertToLlm: (msgs) => msgs.filter(m => ["user", "assistant", "toolResult"].includes(m.role)),
591
+ toolExecution: "parallel", // overridden by per-tool executionMode if set
592
+ beforeToolCall: async ({ toolCall, args, context }) => undefined,
593
+ afterToolCall: async ({ toolCall, result, isError, context }) => undefined,
594
+ shouldStopAfterTurn: async ({ message, toolResults, context, newMessages }) => {
595
+ return shouldCompactBeforeNextTurn(context.messages);
596
+ },
597
+ };
598
+
599
+ const userMessage = { role: "user", content: [{ type: "text", text: "Hello" }], timestamp: Date.now() };
600
+
601
+ const streamFn = models.streamSimple.bind(models);
602
+ for await (const event of agentLoop([userMessage], context, config, undefined, streamFn)) {
603
+ console.log(event.type);
604
+ }
605
+
606
+ // Continue from existing context
607
+ for await (const event of agentLoopContinue(context, config, undefined, streamFn)) {
608
+ console.log(event.type);
609
+ }
610
+ ```
611
+
612
+ `runAgentLoop` / `runAgentLoopContinue` are the promise-based variants: same
613
+ arguments plus an `emit` sink, resolving to the new messages.
614
+
615
+ These low-level streams are observational. They preserve event order, but they do
616
+ not wait for your async event handling to settle before later producer phases
617
+ continue. If you need message processing to act as a barrier before tool preflight,
618
+ use the `Agent` class instead of raw `agentLoop()` or `agentLoopContinue()`.
619
+
620
+ ## License
621
+
622
+ MIT
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Agent loop that works with AgentMessage throughout.
3
+ * Transforms to Message[] only at the LLM call boundary.
4
+ */
5
+ import { EventStream } from "@m4ike1/ion-ai";
6
+ import type { AgentContext, AgentEvent, AgentLoopConfig, AgentMessage, StreamFn } from "./types.ts";
7
+ export type AgentEventSink = (event: AgentEvent) => Promise<void> | void;
8
+ /**
9
+ * Start an agent loop with a new prompt message.
10
+ * The prompt is added to the context and events are emitted for it.
11
+ */
12
+ export declare function agentLoop(prompts: AgentMessage[], context: AgentContext, config: AgentLoopConfig, signal: AbortSignal | undefined, streamFn: StreamFn): EventStream<AgentEvent, AgentMessage[]>;
13
+ /**
14
+ * Continue an agent loop from the current context without adding a new message.
15
+ * Used for retries - context already has user message or tool results.
16
+ *
17
+ * **Important:** The last message in context must convert to a `user` or `toolResult` message
18
+ * via `convertToLlm`. If it doesn't, the LLM provider will reject the request.
19
+ * This cannot be validated here since `convertToLlm` is only called once per turn.
20
+ */
21
+ export declare function agentLoopContinue(context: AgentContext, config: AgentLoopConfig, signal: AbortSignal | undefined, streamFn: StreamFn): EventStream<AgentEvent, AgentMessage[]>;
22
+ export declare function runAgentLoop(prompts: AgentMessage[], context: AgentContext, config: AgentLoopConfig, emit: AgentEventSink, signal: AbortSignal | undefined, streamFn: StreamFn): Promise<AgentMessage[]>;
23
+ export declare function runAgentLoopContinue(context: AgentContext, config: AgentLoopConfig, emit: AgentEventSink, signal: AbortSignal | undefined, streamFn: StreamFn): Promise<AgentMessage[]>;
24
+ //# sourceMappingURL=agent-loop.d.ts.map