evolcore 0.0.4 → 0.0.6

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 (332) hide show
  1. package/CHANGELOG.md +65 -3
  2. package/README.md +4 -12
  3. package/dist/agents/baseagent.js +39 -0
  4. package/dist/agents/claude-runner.js +10 -2
  5. package/dist/agents/codex-runner.js +37 -8
  6. package/dist/agents/ecagent-runner.js +1159 -0
  7. package/dist/agents/gemini-runner.js +4 -1
  8. package/dist/agents/runner-types.js +20 -4
  9. package/dist/aun/msg/history.js +32 -9
  10. package/dist/aun/outbox.js +4 -9
  11. package/dist/channels/aun.js +32 -6
  12. package/dist/channels/daemon.js +7 -4
  13. package/dist/channels/dingtalk.js +3 -5
  14. package/dist/channels/feishu.js +16 -108
  15. package/dist/channels/wechat.js +4 -4
  16. package/dist/channels/wecom.js +4 -6
  17. package/dist/cli/agent-command.js +1 -1
  18. package/dist/cli/agent.js +42 -11
  19. package/dist/cli/aun-commands.js +50 -3
  20. package/dist/cli/daemon-commands.js +127 -21
  21. package/dist/cli/data-command.js +132 -0
  22. package/dist/cli/index.js +11 -3
  23. package/dist/cli/init.js +116 -37
  24. package/dist/cli/net-check.js +9 -20
  25. package/dist/cli/restart-monitor.js +11 -2
  26. package/dist/cli/trigger-command.js +1 -1
  27. package/dist/cli/watch-msg.js +12 -25
  28. package/dist/config/access-policy-domain.js +0 -20
  29. package/dist/config/access-policy.js +5 -29
  30. package/dist/config/builtin-roles.js +3 -1
  31. package/dist/config/config-field-policy.js +1 -1
  32. package/dist/config/gateway-config.js +21 -4
  33. package/dist/config/resolved-config-op.js +10 -0
  34. package/dist/core/auth/operation-catalog.js +1 -1
  35. package/dist/core/command/command-handler.js +2 -2
  36. package/dist/core/command/connect-menu.js +20 -42
  37. package/dist/core/command/menu-handler.js +11 -9
  38. package/dist/core/command/role-menu.js +27 -0
  39. package/dist/core/command/slash-handler.js +18 -14
  40. package/dist/core/data-migration.js +1434 -0
  41. package/dist/core/handoff/store.js +14 -4
  42. package/dist/core/inference/text-inference.js +42 -1
  43. package/dist/core/message/inbound-admission.js +23 -13
  44. package/dist/core/message/pending-hints.js +1 -1
  45. package/dist/core/message/response-engine.js +406 -167
  46. package/dist/core/message/retry-scheduler.js +71 -0
  47. package/dist/core/model/model-catalog.js +7 -2
  48. package/dist/core/model/model-fallback.js +81 -0
  49. package/dist/core/protected-paths.js +41 -8
  50. package/dist/core/session/adapters/ecagent-session-file-adapter.js +112 -0
  51. package/dist/core/session/session-fs-store.js +300 -61
  52. package/dist/core/session/session-manager.js +225 -21
  53. package/dist/core/session/session-title.js +1 -0
  54. package/dist/core/session/session-turn-coordinator.js +8 -1
  55. package/dist/core/system-channels.js +1 -0
  56. package/dist/index.js +10 -9
  57. package/dist/paths.js +35 -27
  58. package/dist/trigger/feedback.js +16 -0
  59. package/dist/trigger/legacy-session-history.js +19 -0
  60. package/dist/trigger/manager.js +12 -1
  61. package/dist/trigger/parser.js +4 -2
  62. package/dist/trigger/scheduler.js +185 -15
  63. package/dist/trigger/session-lock.js +62 -0
  64. package/dist/trigger/state.js +64 -0
  65. package/dist/trigger/validation.js +32 -2
  66. package/dist/utils/aid-bind.js +1 -1
  67. package/dist/utils/cross-platform.js +8 -2
  68. package/dist/utils/error-utils.js +9 -0
  69. package/dist/utils/process-introspect.js +19 -3
  70. package/dist/utils/welcome.js +2 -3
  71. package/ecagent/LICENSE +21 -0
  72. package/ecagent/NOTICE +11 -0
  73. package/ecagent/README.md +61 -0
  74. package/ecagent/dist/agent-loop.d.ts +24 -0
  75. package/ecagent/dist/agent-loop.d.ts.map +1 -0
  76. package/ecagent/dist/agent-loop.js +547 -0
  77. package/ecagent/dist/agent-loop.js.map +1 -0
  78. package/ecagent/dist/agent.d.ts +127 -0
  79. package/ecagent/dist/agent.d.ts.map +1 -0
  80. package/ecagent/dist/agent.js +386 -0
  81. package/ecagent/dist/agent.js.map +1 -0
  82. package/ecagent/dist/harness/agent-harness.d.ts +95 -0
  83. package/ecagent/dist/harness/agent-harness.d.ts.map +1 -0
  84. package/ecagent/dist/harness/agent-harness.js +926 -0
  85. package/ecagent/dist/harness/agent-harness.js.map +1 -0
  86. package/ecagent/dist/harness/compaction/branch-summarization.d.ts +51 -0
  87. package/ecagent/dist/harness/compaction/branch-summarization.d.ts.map +1 -0
  88. package/ecagent/dist/harness/compaction/branch-summarization.js +174 -0
  89. package/ecagent/dist/harness/compaction/branch-summarization.js.map +1 -0
  90. package/ecagent/dist/harness/compaction/compaction.d.ts +95 -0
  91. package/ecagent/dist/harness/compaction/compaction.d.ts.map +1 -0
  92. package/ecagent/dist/harness/compaction/compaction.js +528 -0
  93. package/ecagent/dist/harness/compaction/compaction.js.map +1 -0
  94. package/ecagent/dist/harness/compaction/utils.d.ts +25 -0
  95. package/ecagent/dist/harness/compaction/utils.d.ts.map +1 -0
  96. package/ecagent/dist/harness/compaction/utils.js +131 -0
  97. package/ecagent/dist/harness/compaction/utils.js.map +1 -0
  98. package/ecagent/dist/harness/env/nodejs.d.ts +51 -0
  99. package/ecagent/dist/harness/env/nodejs.d.ts.map +1 -0
  100. package/ecagent/dist/harness/env/nodejs.js +513 -0
  101. package/ecagent/dist/harness/env/nodejs.js.map +1 -0
  102. package/ecagent/dist/harness/messages.d.ts +51 -0
  103. package/ecagent/dist/harness/messages.d.ts.map +1 -0
  104. package/ecagent/dist/harness/messages.js +102 -0
  105. package/ecagent/dist/harness/messages.js.map +1 -0
  106. package/ecagent/dist/harness/prompt-templates.d.ts +48 -0
  107. package/ecagent/dist/harness/prompt-templates.d.ts.map +1 -0
  108. package/ecagent/dist/harness/prompt-templates.js +230 -0
  109. package/ecagent/dist/harness/prompt-templates.js.map +1 -0
  110. package/ecagent/dist/harness/session/jsonl-repo.d.ts +26 -0
  111. package/ecagent/dist/harness/session/jsonl-repo.d.ts.map +1 -0
  112. package/ecagent/dist/harness/session/jsonl-repo.js +100 -0
  113. package/ecagent/dist/harness/session/jsonl-repo.js.map +1 -0
  114. package/ecagent/dist/harness/session/jsonl-storage.d.ts +34 -0
  115. package/ecagent/dist/harness/session/jsonl-storage.d.ts.map +1 -0
  116. package/ecagent/dist/harness/session/jsonl-storage.js +234 -0
  117. package/ecagent/dist/harness/session/jsonl-storage.js.map +1 -0
  118. package/ecagent/dist/harness/session/memory-repo.d.ts +18 -0
  119. package/ecagent/dist/harness/session/memory-repo.d.ts.map +1 -0
  120. package/ecagent/dist/harness/session/memory-repo.js +44 -0
  121. package/ecagent/dist/harness/session/memory-repo.js.map +1 -0
  122. package/ecagent/dist/harness/session/memory-storage.d.ts +25 -0
  123. package/ecagent/dist/harness/session/memory-storage.d.ts.map +1 -0
  124. package/ecagent/dist/harness/session/memory-storage.js +111 -0
  125. package/ecagent/dist/harness/session/memory-storage.js.map +1 -0
  126. package/ecagent/dist/harness/session/repo-utils.d.ts +11 -0
  127. package/ecagent/dist/harness/session/repo-utils.d.ts.map +1 -0
  128. package/ecagent/dist/harness/session/repo-utils.js +39 -0
  129. package/ecagent/dist/harness/session/repo-utils.js.map +1 -0
  130. package/ecagent/dist/harness/session/session.d.ts +47 -0
  131. package/ecagent/dist/harness/session/session.d.ts.map +1 -0
  132. package/ecagent/dist/harness/session/session.js +245 -0
  133. package/ecagent/dist/harness/session/session.js.map +1 -0
  134. package/ecagent/dist/harness/session/uuid.d.ts +2 -0
  135. package/ecagent/dist/harness/session/uuid.d.ts.map +1 -0
  136. package/ecagent/dist/harness/session/uuid.js +50 -0
  137. package/ecagent/dist/harness/session/uuid.js.map +1 -0
  138. package/ecagent/dist/harness/skills.d.ts +44 -0
  139. package/ecagent/dist/harness/skills.d.ts.map +1 -0
  140. package/ecagent/dist/harness/skills.js +311 -0
  141. package/ecagent/dist/harness/skills.js.map +1 -0
  142. package/ecagent/dist/harness/system-prompt.d.ts +3 -0
  143. package/ecagent/dist/harness/system-prompt.d.ts.map +1 -0
  144. package/ecagent/dist/harness/system-prompt.js +30 -0
  145. package/ecagent/dist/harness/system-prompt.js.map +1 -0
  146. package/ecagent/dist/harness/types.d.ts +619 -0
  147. package/ecagent/dist/harness/types.d.ts.map +1 -0
  148. package/ecagent/dist/harness/types.js +81 -0
  149. package/ecagent/dist/harness/types.js.map +1 -0
  150. package/ecagent/dist/harness/utils/shell-output.d.ts +14 -0
  151. package/ecagent/dist/harness/utils/shell-output.d.ts.map +1 -0
  152. package/ecagent/dist/harness/utils/shell-output.js +126 -0
  153. package/ecagent/dist/harness/utils/shell-output.js.map +1 -0
  154. package/ecagent/dist/harness/utils/truncate.d.ts +70 -0
  155. package/ecagent/dist/harness/utils/truncate.d.ts.map +1 -0
  156. package/ecagent/dist/harness/utils/truncate.js +290 -0
  157. package/ecagent/dist/harness/utils/truncate.js.map +1 -0
  158. package/ecagent/dist/index.d.ts +22 -0
  159. package/ecagent/dist/index.d.ts.map +1 -0
  160. package/ecagent/dist/index.js +27 -0
  161. package/ecagent/dist/index.js.map +1 -0
  162. package/ecagent/dist/node.d.ts +3 -0
  163. package/ecagent/dist/node.d.ts.map +1 -0
  164. package/ecagent/dist/node.js +3 -0
  165. package/ecagent/dist/node.js.map +1 -0
  166. package/ecagent/dist/proxy.d.ts +69 -0
  167. package/ecagent/dist/proxy.d.ts.map +1 -0
  168. package/ecagent/dist/proxy.js +278 -0
  169. package/ecagent/dist/proxy.js.map +1 -0
  170. package/ecagent/dist/runtime/api/lazy.d.ts +15 -0
  171. package/ecagent/dist/runtime/api/lazy.d.ts.map +1 -0
  172. package/ecagent/dist/runtime/api/lazy.js +59 -0
  173. package/ecagent/dist/runtime/api/lazy.js.map +1 -0
  174. package/ecagent/dist/runtime/api/pi-messages.d.ts +97 -0
  175. package/ecagent/dist/runtime/api/pi-messages.d.ts.map +1 -0
  176. package/ecagent/dist/runtime/api/pi-messages.js +307 -0
  177. package/ecagent/dist/runtime/api/pi-messages.js.map +1 -0
  178. package/ecagent/dist/runtime/api/pi-messages.lazy.d.ts +3 -0
  179. package/ecagent/dist/runtime/api/pi-messages.lazy.d.ts.map +1 -0
  180. package/ecagent/dist/runtime/api/pi-messages.lazy.js +3 -0
  181. package/ecagent/dist/runtime/api/pi-messages.lazy.js.map +1 -0
  182. package/ecagent/dist/runtime/auth/context.d.ts +7 -0
  183. package/ecagent/dist/runtime/auth/context.d.ts.map +1 -0
  184. package/ecagent/dist/runtime/auth/context.js +42 -0
  185. package/ecagent/dist/runtime/auth/context.js.map +1 -0
  186. package/ecagent/dist/runtime/auth/credential-store.d.ts +16 -0
  187. package/ecagent/dist/runtime/auth/credential-store.d.ts.map +1 -0
  188. package/ecagent/dist/runtime/auth/credential-store.js +39 -0
  189. package/ecagent/dist/runtime/auth/credential-store.js.map +1 -0
  190. package/ecagent/dist/runtime/auth/helpers.d.ts +20 -0
  191. package/ecagent/dist/runtime/auth/helpers.d.ts.map +1 -0
  192. package/ecagent/dist/runtime/auth/helpers.js +46 -0
  193. package/ecagent/dist/runtime/auth/helpers.js.map +1 -0
  194. package/ecagent/dist/runtime/auth/resolve.d.ts +26 -0
  195. package/ecagent/dist/runtime/auth/resolve.d.ts.map +1 -0
  196. package/ecagent/dist/runtime/auth/resolve.js +100 -0
  197. package/ecagent/dist/runtime/auth/resolve.js.map +1 -0
  198. package/ecagent/dist/runtime/auth/types.d.ts +180 -0
  199. package/ecagent/dist/runtime/auth/types.d.ts.map +1 -0
  200. package/ecagent/dist/runtime/auth/types.js +2 -0
  201. package/ecagent/dist/runtime/auth/types.js.map +1 -0
  202. package/ecagent/dist/runtime/compat.d.ts +28 -0
  203. package/ecagent/dist/runtime/compat.d.ts.map +1 -0
  204. package/ecagent/dist/runtime/compat.js +86 -0
  205. package/ecagent/dist/runtime/compat.js.map +1 -0
  206. package/ecagent/dist/runtime/index.d.ts +20 -0
  207. package/ecagent/dist/runtime/index.d.ts.map +1 -0
  208. package/ecagent/dist/runtime/index.js +17 -0
  209. package/ecagent/dist/runtime/index.js.map +1 -0
  210. package/ecagent/dist/runtime/models.d.ts +142 -0
  211. package/ecagent/dist/runtime/models.d.ts.map +1 -0
  212. package/ecagent/dist/runtime/models.js +245 -0
  213. package/ecagent/dist/runtime/models.js.map +1 -0
  214. package/ecagent/dist/runtime/oauth.d.ts +2 -0
  215. package/ecagent/dist/runtime/oauth.d.ts.map +1 -0
  216. package/ecagent/dist/runtime/oauth.js +2 -0
  217. package/ecagent/dist/runtime/oauth.js.map +1 -0
  218. package/ecagent/dist/runtime/providers/faux.d.ts +97 -0
  219. package/ecagent/dist/runtime/providers/faux.d.ts.map +1 -0
  220. package/ecagent/dist/runtime/providers/faux.js +395 -0
  221. package/ecagent/dist/runtime/providers/faux.js.map +1 -0
  222. package/ecagent/dist/runtime/types.d.ts +607 -0
  223. package/ecagent/dist/runtime/types.d.ts.map +1 -0
  224. package/ecagent/dist/runtime/types.js +2 -0
  225. package/ecagent/dist/runtime/types.js.map +1 -0
  226. package/ecagent/dist/runtime/utils/diagnostics.d.ts +19 -0
  227. package/ecagent/dist/runtime/utils/diagnostics.d.ts.map +1 -0
  228. package/ecagent/dist/runtime/utils/diagnostics.js +25 -0
  229. package/ecagent/dist/runtime/utils/diagnostics.js.map +1 -0
  230. package/ecagent/dist/runtime/utils/event-stream.d.ts +21 -0
  231. package/ecagent/dist/runtime/utils/event-stream.d.ts.map +1 -0
  232. package/ecagent/dist/runtime/utils/event-stream.js +77 -0
  233. package/ecagent/dist/runtime/utils/event-stream.js.map +1 -0
  234. package/ecagent/dist/runtime/utils/headers.d.ts +4 -0
  235. package/ecagent/dist/runtime/utils/headers.d.ts.map +1 -0
  236. package/ecagent/dist/runtime/utils/headers.js +18 -0
  237. package/ecagent/dist/runtime/utils/headers.js.map +1 -0
  238. package/ecagent/dist/runtime/utils/json-parse.d.ts +16 -0
  239. package/ecagent/dist/runtime/utils/json-parse.d.ts.map +1 -0
  240. package/ecagent/dist/runtime/utils/json-parse.js +113 -0
  241. package/ecagent/dist/runtime/utils/json-parse.js.map +1 -0
  242. package/ecagent/dist/runtime/utils/oauth/types.d.ts +64 -0
  243. package/ecagent/dist/runtime/utils/oauth/types.d.ts.map +1 -0
  244. package/ecagent/dist/runtime/utils/oauth/types.js +2 -0
  245. package/ecagent/dist/runtime/utils/oauth/types.js.map +1 -0
  246. package/ecagent/dist/runtime/utils/overflow.d.ts +58 -0
  247. package/ecagent/dist/runtime/utils/overflow.d.ts.map +1 -0
  248. package/ecagent/dist/runtime/utils/overflow.js +158 -0
  249. package/ecagent/dist/runtime/utils/overflow.js.map +1 -0
  250. package/ecagent/dist/runtime/utils/provider-env.d.ts +7 -0
  251. package/ecagent/dist/runtime/utils/provider-env.d.ts.map +1 -0
  252. package/ecagent/dist/runtime/utils/provider-env.js +44 -0
  253. package/ecagent/dist/runtime/utils/provider-env.js.map +1 -0
  254. package/ecagent/dist/runtime/utils/retry.d.ts +12 -0
  255. package/ecagent/dist/runtime/utils/retry.d.ts.map +1 -0
  256. package/ecagent/dist/runtime/utils/retry.js +90 -0
  257. package/ecagent/dist/runtime/utils/retry.js.map +1 -0
  258. package/ecagent/dist/runtime/utils/typebox-helpers.d.ts +17 -0
  259. package/ecagent/dist/runtime/utils/typebox-helpers.d.ts.map +1 -0
  260. package/ecagent/dist/runtime/utils/typebox-helpers.js +21 -0
  261. package/ecagent/dist/runtime/utils/typebox-helpers.js.map +1 -0
  262. package/ecagent/dist/runtime/utils/validation.d.ts +18 -0
  263. package/ecagent/dist/runtime/utils/validation.d.ts.map +1 -0
  264. package/ecagent/dist/runtime/utils/validation.js +269 -0
  265. package/ecagent/dist/runtime/utils/validation.js.map +1 -0
  266. package/ecagent/dist/types.d.ts +401 -0
  267. package/ecagent/dist/types.d.ts.map +1 -0
  268. package/ecagent/dist/types.js +2 -0
  269. package/ecagent/dist/types.js.map +1 -0
  270. package/ecagent/package.json +93 -0
  271. package/ecagent/src/agent-loop.ts +792 -0
  272. package/ecagent/src/agent.ts +575 -0
  273. package/ecagent/src/harness/agent-harness.ts +1029 -0
  274. package/ecagent/src/harness/compaction/branch-summarization.ts +261 -0
  275. package/ecagent/src/harness/compaction/compaction.ts +753 -0
  276. package/ecagent/src/harness/compaction/utils.ts +144 -0
  277. package/ecagent/src/harness/env/nodejs.ts +569 -0
  278. package/ecagent/src/harness/messages.ts +164 -0
  279. package/ecagent/src/harness/prompt-templates.ts +267 -0
  280. package/ecagent/src/harness/session/jsonl-repo.ts +179 -0
  281. package/ecagent/src/harness/session/jsonl-storage.ts +314 -0
  282. package/ecagent/src/harness/session/memory-repo.ts +50 -0
  283. package/ecagent/src/harness/session/memory-storage.ts +133 -0
  284. package/ecagent/src/harness/session/repo-utils.ts +51 -0
  285. package/ecagent/src/harness/session/session.ts +338 -0
  286. package/ecagent/src/harness/session/uuid.ts +54 -0
  287. package/ecagent/src/harness/skills.ts +375 -0
  288. package/ecagent/src/harness/system-prompt.ts +34 -0
  289. package/ecagent/src/harness/types.ts +838 -0
  290. package/ecagent/src/harness/utils/shell-output.ts +135 -0
  291. package/ecagent/src/harness/utils/truncate.ts +344 -0
  292. package/ecagent/src/index.ts +46 -0
  293. package/ecagent/src/node.ts +2 -0
  294. package/ecagent/src/proxy.ts +367 -0
  295. package/ecagent/src/runtime/api/lazy.ts +70 -0
  296. package/ecagent/src/runtime/api/pi-messages.lazy.ts +4 -0
  297. package/ecagent/src/runtime/api/pi-messages.ts +436 -0
  298. package/ecagent/src/runtime/auth/context.ts +45 -0
  299. package/ecagent/src/runtime/auth/credential-store.ts +47 -0
  300. package/ecagent/src/runtime/auth/helpers.ts +46 -0
  301. package/ecagent/src/runtime/auth/resolve.ts +141 -0
  302. package/ecagent/src/runtime/auth/types.ts +182 -0
  303. package/ecagent/src/runtime/compat.ts +158 -0
  304. package/ecagent/src/runtime/index.ts +31 -0
  305. package/ecagent/src/runtime/models.ts +452 -0
  306. package/ecagent/src/runtime/oauth.ts +1 -0
  307. package/ecagent/src/runtime/providers/faux.ts +538 -0
  308. package/ecagent/src/runtime/types.ts +718 -0
  309. package/ecagent/src/runtime/utils/diagnostics.ts +45 -0
  310. package/ecagent/src/runtime/utils/event-stream.ts +88 -0
  311. package/ecagent/src/runtime/utils/headers.ts +18 -0
  312. package/ecagent/src/runtime/utils/json-parse.ts +124 -0
  313. package/ecagent/src/runtime/utils/oauth/types.ts +79 -0
  314. package/ecagent/src/runtime/utils/overflow.ts +165 -0
  315. package/ecagent/src/runtime/utils/provider-env.ts +52 -0
  316. package/ecagent/src/runtime/utils/retry.ts +101 -0
  317. package/ecagent/src/runtime/utils/typebox-helpers.ts +24 -0
  318. package/ecagent/src/runtime/utils/validation.ts +310 -0
  319. package/ecagent/src/types.ts +430 -0
  320. package/ecagent/tsconfig.build.json +32 -0
  321. package/kits/docs/evolcore/config.md +4 -4
  322. package/kits/docs/evolcore/contact.md +2 -1
  323. package/kits/schemas/_meta.json +7 -4
  324. package/kits/schemas/agent-config.schema.10.json +370 -0
  325. package/kits/schemas/agent-config.schema.9.json +2 -12
  326. package/kits/schemas/defaults.schema.4.json +93 -0
  327. package/kits/schemas/relation-config.schema.8.json +69 -0
  328. package/kits/templates/roles/admin.json +1 -1
  329. package/package.json +22 -6
  330. package/skills/eclink/SKILL.md +70 -0
  331. package/skills/eclink/agents/openai.yaml +4 -0
  332. package/assets/.env.template +0 -4
package/ecagent/NOTICE ADDED
@@ -0,0 +1,11 @@
1
+ This distribution contains modified packaging of @earendil-works/pi-agent-core.
2
+
3
+ Upstream project: https://github.com/earendil-works/pi
4
+ Upstream version: 0.80.7
5
+ Upstream commit: 818d67457cdd6b60bce6b121d16b23141c252dd8
6
+
7
+ Modification: TypeScript sources from @earendil-works/pi-agent-core and the
8
+ provider-free protocol subset of @earendil-works/pi-ai are maintained together
9
+ in this package. Provider SDK implementations and dependencies are excluded.
10
+ Callers supply a custom model stream function or use the included pi-messages
11
+ protocol runtime.
@@ -0,0 +1,61 @@
1
+ # ecagent
2
+
3
+ `ecagent` is an unofficial lightweight distribution of
4
+ [`@earendil-works/pi-agent-core`](https://github.com/earendil-works/pi). It
5
+ includes the Pi agent loop, tools, sessions, compaction, skills, and execution
6
+ environment abstractions together with an embedded provider-free model runtime.
7
+ The published package includes both the TypeScript source in `src/` and the
8
+ compiled ESM output in `dist/`.
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ npm install ecagent
14
+
15
+ # Or install it globally for a shared Node.js runtime
16
+ npm install --global ecagent
17
+ ```
18
+
19
+ Supply a custom model stream function. No model provider SDK is installed by
20
+ default:
21
+
22
+ ```typescript
23
+ import { Agent } from "ecagent";
24
+
25
+ const agent = new Agent({
26
+ initialState: {
27
+ model,
28
+ systemPrompt: "You are a coding agent.",
29
+ },
30
+ streamFn: evolcoreModelStream,
31
+ });
32
+ ```
33
+
34
+ The `streamFn` must implement the Pi stream contract exported by
35
+ `ecagent/runtime`:
36
+
37
+ ```typescript
38
+ import { AssistantMessageEventStream } from "ecagent/runtime";
39
+ ```
40
+
41
+ EvolCore uses this boundary to connect its own credentials, gateway, streaming,
42
+ and abort handling.
43
+
44
+ ## Build from source
45
+
46
+ ```bash
47
+ npm install
48
+ npm run build
49
+ ```
50
+
51
+ The build runs TypeScript directly over the checked-in source. It does not
52
+ download precompiled upstream artifacts.
53
+
54
+ ## Upstream
55
+
56
+ - Package: `@earendil-works/pi-agent-core@0.80.7`
57
+ - Runtime: `@earendil-works/pi-ai@0.80.7`
58
+ - Commit: `818d67457cdd6b60bce6b121d16b23141c252dd8`
59
+ - License: MIT
60
+
61
+ This package is not affiliated with or endorsed by the Pi maintainers.
@@ -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 "ecagent/runtime/compat";
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, 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, streamFn?: StreamFn): EventStream<AgentEvent, AgentMessage[]>;
22
+ export declare function runAgentLoop(prompts: AgentMessage[], context: AgentContext, config: AgentLoopConfig, emit: AgentEventSink, signal?: AbortSignal, streamFn?: StreamFn): Promise<AgentMessage[]>;
23
+ export declare function runAgentLoopContinue(context: AgentContext, config: AgentLoopConfig, emit: AgentEventSink, signal?: AbortSignal, streamFn?: StreamFn): Promise<AgentMessage[]>;
24
+ //# sourceMappingURL=agent-loop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-loop.d.ts","sourceRoot":"","sources":["../src/agent-loop.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAGN,WAAW,EAIX,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EACX,YAAY,EACZ,UAAU,EACV,eAAe,EACf,YAAY,EAIZ,QAAQ,EACR,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAEzE;;;GAGG;AACH,wBAAgB,SAAS,CACxB,OAAO,EAAE,YAAY,EAAE,EACvB,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,QAAQ,GACjB,WAAW,CAAC,UAAU,EAAE,YAAY,EAAE,CAAC,CAiBzC;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAChC,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,QAAQ,GACjB,WAAW,CAAC,UAAU,EAAE,YAAY,EAAE,CAAC,CAwBzC;AAED,wBAAsB,YAAY,CACjC,OAAO,EAAE,YAAY,EAAE,EACvB,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,cAAc,EACpB,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC,YAAY,EAAE,CAAC,CAgBzB;AAED,wBAAsB,oBAAoB,CACzC,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,cAAc,EACpB,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC,YAAY,EAAE,CAAC,CAiBzB"}
@@ -0,0 +1,547 @@
1
+ /**
2
+ * Agent loop that works with AgentMessage throughout.
3
+ * Transforms to Message[] only at the LLM call boundary.
4
+ */
5
+ import { EventStream, streamSimple, validateToolArguments, } from "ecagent/runtime/compat";
6
+ /**
7
+ * Start an agent loop with a new prompt message.
8
+ * The prompt is added to the context and events are emitted for it.
9
+ */
10
+ export function agentLoop(prompts, context, config, signal, streamFn) {
11
+ const stream = createAgentStream();
12
+ void runAgentLoop(prompts, context, config, async (event) => {
13
+ stream.push(event);
14
+ }, signal, streamFn).then((messages) => {
15
+ stream.end(messages);
16
+ });
17
+ return stream;
18
+ }
19
+ /**
20
+ * Continue an agent loop from the current context without adding a new message.
21
+ * Used for retries - context already has user message or tool results.
22
+ *
23
+ * **Important:** The last message in context must convert to a `user` or `toolResult` message
24
+ * via `convertToLlm`. If it doesn't, the LLM provider will reject the request.
25
+ * This cannot be validated here since `convertToLlm` is only called once per turn.
26
+ */
27
+ export function agentLoopContinue(context, config, signal, streamFn) {
28
+ if (context.messages.length === 0) {
29
+ throw new Error("Cannot continue: no messages in context");
30
+ }
31
+ if (context.messages[context.messages.length - 1].role === "assistant") {
32
+ throw new Error("Cannot continue from message role: assistant");
33
+ }
34
+ const stream = createAgentStream();
35
+ void runAgentLoopContinue(context, config, async (event) => {
36
+ stream.push(event);
37
+ }, signal, streamFn).then((messages) => {
38
+ stream.end(messages);
39
+ });
40
+ return stream;
41
+ }
42
+ export async function runAgentLoop(prompts, context, config, emit, signal, streamFn) {
43
+ const newMessages = [...prompts];
44
+ const currentContext = {
45
+ ...context,
46
+ messages: [...context.messages, ...prompts],
47
+ };
48
+ await emit({ type: "agent_start" });
49
+ await emit({ type: "turn_start" });
50
+ for (const prompt of prompts) {
51
+ await emit({ type: "message_start", message: prompt });
52
+ await emit({ type: "message_end", message: prompt });
53
+ }
54
+ await runLoop(currentContext, newMessages, config, signal, emit, streamFn);
55
+ return newMessages;
56
+ }
57
+ export async function runAgentLoopContinue(context, config, emit, signal, streamFn) {
58
+ if (context.messages.length === 0) {
59
+ throw new Error("Cannot continue: no messages in context");
60
+ }
61
+ if (context.messages[context.messages.length - 1].role === "assistant") {
62
+ throw new Error("Cannot continue from message role: assistant");
63
+ }
64
+ const newMessages = [];
65
+ const currentContext = { ...context };
66
+ await emit({ type: "agent_start" });
67
+ await emit({ type: "turn_start" });
68
+ await runLoop(currentContext, newMessages, config, signal, emit, streamFn);
69
+ return newMessages;
70
+ }
71
+ function createAgentStream() {
72
+ return new EventStream((event) => event.type === "agent_end", (event) => (event.type === "agent_end" ? event.messages : []));
73
+ }
74
+ /**
75
+ * Main loop logic shared by agentLoop and agentLoopContinue.
76
+ */
77
+ async function runLoop(initialContext, newMessages, initialConfig, signal, emit, streamFn) {
78
+ let currentContext = initialContext;
79
+ let config = initialConfig;
80
+ let firstTurn = true;
81
+ // Check for steering messages at start (user may have typed while waiting)
82
+ let pendingMessages = (await config.getSteeringMessages?.()) || [];
83
+ // Outer loop: continues when queued follow-up messages arrive after agent would stop
84
+ while (true) {
85
+ let hasMoreToolCalls = true;
86
+ // Inner loop: process tool calls and steering messages
87
+ while (hasMoreToolCalls || pendingMessages.length > 0) {
88
+ if (!firstTurn) {
89
+ await emit({ type: "turn_start" });
90
+ }
91
+ else {
92
+ firstTurn = false;
93
+ }
94
+ // Process pending messages (inject before next assistant response)
95
+ if (pendingMessages.length > 0) {
96
+ for (const message of pendingMessages) {
97
+ await emit({ type: "message_start", message });
98
+ await emit({ type: "message_end", message });
99
+ currentContext.messages.push(message);
100
+ newMessages.push(message);
101
+ }
102
+ pendingMessages = [];
103
+ }
104
+ // Stream assistant response
105
+ const message = await streamAssistantResponse(currentContext, config, signal, emit, streamFn);
106
+ newMessages.push(message);
107
+ if (message.stopReason === "error" || message.stopReason === "aborted") {
108
+ await emit({ type: "turn_end", message, toolResults: [] });
109
+ await emit({ type: "agent_end", messages: newMessages });
110
+ return;
111
+ }
112
+ // Check for tool calls
113
+ const toolCalls = message.content.filter((c) => c.type === "toolCall");
114
+ const toolResults = [];
115
+ hasMoreToolCalls = false;
116
+ if (toolCalls.length > 0) {
117
+ // A "length" stop means the output was cut off by the token limit, so
118
+ // every tool call in the message may carry truncated arguments. Fail
119
+ // them all instead of executing potentially borked calls.
120
+ const executedToolBatch = message.stopReason === "length"
121
+ ? await failToolCallsFromTruncatedMessage(toolCalls, emit)
122
+ : await executeToolCalls(currentContext, message, config, signal, emit);
123
+ toolResults.push(...executedToolBatch.messages);
124
+ hasMoreToolCalls = !executedToolBatch.terminate;
125
+ for (const result of toolResults) {
126
+ currentContext.messages.push(result);
127
+ newMessages.push(result);
128
+ }
129
+ }
130
+ await emit({ type: "turn_end", message, toolResults });
131
+ const nextTurnContext = {
132
+ message,
133
+ toolResults,
134
+ context: currentContext,
135
+ newMessages,
136
+ };
137
+ const nextTurnSnapshot = await config.prepareNextTurn?.(nextTurnContext);
138
+ if (nextTurnSnapshot) {
139
+ currentContext = nextTurnSnapshot.context ?? currentContext;
140
+ config = {
141
+ ...config,
142
+ model: nextTurnSnapshot.model ?? config.model,
143
+ reasoning: nextTurnSnapshot.thinkingLevel === undefined
144
+ ? config.reasoning
145
+ : nextTurnSnapshot.thinkingLevel === "off"
146
+ ? undefined
147
+ : nextTurnSnapshot.thinkingLevel,
148
+ };
149
+ }
150
+ if (await config.shouldStopAfterTurn?.({
151
+ message,
152
+ toolResults,
153
+ context: currentContext,
154
+ newMessages,
155
+ })) {
156
+ await emit({ type: "agent_end", messages: newMessages });
157
+ return;
158
+ }
159
+ pendingMessages = (await config.getSteeringMessages?.()) || [];
160
+ }
161
+ // Agent would stop here. Check for follow-up messages.
162
+ const followUpMessages = (await config.getFollowUpMessages?.()) || [];
163
+ if (followUpMessages.length > 0) {
164
+ // Set as pending so inner loop processes them
165
+ pendingMessages = followUpMessages;
166
+ continue;
167
+ }
168
+ // No more messages, exit
169
+ break;
170
+ }
171
+ await emit({ type: "agent_end", messages: newMessages });
172
+ }
173
+ /**
174
+ * Stream an assistant response from the LLM.
175
+ * This is where AgentMessage[] gets transformed to Message[] for the LLM.
176
+ */
177
+ async function streamAssistantResponse(context, config, signal, emit, streamFn) {
178
+ // Apply context transform if configured (AgentMessage[] → AgentMessage[])
179
+ let messages = context.messages;
180
+ if (config.transformContext) {
181
+ messages = await config.transformContext(messages, signal);
182
+ }
183
+ // Convert to LLM-compatible messages (AgentMessage[] → Message[])
184
+ const llmMessages = await config.convertToLlm(messages);
185
+ // Build LLM context
186
+ const llmContext = {
187
+ systemPrompt: context.systemPrompt,
188
+ messages: llmMessages,
189
+ tools: context.tools,
190
+ };
191
+ const streamFunction = streamFn || streamSimple;
192
+ // Resolve API key (important for expiring tokens)
193
+ const resolvedApiKey = (config.getApiKey ? await config.getApiKey(config.model.provider) : undefined) || config.apiKey;
194
+ const response = await streamFunction(config.model, llmContext, {
195
+ ...config,
196
+ apiKey: resolvedApiKey,
197
+ signal,
198
+ });
199
+ let partialMessage = null;
200
+ let addedPartial = false;
201
+ for await (const event of response) {
202
+ switch (event.type) {
203
+ case "start":
204
+ partialMessage = event.partial;
205
+ context.messages.push(partialMessage);
206
+ addedPartial = true;
207
+ await emit({ type: "message_start", message: { ...partialMessage } });
208
+ break;
209
+ case "text_start":
210
+ case "text_delta":
211
+ case "text_end":
212
+ case "thinking_start":
213
+ case "thinking_delta":
214
+ case "thinking_end":
215
+ case "toolcall_start":
216
+ case "toolcall_delta":
217
+ case "toolcall_end":
218
+ if (partialMessage) {
219
+ partialMessage = event.partial;
220
+ context.messages[context.messages.length - 1] = partialMessage;
221
+ await emit({
222
+ type: "message_update",
223
+ assistantMessageEvent: event,
224
+ message: { ...partialMessage },
225
+ });
226
+ }
227
+ break;
228
+ case "done":
229
+ case "error": {
230
+ const finalMessage = await response.result();
231
+ if (addedPartial) {
232
+ context.messages[context.messages.length - 1] = finalMessage;
233
+ }
234
+ else {
235
+ context.messages.push(finalMessage);
236
+ }
237
+ if (!addedPartial) {
238
+ await emit({ type: "message_start", message: { ...finalMessage } });
239
+ }
240
+ await emit({ type: "message_end", message: finalMessage });
241
+ return finalMessage;
242
+ }
243
+ }
244
+ }
245
+ const finalMessage = await response.result();
246
+ if (addedPartial) {
247
+ context.messages[context.messages.length - 1] = finalMessage;
248
+ }
249
+ else {
250
+ context.messages.push(finalMessage);
251
+ await emit({ type: "message_start", message: { ...finalMessage } });
252
+ }
253
+ await emit({ type: "message_end", message: finalMessage });
254
+ return finalMessage;
255
+ }
256
+ /**
257
+ * Fail all tool calls from an assistant message that was truncated by the
258
+ * output token limit. Streamed tool-call arguments are finalized with a
259
+ * best-effort JSON salvage parser, so a truncated message can yield tool calls
260
+ * whose arguments parse and validate but are silently incomplete. None of them
261
+ * are safe to execute; report each as an error so the model can re-issue them.
262
+ */
263
+ async function failToolCallsFromTruncatedMessage(toolCalls, emit) {
264
+ const messages = [];
265
+ for (const toolCall of toolCalls) {
266
+ await emit({
267
+ type: "tool_execution_start",
268
+ toolCallId: toolCall.id,
269
+ toolName: toolCall.name,
270
+ args: toolCall.arguments,
271
+ });
272
+ const finalized = {
273
+ toolCall,
274
+ result: createErrorToolResult(`Tool call "${toolCall.name}" was not executed: the response hit the output token limit, so its arguments may be truncated. Re-issue the tool call with complete arguments.`),
275
+ isError: true,
276
+ };
277
+ await emitToolExecutionEnd(finalized, emit);
278
+ const toolResultMessage = createToolResultMessage(finalized);
279
+ await emitToolResultMessage(toolResultMessage, emit);
280
+ messages.push(toolResultMessage);
281
+ }
282
+ return { messages, terminate: false };
283
+ }
284
+ /**
285
+ * Execute tool calls from an assistant message.
286
+ */
287
+ async function executeToolCalls(currentContext, assistantMessage, config, signal, emit) {
288
+ const toolCalls = assistantMessage.content.filter((c) => c.type === "toolCall");
289
+ const hasSequentialToolCall = toolCalls.some((tc) => currentContext.tools?.find((t) => t.name === tc.name)?.executionMode === "sequential");
290
+ if (config.toolExecution === "sequential" || hasSequentialToolCall) {
291
+ return executeToolCallsSequential(currentContext, assistantMessage, toolCalls, config, signal, emit);
292
+ }
293
+ return executeToolCallsParallel(currentContext, assistantMessage, toolCalls, config, signal, emit);
294
+ }
295
+ async function executeToolCallsSequential(currentContext, assistantMessage, toolCalls, config, signal, emit) {
296
+ const finalizedCalls = [];
297
+ const messages = [];
298
+ for (const toolCall of toolCalls) {
299
+ await emit({
300
+ type: "tool_execution_start",
301
+ toolCallId: toolCall.id,
302
+ toolName: toolCall.name,
303
+ args: toolCall.arguments,
304
+ });
305
+ const preparation = await prepareToolCall(currentContext, assistantMessage, toolCall, config, signal);
306
+ let finalized;
307
+ if (preparation.kind === "immediate") {
308
+ finalized = {
309
+ toolCall,
310
+ result: preparation.result,
311
+ isError: preparation.isError,
312
+ };
313
+ }
314
+ else {
315
+ const executed = await executePreparedToolCall(preparation, signal, emit);
316
+ finalized = await finalizeExecutedToolCall(currentContext, assistantMessage, preparation, executed, config, signal);
317
+ }
318
+ await emitToolExecutionEnd(finalized, emit);
319
+ const toolResultMessage = createToolResultMessage(finalized);
320
+ await emitToolResultMessage(toolResultMessage, emit);
321
+ finalizedCalls.push(finalized);
322
+ messages.push(toolResultMessage);
323
+ if (signal?.aborted) {
324
+ break;
325
+ }
326
+ }
327
+ return {
328
+ messages,
329
+ terminate: shouldTerminateToolBatch(finalizedCalls),
330
+ };
331
+ }
332
+ async function executeToolCallsParallel(currentContext, assistantMessage, toolCalls, config, signal, emit) {
333
+ const finalizedCalls = [];
334
+ for (const toolCall of toolCalls) {
335
+ await emit({
336
+ type: "tool_execution_start",
337
+ toolCallId: toolCall.id,
338
+ toolName: toolCall.name,
339
+ args: toolCall.arguments,
340
+ });
341
+ const preparation = await prepareToolCall(currentContext, assistantMessage, toolCall, config, signal);
342
+ if (preparation.kind === "immediate") {
343
+ const finalized = {
344
+ toolCall,
345
+ result: preparation.result,
346
+ isError: preparation.isError,
347
+ };
348
+ await emitToolExecutionEnd(finalized, emit);
349
+ finalizedCalls.push(finalized);
350
+ if (signal?.aborted) {
351
+ break;
352
+ }
353
+ continue;
354
+ }
355
+ finalizedCalls.push(async () => {
356
+ const executed = await executePreparedToolCall(preparation, signal, emit);
357
+ const finalized = await finalizeExecutedToolCall(currentContext, assistantMessage, preparation, executed, config, signal);
358
+ await emitToolExecutionEnd(finalized, emit);
359
+ return finalized;
360
+ });
361
+ if (signal?.aborted) {
362
+ break;
363
+ }
364
+ }
365
+ const orderedFinalizedCalls = await Promise.all(finalizedCalls.map((entry) => (typeof entry === "function" ? entry() : Promise.resolve(entry))));
366
+ const messages = [];
367
+ for (const finalized of orderedFinalizedCalls) {
368
+ const toolResultMessage = createToolResultMessage(finalized);
369
+ await emitToolResultMessage(toolResultMessage, emit);
370
+ messages.push(toolResultMessage);
371
+ }
372
+ return {
373
+ messages,
374
+ terminate: shouldTerminateToolBatch(orderedFinalizedCalls),
375
+ };
376
+ }
377
+ function shouldTerminateToolBatch(finalizedCalls) {
378
+ return finalizedCalls.length > 0 && finalizedCalls.every((finalized) => finalized.result.terminate === true);
379
+ }
380
+ function prepareToolCallArguments(tool, toolCall) {
381
+ if (!tool.prepareArguments) {
382
+ return toolCall;
383
+ }
384
+ const preparedArguments = tool.prepareArguments(toolCall.arguments);
385
+ if (preparedArguments === toolCall.arguments) {
386
+ return toolCall;
387
+ }
388
+ return {
389
+ ...toolCall,
390
+ arguments: preparedArguments,
391
+ };
392
+ }
393
+ async function prepareToolCall(currentContext, assistantMessage, toolCall, config, signal) {
394
+ const tool = currentContext.tools?.find((t) => t.name === toolCall.name);
395
+ if (!tool) {
396
+ return {
397
+ kind: "immediate",
398
+ result: createErrorToolResult(`Tool ${toolCall.name} not found`),
399
+ isError: true,
400
+ };
401
+ }
402
+ try {
403
+ const preparedToolCall = prepareToolCallArguments(tool, toolCall);
404
+ const validatedArgs = validateToolArguments(tool, preparedToolCall);
405
+ if (config.beforeToolCall) {
406
+ const beforeResult = await config.beforeToolCall({
407
+ assistantMessage,
408
+ toolCall,
409
+ args: validatedArgs,
410
+ context: currentContext,
411
+ }, signal);
412
+ if (signal?.aborted) {
413
+ return {
414
+ kind: "immediate",
415
+ result: createErrorToolResult("Operation aborted"),
416
+ isError: true,
417
+ };
418
+ }
419
+ if (beforeResult?.block) {
420
+ return {
421
+ kind: "immediate",
422
+ result: createErrorToolResult(beforeResult.reason || "Tool execution was blocked"),
423
+ isError: true,
424
+ };
425
+ }
426
+ }
427
+ if (signal?.aborted) {
428
+ return {
429
+ kind: "immediate",
430
+ result: createErrorToolResult("Operation aborted"),
431
+ isError: true,
432
+ };
433
+ }
434
+ return {
435
+ kind: "prepared",
436
+ toolCall,
437
+ tool,
438
+ args: validatedArgs,
439
+ };
440
+ }
441
+ catch (error) {
442
+ return {
443
+ kind: "immediate",
444
+ result: createErrorToolResult(error instanceof Error ? error.message : String(error)),
445
+ isError: true,
446
+ };
447
+ }
448
+ }
449
+ async function executePreparedToolCall(prepared, signal, emit) {
450
+ const updateEvents = [];
451
+ let acceptingUpdates = true;
452
+ try {
453
+ const result = await prepared.tool.execute(prepared.toolCall.id, prepared.args, signal, (partialResult) => {
454
+ if (!acceptingUpdates)
455
+ return;
456
+ updateEvents.push(Promise.resolve(emit({
457
+ type: "tool_execution_update",
458
+ toolCallId: prepared.toolCall.id,
459
+ toolName: prepared.toolCall.name,
460
+ args: prepared.toolCall.arguments,
461
+ partialResult,
462
+ })));
463
+ });
464
+ acceptingUpdates = false;
465
+ await Promise.all(updateEvents);
466
+ return { result, isError: false };
467
+ }
468
+ catch (error) {
469
+ acceptingUpdates = false;
470
+ await Promise.all(updateEvents);
471
+ return {
472
+ result: createErrorToolResult(error instanceof Error ? error.message : String(error)),
473
+ isError: true,
474
+ };
475
+ }
476
+ finally {
477
+ acceptingUpdates = false;
478
+ }
479
+ }
480
+ async function finalizeExecutedToolCall(currentContext, assistantMessage, prepared, executed, config, signal) {
481
+ let result = executed.result;
482
+ let isError = executed.isError;
483
+ if (config.afterToolCall) {
484
+ try {
485
+ const afterResult = await config.afterToolCall({
486
+ assistantMessage,
487
+ toolCall: prepared.toolCall,
488
+ args: prepared.args,
489
+ result,
490
+ isError,
491
+ context: currentContext,
492
+ }, signal);
493
+ if (afterResult) {
494
+ result = {
495
+ ...result,
496
+ content: afterResult.content ?? result.content,
497
+ details: afterResult.details ?? result.details,
498
+ terminate: afterResult.terminate ?? result.terminate,
499
+ };
500
+ isError = afterResult.isError ?? isError;
501
+ }
502
+ }
503
+ catch (error) {
504
+ result = createErrorToolResult(error instanceof Error ? error.message : String(error));
505
+ isError = true;
506
+ }
507
+ }
508
+ return {
509
+ toolCall: prepared.toolCall,
510
+ result,
511
+ isError,
512
+ };
513
+ }
514
+ function createErrorToolResult(message) {
515
+ return {
516
+ content: [{ type: "text", text: message }],
517
+ details: {},
518
+ };
519
+ }
520
+ async function emitToolExecutionEnd(finalized, emit) {
521
+ await emit({
522
+ type: "tool_execution_end",
523
+ toolCallId: finalized.toolCall.id,
524
+ toolName: finalized.toolCall.name,
525
+ result: finalized.result,
526
+ isError: finalized.isError,
527
+ });
528
+ }
529
+ function createToolResultMessage(finalized) {
530
+ return {
531
+ role: "toolResult",
532
+ toolCallId: finalized.toolCall.id,
533
+ toolName: finalized.toolCall.name,
534
+ // Untyped tools (JS extensions) can return results without content; normalize
535
+ // so the null never enters session history or provider payloads.
536
+ content: finalized.result.content ?? [],
537
+ details: finalized.result.details,
538
+ ...(finalized.result.addedToolNames?.length ? { addedToolNames: finalized.result.addedToolNames } : {}),
539
+ isError: finalized.isError,
540
+ timestamp: Date.now(),
541
+ };
542
+ }
543
+ async function emitToolResultMessage(toolResultMessage, emit) {
544
+ await emit({ type: "message_start", message: toolResultMessage });
545
+ await emit({ type: "message_end", message: toolResultMessage });
546
+ }
547
+ //# sourceMappingURL=agent-loop.js.map