@warlock.js/ai 4.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (490) hide show
  1. package/README.md +72 -0
  2. package/cjs/index.cjs +8625 -0
  3. package/cjs/index.cjs.map +1 -0
  4. package/esm/agent/agent-config.type.d.mts +160 -0
  5. package/esm/agent/agent-config.type.d.mts.map +1 -0
  6. package/esm/agent/agent-input-builder.mjs +111 -0
  7. package/esm/agent/agent-input-builder.mjs.map +1 -0
  8. package/esm/agent/agent-log-event.mjs +101 -0
  9. package/esm/agent/agent-log-event.mjs.map +1 -0
  10. package/esm/agent/agent-stream.d.mts +47 -0
  11. package/esm/agent/agent-stream.d.mts.map +1 -0
  12. package/esm/agent/agent-stream.mjs +82 -0
  13. package/esm/agent/agent-stream.mjs.map +1 -0
  14. package/esm/agent/agent-to-stream-event.mjs +86 -0
  15. package/esm/agent/agent-to-stream-event.mjs.map +1 -0
  16. package/esm/agent/agent.d.mts +38 -0
  17. package/esm/agent/agent.d.mts.map +1 -0
  18. package/esm/agent/agent.mjs +974 -0
  19. package/esm/agent/agent.mjs.map +1 -0
  20. package/esm/agent/index.d.mts +3 -0
  21. package/esm/agent/index.mjs +4 -0
  22. package/esm/agent/json-stream-guard.mjs +400 -0
  23. package/esm/agent/json-stream-guard.mjs.map +1 -0
  24. package/esm/ai.d.mts +64 -0
  25. package/esm/ai.d.mts.map +1 -0
  26. package/esm/ai.mjs +65 -0
  27. package/esm/ai.mjs.map +1 -0
  28. package/esm/config.d.mts +79 -0
  29. package/esm/config.d.mts.map +1 -0
  30. package/esm/config.mjs +43 -0
  31. package/esm/config.mjs.map +1 -0
  32. package/esm/contracts/agent/agent-options.type.d.mts +132 -0
  33. package/esm/contracts/agent/agent-options.type.d.mts.map +1 -0
  34. package/esm/contracts/agent/agent.contract.d.mts +92 -0
  35. package/esm/contracts/agent/agent.contract.d.mts.map +1 -0
  36. package/esm/contracts/agent/index.d.mts +2 -0
  37. package/esm/contracts/attachment.type.d.mts +100 -0
  38. package/esm/contracts/attachment.type.d.mts.map +1 -0
  39. package/esm/contracts/content-part.type.d.mts +55 -0
  40. package/esm/contracts/content-part.type.d.mts.map +1 -0
  41. package/esm/contracts/conversation-message.type.d.mts +51 -0
  42. package/esm/contracts/conversation-message.type.d.mts.map +1 -0
  43. package/esm/contracts/embedder.contract.d.mts +69 -0
  44. package/esm/contracts/embedder.contract.d.mts.map +1 -0
  45. package/esm/contracts/end.type.d.mts +53 -0
  46. package/esm/contracts/end.type.d.mts.map +1 -0
  47. package/esm/contracts/end.type.mjs +47 -0
  48. package/esm/contracts/end.type.mjs.map +1 -0
  49. package/esm/contracts/events/agent-events.type.d.mts +71 -0
  50. package/esm/contracts/events/agent-events.type.d.mts.map +1 -0
  51. package/esm/contracts/events/complete-event.type.d.mts +33 -0
  52. package/esm/contracts/events/complete-event.type.d.mts.map +1 -0
  53. package/esm/contracts/events/event-identity.type.d.mts +30 -0
  54. package/esm/contracts/events/event-identity.type.d.mts.map +1 -0
  55. package/esm/contracts/events/event-map.type.d.mts +80 -0
  56. package/esm/contracts/events/event-map.type.d.mts.map +1 -0
  57. package/esm/contracts/events/index.d.mts +7 -0
  58. package/esm/contracts/events/supervisor-events.type.d.mts +162 -0
  59. package/esm/contracts/events/supervisor-events.type.d.mts.map +1 -0
  60. package/esm/contracts/events/usage-event.type.d.mts +39 -0
  61. package/esm/contracts/events/usage-event.type.d.mts.map +1 -0
  62. package/esm/contracts/events/workflow-events.type.d.mts +51 -0
  63. package/esm/contracts/events/workflow-events.type.d.mts.map +1 -0
  64. package/esm/contracts/executable.contract.d.mts +25 -0
  65. package/esm/contracts/executable.contract.d.mts.map +1 -0
  66. package/esm/contracts/finish-reason.type.d.mts +17 -0
  67. package/esm/contracts/finish-reason.type.d.mts.map +1 -0
  68. package/esm/contracts/index.d.mts +63 -0
  69. package/esm/contracts/middleware/index.d.mts +3 -0
  70. package/esm/contracts/middleware/middleware-context.type.d.mts +99 -0
  71. package/esm/contracts/middleware/middleware-context.type.d.mts.map +1 -0
  72. package/esm/contracts/middleware/middleware-state.type.d.mts +34 -0
  73. package/esm/contracts/middleware/middleware-state.type.d.mts.map +1 -0
  74. package/esm/contracts/middleware/middleware.contract.d.mts +140 -0
  75. package/esm/contracts/middleware/middleware.contract.d.mts.map +1 -0
  76. package/esm/contracts/model-tool-call-request.type.d.mts +58 -0
  77. package/esm/contracts/model-tool-call-request.type.d.mts.map +1 -0
  78. package/esm/contracts/model.contract.d.mts +164 -0
  79. package/esm/contracts/model.contract.d.mts.map +1 -0
  80. package/esm/contracts/placeholders.type.d.mts +23 -0
  81. package/esm/contracts/placeholders.type.d.mts.map +1 -0
  82. package/esm/contracts/result/agent-result.type.d.mts +33 -0
  83. package/esm/contracts/result/agent-result.type.d.mts.map +1 -0
  84. package/esm/contracts/result/attempt-entry.type.d.mts +40 -0
  85. package/esm/contracts/result/attempt-entry.type.d.mts.map +1 -0
  86. package/esm/contracts/result/base-report.type.d.mts +137 -0
  87. package/esm/contracts/result/base-report.type.d.mts.map +1 -0
  88. package/esm/contracts/result/base-report.type.mjs +17 -0
  89. package/esm/contracts/result/base-report.type.mjs.map +1 -0
  90. package/esm/contracts/result/base-result.type.d.mts +26 -0
  91. package/esm/contracts/result/base-result.type.d.mts.map +1 -0
  92. package/esm/contracts/result/execute-result.type.d.mts +40 -0
  93. package/esm/contracts/result/execute-result.type.d.mts.map +1 -0
  94. package/esm/contracts/result/execution-report.type.d.mts +50 -0
  95. package/esm/contracts/result/execution-report.type.d.mts.map +1 -0
  96. package/esm/contracts/result/index.d.mts +14 -0
  97. package/esm/contracts/result/llm-trip.type.d.mts +36 -0
  98. package/esm/contracts/result/llm-trip.type.d.mts.map +1 -0
  99. package/esm/contracts/result/model-pricing.type.d.mts +51 -0
  100. package/esm/contracts/result/model-pricing.type.d.mts.map +1 -0
  101. package/esm/contracts/result/session-send-result.type.d.mts +29 -0
  102. package/esm/contracts/result/session-send-result.type.d.mts.map +1 -0
  103. package/esm/contracts/result/step-result.type.d.mts +43 -0
  104. package/esm/contracts/result/step-result.type.d.mts.map +1 -0
  105. package/esm/contracts/result/supervisor-result.type.d.mts +86 -0
  106. package/esm/contracts/result/supervisor-result.type.d.mts.map +1 -0
  107. package/esm/contracts/result/tool-call.type.d.mts +44 -0
  108. package/esm/contracts/result/tool-call.type.d.mts.map +1 -0
  109. package/esm/contracts/result/usage.type.d.mts +57 -0
  110. package/esm/contracts/result/usage.type.d.mts.map +1 -0
  111. package/esm/contracts/result/workflow-result.type.d.mts +45 -0
  112. package/esm/contracts/result/workflow-result.type.d.mts.map +1 -0
  113. package/esm/contracts/sdk-adapter.contract.d.mts +77 -0
  114. package/esm/contracts/sdk-adapter.contract.d.mts.map +1 -0
  115. package/esm/contracts/stream/stream-event.type.d.mts +68 -0
  116. package/esm/contracts/stream/stream-event.type.d.mts.map +1 -0
  117. package/esm/contracts/stream/stream.contract.d.mts +61 -0
  118. package/esm/contracts/stream/stream.contract.d.mts.map +1 -0
  119. package/esm/contracts/streaming-tool-guard-config.type.d.mts +78 -0
  120. package/esm/contracts/streaming-tool-guard-config.type.d.mts.map +1 -0
  121. package/esm/contracts/supervisor/ack-entry.type.d.mts +97 -0
  122. package/esm/contracts/supervisor/ack-entry.type.d.mts.map +1 -0
  123. package/esm/contracts/supervisor/classifier-context.type.d.mts +189 -0
  124. package/esm/contracts/supervisor/classifier-context.type.d.mts.map +1 -0
  125. package/esm/contracts/supervisor/dispatch-context.type.d.mts +235 -0
  126. package/esm/contracts/supervisor/dispatch-context.type.d.mts.map +1 -0
  127. package/esm/contracts/supervisor/evaluate-context.type.d.mts +124 -0
  128. package/esm/contracts/supervisor/evaluate-context.type.d.mts.map +1 -0
  129. package/esm/contracts/supervisor/index.d.mts +16 -0
  130. package/esm/contracts/supervisor/intent-entry.type.d.mts +254 -0
  131. package/esm/contracts/supervisor/intent-entry.type.d.mts.map +1 -0
  132. package/esm/contracts/supervisor/iteration-snapshot.type.d.mts +117 -0
  133. package/esm/contracts/supervisor/iteration-snapshot.type.d.mts.map +1 -0
  134. package/esm/contracts/supervisor/next.type.d.mts +25 -0
  135. package/esm/contracts/supervisor/next.type.d.mts.map +1 -0
  136. package/esm/contracts/supervisor/route-context.type.d.mts +91 -0
  137. package/esm/contracts/supervisor/route-context.type.d.mts.map +1 -0
  138. package/esm/contracts/supervisor/router-entry.type.d.mts +67 -0
  139. package/esm/contracts/supervisor/router-entry.type.d.mts.map +1 -0
  140. package/esm/contracts/supervisor/supervisor-config.type.d.mts +356 -0
  141. package/esm/contracts/supervisor/supervisor-config.type.d.mts.map +1 -0
  142. package/esm/contracts/supervisor/supervisor-execute-options.type.d.mts +90 -0
  143. package/esm/contracts/supervisor/supervisor-execute-options.type.d.mts.map +1 -0
  144. package/esm/contracts/supervisor/supervisor-input.type.d.mts +24 -0
  145. package/esm/contracts/supervisor/supervisor-input.type.d.mts.map +1 -0
  146. package/esm/contracts/supervisor/supervisor-snapshot.type.d.mts +49 -0
  147. package/esm/contracts/supervisor/supervisor-snapshot.type.d.mts.map +1 -0
  148. package/esm/contracts/supervisor/supervisor-stream-event.type.d.mts +16 -0
  149. package/esm/contracts/supervisor/supervisor-stream-event.type.d.mts.map +1 -0
  150. package/esm/contracts/supervisor/supervisor.contract.d.mts +126 -0
  151. package/esm/contracts/supervisor/supervisor.contract.d.mts.map +1 -0
  152. package/esm/contracts/system-prompt.contract.d.mts +118 -0
  153. package/esm/contracts/system-prompt.contract.d.mts.map +1 -0
  154. package/esm/contracts/tool.contract.d.mts +161 -0
  155. package/esm/contracts/tool.contract.d.mts.map +1 -0
  156. package/esm/contracts/workflow/index.d.mts +6 -0
  157. package/esm/contracts/workflow/next-step-result.type.d.mts +17 -0
  158. package/esm/contracts/workflow/next-step-result.type.d.mts.map +1 -0
  159. package/esm/contracts/workflow/retry-config.type.d.mts +19 -0
  160. package/esm/contracts/workflow/retry-config.type.d.mts.map +1 -0
  161. package/esm/contracts/workflow/step.contract.d.mts +189 -0
  162. package/esm/contracts/workflow/step.contract.d.mts.map +1 -0
  163. package/esm/contracts/workflow/workflow-context.type.d.mts +45 -0
  164. package/esm/contracts/workflow/workflow-context.type.d.mts.map +1 -0
  165. package/esm/contracts/workflow/workflow-snapshot.type.d.mts +24 -0
  166. package/esm/contracts/workflow/workflow-snapshot.type.d.mts.map +1 -0
  167. package/esm/contracts/workflow/workflow.contract.d.mts +142 -0
  168. package/esm/contracts/workflow/workflow.contract.d.mts.map +1 -0
  169. package/esm/errors/agent-cancelled-error.d.mts +49 -0
  170. package/esm/errors/agent-cancelled-error.d.mts.map +1 -0
  171. package/esm/errors/agent-cancelled-error.mjs +43 -0
  172. package/esm/errors/agent-cancelled-error.mjs.map +1 -0
  173. package/esm/errors/agent-execution-error.d.mts +32 -0
  174. package/esm/errors/agent-execution-error.d.mts.map +1 -0
  175. package/esm/errors/agent-execution-error.mjs +35 -0
  176. package/esm/errors/agent-execution-error.mjs.map +1 -0
  177. package/esm/errors/agent-max-trips-error.d.mts +45 -0
  178. package/esm/errors/agent-max-trips-error.d.mts.map +1 -0
  179. package/esm/errors/agent-max-trips-error.mjs +41 -0
  180. package/esm/errors/agent-max-trips-error.mjs.map +1 -0
  181. package/esm/errors/ai-error.d.mts +94 -0
  182. package/esm/errors/ai-error.d.mts.map +1 -0
  183. package/esm/errors/ai-error.mjs +68 -0
  184. package/esm/errors/ai-error.mjs.map +1 -0
  185. package/esm/errors/budget-exceeded-error.d.mts +41 -0
  186. package/esm/errors/budget-exceeded-error.d.mts.map +1 -0
  187. package/esm/errors/budget-exceeded-error.mjs +31 -0
  188. package/esm/errors/budget-exceeded-error.mjs.map +1 -0
  189. package/esm/errors/content-filter-error.d.mts +33 -0
  190. package/esm/errors/content-filter-error.d.mts.map +1 -0
  191. package/esm/errors/content-filter-error.mjs +28 -0
  192. package/esm/errors/content-filter-error.mjs.map +1 -0
  193. package/esm/errors/context-length-exceeded-error.d.mts +38 -0
  194. package/esm/errors/context-length-exceeded-error.d.mts.map +1 -0
  195. package/esm/errors/context-length-exceeded-error.mjs +31 -0
  196. package/esm/errors/context-length-exceeded-error.mjs.map +1 -0
  197. package/esm/errors/error-category.type.d.mts +30 -0
  198. package/esm/errors/error-category.type.d.mts.map +1 -0
  199. package/esm/errors/error-code.type.d.mts +19 -0
  200. package/esm/errors/error-code.type.d.mts.map +1 -0
  201. package/esm/errors/guardrail-violation-error.d.mts +55 -0
  202. package/esm/errors/guardrail-violation-error.d.mts.map +1 -0
  203. package/esm/errors/guardrail-violation-error.mjs +41 -0
  204. package/esm/errors/guardrail-violation-error.mjs.map +1 -0
  205. package/esm/errors/index.d.mts +29 -0
  206. package/esm/errors/index.mjs +29 -0
  207. package/esm/errors/invalid-request-error.d.mts +27 -0
  208. package/esm/errors/invalid-request-error.d.mts.map +1 -0
  209. package/esm/errors/invalid-request-error.mjs +31 -0
  210. package/esm/errors/invalid-request-error.mjs.map +1 -0
  211. package/esm/errors/max-iterations-error.d.mts +31 -0
  212. package/esm/errors/max-iterations-error.d.mts.map +1 -0
  213. package/esm/errors/max-iterations-error.mjs +32 -0
  214. package/esm/errors/max-iterations-error.mjs.map +1 -0
  215. package/esm/errors/max-steps-exceeded-error.d.mts +20 -0
  216. package/esm/errors/max-steps-exceeded-error.d.mts.map +1 -0
  217. package/esm/errors/max-steps-exceeded-error.mjs +21 -0
  218. package/esm/errors/max-steps-exceeded-error.mjs.map +1 -0
  219. package/esm/errors/provider-auth-error.d.mts +22 -0
  220. package/esm/errors/provider-auth-error.d.mts.map +1 -0
  221. package/esm/errors/provider-auth-error.mjs +26 -0
  222. package/esm/errors/provider-auth-error.mjs.map +1 -0
  223. package/esm/errors/provider-error.d.mts +38 -0
  224. package/esm/errors/provider-error.d.mts.map +1 -0
  225. package/esm/errors/provider-error.mjs +42 -0
  226. package/esm/errors/provider-error.mjs.map +1 -0
  227. package/esm/errors/provider-rate-limit-error.d.mts +34 -0
  228. package/esm/errors/provider-rate-limit-error.d.mts.map +1 -0
  229. package/esm/errors/provider-rate-limit-error.mjs +31 -0
  230. package/esm/errors/provider-rate-limit-error.mjs.map +1 -0
  231. package/esm/errors/provider-timeout-error.d.mts +22 -0
  232. package/esm/errors/provider-timeout-error.d.mts.map +1 -0
  233. package/esm/errors/provider-timeout-error.mjs +26 -0
  234. package/esm/errors/provider-timeout-error.mjs.map +1 -0
  235. package/esm/errors/quota-exceeded-error.d.mts +36 -0
  236. package/esm/errors/quota-exceeded-error.d.mts.map +1 -0
  237. package/esm/errors/quota-exceeded-error.mjs +40 -0
  238. package/esm/errors/quota-exceeded-error.mjs.map +1 -0
  239. package/esm/errors/routing-error.d.mts +23 -0
  240. package/esm/errors/routing-error.d.mts.map +1 -0
  241. package/esm/errors/routing-error.mjs +23 -0
  242. package/esm/errors/routing-error.mjs.map +1 -0
  243. package/esm/errors/schema-validation-error.d.mts +40 -0
  244. package/esm/errors/schema-validation-error.d.mts.map +1 -0
  245. package/esm/errors/schema-validation-error.mjs +37 -0
  246. package/esm/errors/schema-validation-error.mjs.map +1 -0
  247. package/esm/errors/step-failed-error.d.mts +20 -0
  248. package/esm/errors/step-failed-error.d.mts.map +1 -0
  249. package/esm/errors/step-failed-error.mjs +19 -0
  250. package/esm/errors/step-failed-error.mjs.map +1 -0
  251. package/esm/errors/supervisor-cancelled-error.d.mts +29 -0
  252. package/esm/errors/supervisor-cancelled-error.d.mts.map +1 -0
  253. package/esm/errors/supervisor-cancelled-error.mjs +29 -0
  254. package/esm/errors/supervisor-cancelled-error.mjs.map +1 -0
  255. package/esm/errors/supervisor-drift-error.d.mts +31 -0
  256. package/esm/errors/supervisor-drift-error.d.mts.map +1 -0
  257. package/esm/errors/supervisor-drift-error.mjs +30 -0
  258. package/esm/errors/supervisor-drift-error.mjs.map +1 -0
  259. package/esm/errors/supervisor-failed-error.d.mts +40 -0
  260. package/esm/errors/supervisor-failed-error.d.mts.map +1 -0
  261. package/esm/errors/supervisor-failed-error.mjs +43 -0
  262. package/esm/errors/supervisor-failed-error.mjs.map +1 -0
  263. package/esm/errors/supervisor-routing-error.d.mts +44 -0
  264. package/esm/errors/supervisor-routing-error.d.mts.map +1 -0
  265. package/esm/errors/supervisor-routing-error.mjs +39 -0
  266. package/esm/errors/supervisor-routing-error.mjs.map +1 -0
  267. package/esm/errors/tool-execution-error.d.mts +35 -0
  268. package/esm/errors/tool-execution-error.d.mts.map +1 -0
  269. package/esm/errors/tool-execution-error.mjs +32 -0
  270. package/esm/errors/tool-execution-error.mjs.map +1 -0
  271. package/esm/errors/workflow-cancelled-error.d.mts +23 -0
  272. package/esm/errors/workflow-cancelled-error.d.mts.map +1 -0
  273. package/esm/errors/workflow-cancelled-error.mjs +23 -0
  274. package/esm/errors/workflow-cancelled-error.mjs.map +1 -0
  275. package/esm/errors/workflow-drift-error.d.mts +25 -0
  276. package/esm/errors/workflow-drift-error.d.mts.map +1 -0
  277. package/esm/errors/workflow-drift-error.mjs +24 -0
  278. package/esm/errors/workflow-drift-error.mjs.map +1 -0
  279. package/esm/errors/workflow-error.d.mts +15 -0
  280. package/esm/errors/workflow-error.d.mts.map +1 -0
  281. package/esm/errors/workflow-error.mjs +18 -0
  282. package/esm/errors/workflow-error.mjs.map +1 -0
  283. package/esm/index.d.mts +137 -0
  284. package/esm/index.mjs +81 -0
  285. package/esm/middleware/builtins/budget.d.mts +103 -0
  286. package/esm/middleware/builtins/budget.d.mts.map +1 -0
  287. package/esm/middleware/builtins/budget.mjs +100 -0
  288. package/esm/middleware/builtins/budget.mjs.map +1 -0
  289. package/esm/middleware/builtins/guardrail.d.mts +92 -0
  290. package/esm/middleware/builtins/guardrail.d.mts.map +1 -0
  291. package/esm/middleware/builtins/guardrail.mjs +76 -0
  292. package/esm/middleware/builtins/guardrail.mjs.map +1 -0
  293. package/esm/middleware/builtins/semantic-cache.d.mts +106 -0
  294. package/esm/middleware/builtins/semantic-cache.d.mts.map +1 -0
  295. package/esm/middleware/builtins/semantic-cache.mjs +149 -0
  296. package/esm/middleware/builtins/semantic-cache.mjs.map +1 -0
  297. package/esm/middleware/helpers/compose.d.mts +42 -0
  298. package/esm/middleware/helpers/compose.d.mts.map +1 -0
  299. package/esm/middleware/helpers/compose.mjs +52 -0
  300. package/esm/middleware/helpers/compose.mjs.map +1 -0
  301. package/esm/middleware/helpers/for-tool.d.mts +55 -0
  302. package/esm/middleware/helpers/for-tool.d.mts.map +1 -0
  303. package/esm/middleware/helpers/for-tool.mjs +80 -0
  304. package/esm/middleware/helpers/for-tool.mjs.map +1 -0
  305. package/esm/middleware/helpers/index.d.mts +2 -0
  306. package/esm/middleware/index.d.mts +8 -0
  307. package/esm/middleware/index.mjs +10 -0
  308. package/esm/middleware/pipeline.d.mts +70 -0
  309. package/esm/middleware/pipeline.d.mts.map +1 -0
  310. package/esm/middleware/pipeline.mjs +100 -0
  311. package/esm/middleware/pipeline.mjs.map +1 -0
  312. package/esm/middleware/utils/extract-user-text.d.mts +33 -0
  313. package/esm/middleware/utils/extract-user-text.d.mts.map +1 -0
  314. package/esm/middleware/utils/extract-user-text.mjs +40 -0
  315. package/esm/middleware/utils/extract-user-text.mjs.map +1 -0
  316. package/esm/middleware/utils/index.d.mts +2 -0
  317. package/esm/middleware/utils/namespaced-state.d.mts +60 -0
  318. package/esm/middleware/utils/namespaced-state.d.mts.map +1 -0
  319. package/esm/middleware/utils/namespaced-state.mjs +60 -0
  320. package/esm/middleware/utils/namespaced-state.mjs.map +1 -0
  321. package/esm/mock/index.d.mts +4 -0
  322. package/esm/mock/index.mjs +5 -0
  323. package/esm/mock/mock-agent.d.mts +41 -0
  324. package/esm/mock/mock-agent.d.mts.map +1 -0
  325. package/esm/mock/mock-agent.mjs +39 -0
  326. package/esm/mock/mock-agent.mjs.map +1 -0
  327. package/esm/mock/mock-config.type.d.mts +31 -0
  328. package/esm/mock/mock-config.type.d.mts.map +1 -0
  329. package/esm/mock/mock-model.d.mts +94 -0
  330. package/esm/mock/mock-model.d.mts.map +1 -0
  331. package/esm/mock/mock-model.mjs +150 -0
  332. package/esm/mock/mock-model.mjs.map +1 -0
  333. package/esm/mock/mock-sdk.d.mts +25 -0
  334. package/esm/mock/mock-sdk.d.mts.map +1 -0
  335. package/esm/mock/mock-sdk.mjs +37 -0
  336. package/esm/mock/mock-sdk.mjs.map +1 -0
  337. package/esm/supervisor/as-tool.d.mts +45 -0
  338. package/esm/supervisor/as-tool.d.mts.map +1 -0
  339. package/esm/supervisor/as-tool.mjs +80 -0
  340. package/esm/supervisor/as-tool.mjs.map +1 -0
  341. package/esm/supervisor/cancellation.d.mts +12 -0
  342. package/esm/supervisor/cancellation.d.mts.map +1 -0
  343. package/esm/supervisor/cancellation.mjs +22 -0
  344. package/esm/supervisor/cancellation.mjs.map +1 -0
  345. package/esm/supervisor/decide.mjs +272 -0
  346. package/esm/supervisor/decide.mjs.map +1 -0
  347. package/esm/supervisor/emitter.d.mts +27 -0
  348. package/esm/supervisor/emitter.d.mts.map +1 -0
  349. package/esm/supervisor/emitter.mjs +47 -0
  350. package/esm/supervisor/emitter.mjs.map +1 -0
  351. package/esm/supervisor/entries.d.mts +141 -0
  352. package/esm/supervisor/entries.d.mts.map +1 -0
  353. package/esm/supervisor/entries.mjs +206 -0
  354. package/esm/supervisor/entries.mjs.map +1 -0
  355. package/esm/supervisor/execution.d.mts +637 -0
  356. package/esm/supervisor/execution.d.mts.map +1 -0
  357. package/esm/supervisor/execution.mjs +1868 -0
  358. package/esm/supervisor/execution.mjs.map +1 -0
  359. package/esm/supervisor/index.d.mts +11 -0
  360. package/esm/supervisor/index.mjs +12 -0
  361. package/esm/supervisor/router-prompt.d.mts +56 -0
  362. package/esm/supervisor/router-prompt.d.mts.map +1 -0
  363. package/esm/supervisor/router-prompt.mjs +52 -0
  364. package/esm/supervisor/router-prompt.mjs.map +1 -0
  365. package/esm/supervisor/signature.d.mts +28 -0
  366. package/esm/supervisor/signature.d.mts.map +1 -0
  367. package/esm/supervisor/signature.mjs +89 -0
  368. package/esm/supervisor/signature.mjs.map +1 -0
  369. package/esm/supervisor/snapshot.d.mts +54 -0
  370. package/esm/supervisor/snapshot.d.mts.map +1 -0
  371. package/esm/supervisor/snapshot.mjs +77 -0
  372. package/esm/supervisor/snapshot.mjs.map +1 -0
  373. package/esm/supervisor/supervisor-stream.d.mts +29 -0
  374. package/esm/supervisor/supervisor-stream.d.mts.map +1 -0
  375. package/esm/supervisor/supervisor-stream.mjs +89 -0
  376. package/esm/supervisor/supervisor-stream.mjs.map +1 -0
  377. package/esm/supervisor/supervisor.d.mts +27 -0
  378. package/esm/supervisor/supervisor.d.mts.map +1 -0
  379. package/esm/supervisor/supervisor.mjs +138 -0
  380. package/esm/supervisor/supervisor.mjs.map +1 -0
  381. package/esm/system-prompt/instruction.d.mts +52 -0
  382. package/esm/system-prompt/instruction.d.mts.map +1 -0
  383. package/esm/system-prompt/instruction.mjs +57 -0
  384. package/esm/system-prompt/instruction.mjs.map +1 -0
  385. package/esm/system-prompt/persona.d.mts +52 -0
  386. package/esm/system-prompt/persona.d.mts.map +1 -0
  387. package/esm/system-prompt/persona.mjs +57 -0
  388. package/esm/system-prompt/persona.mjs.map +1 -0
  389. package/esm/system-prompt/render-placeholders.d.mts +31 -0
  390. package/esm/system-prompt/render-placeholders.d.mts.map +1 -0
  391. package/esm/system-prompt/render-placeholders.mjs +58 -0
  392. package/esm/system-prompt/render-placeholders.mjs.map +1 -0
  393. package/esm/system-prompt/system-prompt.d.mts +117 -0
  394. package/esm/system-prompt/system-prompt.d.mts.map +1 -0
  395. package/esm/system-prompt/system-prompt.mjs +137 -0
  396. package/esm/system-prompt/system-prompt.mjs.map +1 -0
  397. package/esm/tool/index.d.mts +1 -0
  398. package/esm/tool/index.mjs +3 -0
  399. package/esm/tool/tool.d.mts +64 -0
  400. package/esm/tool/tool.d.mts.map +1 -0
  401. package/esm/tool/tool.mjs +184 -0
  402. package/esm/tool/tool.mjs.map +1 -0
  403. package/esm/utils/compute-cost.d.mts +58 -0
  404. package/esm/utils/compute-cost.d.mts.map +1 -0
  405. package/esm/utils/compute-cost.mjs +87 -0
  406. package/esm/utils/compute-cost.mjs.map +1 -0
  407. package/esm/utils/extract-json-payload.d.mts +33 -0
  408. package/esm/utils/extract-json-payload.d.mts.map +1 -0
  409. package/esm/utils/extract-json-payload.mjs +39 -0
  410. package/esm/utils/extract-json-payload.mjs.map +1 -0
  411. package/esm/utils/generate-run-id.d.mts +20 -0
  412. package/esm/utils/generate-run-id.d.mts.map +1 -0
  413. package/esm/utils/generate-run-id.mjs +23 -0
  414. package/esm/utils/generate-run-id.mjs.map +1 -0
  415. package/esm/utils/index.d.mts +9 -0
  416. package/esm/utils/index.mjs +11 -0
  417. package/esm/utils/json-schema.d.mts +57 -0
  418. package/esm/utils/json-schema.d.mts.map +1 -0
  419. package/esm/utils/json-schema.mjs +89 -0
  420. package/esm/utils/json-schema.mjs.map +1 -0
  421. package/esm/utils/prepare-attachment-part.d.mts +36 -0
  422. package/esm/utils/prepare-attachment-part.d.mts.map +1 -0
  423. package/esm/utils/prepare-attachment-part.mjs +140 -0
  424. package/esm/utils/prepare-attachment-part.mjs.map +1 -0
  425. package/esm/utils/resolve-attachment.d.mts +33 -0
  426. package/esm/utils/resolve-attachment.d.mts.map +1 -0
  427. package/esm/utils/resolve-attachment.mjs +73 -0
  428. package/esm/utils/resolve-attachment.mjs.map +1 -0
  429. package/esm/utils/safe-json-parse.d.mts +14 -0
  430. package/esm/utils/safe-json-parse.d.mts.map +1 -0
  431. package/esm/utils/safe-json-parse.mjs +22 -0
  432. package/esm/utils/safe-json-parse.mjs.map +1 -0
  433. package/esm/utils/stamp-report-lineage.d.mts +61 -0
  434. package/esm/utils/stamp-report-lineage.d.mts.map +1 -0
  435. package/esm/utils/stamp-report-lineage.mjs +47 -0
  436. package/esm/utils/stamp-report-lineage.mjs.map +1 -0
  437. package/esm/utils/token-count.d.mts +15 -0
  438. package/esm/utils/token-count.d.mts.map +1 -0
  439. package/esm/utils/token-count.mjs +18 -0
  440. package/esm/utils/token-count.mjs.map +1 -0
  441. package/esm/workflow/as-tool.mjs +55 -0
  442. package/esm/workflow/as-tool.mjs.map +1 -0
  443. package/esm/workflow/cancellation.mjs +44 -0
  444. package/esm/workflow/cancellation.mjs.map +1 -0
  445. package/esm/workflow/emitter.mjs +40 -0
  446. package/esm/workflow/emitter.mjs.map +1 -0
  447. package/esm/workflow/engine.mjs +362 -0
  448. package/esm/workflow/engine.mjs.map +1 -0
  449. package/esm/workflow/index.d.mts +3 -0
  450. package/esm/workflow/index.mjs +5 -0
  451. package/esm/workflow/retry.mjs +32 -0
  452. package/esm/workflow/retry.mjs.map +1 -0
  453. package/esm/workflow/router.mjs +56 -0
  454. package/esm/workflow/router.mjs.map +1 -0
  455. package/esm/workflow/run-scoped-emitter.mjs +32 -0
  456. package/esm/workflow/run-scoped-emitter.mjs.map +1 -0
  457. package/esm/workflow/signature.d.mts +7 -0
  458. package/esm/workflow/signature.d.mts.map +1 -0
  459. package/esm/workflow/signature.mjs +34 -0
  460. package/esm/workflow/signature.mjs.map +1 -0
  461. package/esm/workflow/snapshot.mjs +71 -0
  462. package/esm/workflow/snapshot.mjs.map +1 -0
  463. package/esm/workflow/state.mjs +37 -0
  464. package/esm/workflow/state.mjs.map +1 -0
  465. package/esm/workflow/step-runner.mjs +371 -0
  466. package/esm/workflow/step-runner.mjs.map +1 -0
  467. package/esm/workflow/step.d.mts +19 -0
  468. package/esm/workflow/step.d.mts.map +1 -0
  469. package/esm/workflow/step.mjs +37 -0
  470. package/esm/workflow/step.mjs.map +1 -0
  471. package/esm/workflow/workflow.d.mts +12 -0
  472. package/esm/workflow/workflow.d.mts.map +1 -0
  473. package/esm/workflow/workflow.mjs +116 -0
  474. package/esm/workflow/workflow.mjs.map +1 -0
  475. package/llms-full.txt +2293 -0
  476. package/llms.txt +20 -0
  477. package/package.json +37 -0
  478. package/skills/README.md +53 -0
  479. package/skills/ai-basics/SKILL.md +95 -0
  480. package/skills/attach-ai-middleware/SKILL.md +184 -0
  481. package/skills/define-ai-tool/SKILL.md +186 -0
  482. package/skills/embed-text/SKILL.md +105 -0
  483. package/skills/handle-ai-errors/SKILL.md +194 -0
  484. package/skills/log-ai-calls/SKILL.md +141 -0
  485. package/skills/persist-ai-data/SKILL.md +207 -0
  486. package/skills/pick-ai-provider/SKILL.md +164 -0
  487. package/skills/run-ai-agent/SKILL.md +267 -0
  488. package/skills/run-ai-workflow/SKILL.md +258 -0
  489. package/skills/run-supervisor/SKILL.md +309 -0
  490. package/skills/write-system-prompt/SKILL.md +129 -0
@@ -0,0 +1,974 @@
1
+ import { AIError } from "../errors/ai-error.mjs";
2
+ import { AgentExecutionError } from "../errors/agent-execution-error.mjs";
3
+ import { AgentCancelledError } from "../errors/agent-cancelled-error.mjs";
4
+ import { AgentMaxTripsError } from "../errors/agent-max-trips-error.mjs";
5
+ import { SchemaValidationError } from "../errors/schema-validation-error.mjs";
6
+ import "../errors/index.mjs";
7
+ import { runPipeline } from "../middleware/pipeline.mjs";
8
+ import "../middleware/index.mjs";
9
+ import { accumulateCost, computeCost } from "../utils/compute-cost.mjs";
10
+ import { extractJsonPayload } from "../utils/extract-json-payload.mjs";
11
+ import { generateRunId } from "../utils/generate-run-id.mjs";
12
+ import { safeJsonParse } from "../utils/safe-json-parse.mjs";
13
+ import { stampReportLineage } from "../utils/stamp-report-lineage.mjs";
14
+ import "../utils/index.mjs";
15
+ import { buildAgentInputMessages } from "./agent-input-builder.mjs";
16
+ import { logAgentEvent } from "./agent-log-event.mjs";
17
+ import { createAgentStream } from "./agent-stream.mjs";
18
+ import { agentEventToStreamEvent } from "./agent-to-stream-event.mjs";
19
+ import { JsonStreamGuard } from "./json-stream-guard.mjs";
20
+ import { log } from "@warlock.js/logger";
21
+
22
+ //#region ../../@warlock.js/ai/src/agent/agent.ts
23
+ const LOG_MODULE = "ai.agent";
24
+ /**
25
+ * Detect abort-flavored errors surfaced by SDK HTTP layers — the
26
+ * DOM `AbortError`, axios `ERR_CANCELED`, node-fetch's own
27
+ * `AbortError`. Used to classify them as cancellation rather than
28
+ * generic agent-execution failures.
29
+ */
30
+ function isAbortLike(err) {
31
+ if (!err || typeof err !== "object") return false;
32
+ const e = err;
33
+ return e.name === "AbortError" || e.code === "ERR_CANCELED" || e.code === "ABORT_ERR";
34
+ }
35
+ /**
36
+ * Readable synthetic name for agents constructed without an explicit
37
+ * `name`. Format: `anon_<provider>_<model>[_<tool1>+<tool2>+...]` —
38
+ * deterministic (same config → same name across restarts) and
39
+ * human-readable in logs / workflow snapshots.
40
+ *
41
+ * Keeps drift detection honest for the `ai.agent({ model })`
42
+ * one-liner without punishing it with a hashed id nobody can read.
43
+ */
44
+ function synthesizeAgentName(config) {
45
+ const provider = config.model?.provider ?? "unknown";
46
+ const model = config.model?.name ?? "unknown";
47
+ const tools = (config.tools ?? []).map((tool) => tool.name).sort().join("+");
48
+ const base = `anon_${sanitize(provider)}_${sanitize(model)}`;
49
+ return tools ? `${base}_${sanitize(tools, { keepPlus: true })}` : base;
50
+ }
51
+ function sanitize(value, opts = {}) {
52
+ const allowed = opts.keepPlus ? /[^a-zA-Z0-9._+-]/g : /[^a-zA-Z0-9._-]/g;
53
+ return value.replace(allowed, "-");
54
+ }
55
+ /**
56
+ * Authoring-time check on the middleware array. Throws an
57
+ * `AgentExecutionError` with `context: { authoring: true }` the
58
+ * moment an invalid entry is found — the agent factory surface is
59
+ * where config bugs should surface, not ten trips into a run.
60
+ *
61
+ * Validates:
62
+ * - Every entry is a non-null object with a non-empty string `name`.
63
+ * - No two entries share the same `name` (would silently collide on
64
+ * `ctx.state` keys and produce impossible-to-debug behavior).
65
+ *
66
+ * Does NOT validate that hook maps contain callable functions —
67
+ * that would catch late-binding bugs but also reject legitimate
68
+ * patterns like `before` being conditionally `undefined`. Runtime
69
+ * dispatch handles missing hooks safely.
70
+ */
71
+ function validateMiddleware(middleware) {
72
+ if (!middleware || middleware.length === 0) return;
73
+ const seen = /* @__PURE__ */ new Set();
74
+ for (let index = 0; index < middleware.length; index++) {
75
+ const entry = middleware[index];
76
+ if (!entry || typeof entry !== "object") throw new AgentExecutionError(`middleware[${index}] must be an object; received ${entry === null ? "null" : typeof entry}`, { context: {
77
+ authoring: true,
78
+ index
79
+ } });
80
+ const name = entry.name;
81
+ if (typeof name !== "string" || name.length === 0) throw new AgentExecutionError(`middleware[${index}] must have a non-empty string "name"`, { context: {
82
+ authoring: true,
83
+ index
84
+ } });
85
+ if (seen.has(name)) throw new AgentExecutionError(`duplicate middleware name "${name}" — each middleware needs a unique name so ctx.state keys do not collide`, { context: {
86
+ authoring: true,
87
+ index,
88
+ name
89
+ } });
90
+ seen.add(name);
91
+ }
92
+ }
93
+ /**
94
+ * Creates an executable AI agent from the given configuration.
95
+ *
96
+ * The agent runs a bounded trip loop: each trip calls the model, dispatches
97
+ * any requested tool calls, then loops until the model stops or `maxTrips`
98
+ * is reached. Each `execute()` / `stream()` call spawns a fresh internal
99
+ * `Execution` instance — the factory itself holds no state across calls.
100
+ *
101
+ * `execute()` never throws — any error is attached to the returned result
102
+ * under `result.error`. `stream()` surfaces errors both on the terminal
103
+ * `error` stream event and via the `stream.result` promise.
104
+ *
105
+ * @example
106
+ * const myAgent = agent({
107
+ * model: openai.model({ name: "gpt-4o" }),
108
+ * systemPrompt: "You are a helpful assistant.",
109
+ * tools: [searchTool],
110
+ * });
111
+ *
112
+ * const result = await myAgent.execute("What is the capital of Egypt?");
113
+ *
114
+ * @example
115
+ * const stream = myAgent.stream("Write a haiku about Cairo.");
116
+ *
117
+ * for await (const event of stream) {
118
+ * if (event.type === "streaming") process.stdout.write(event.delta);
119
+ * }
120
+ *
121
+ * const result = await stream.result;
122
+ */
123
+ function agent(config) {
124
+ validateMiddleware(config.middleware);
125
+ const isAnonymous = !config.name || typeof config.name !== "string";
126
+ const name = isAnonymous ? synthesizeAgentName(config) : config.name;
127
+ const resolvedConfig = {
128
+ ...config,
129
+ name
130
+ };
131
+ const instanceHandlers = /* @__PURE__ */ new Map();
132
+ function on(event, handler) {
133
+ const existing = instanceHandlers.get(event);
134
+ const bucket = existing ?? /* @__PURE__ */ new Set();
135
+ if (!existing) instanceHandlers.set(event, bucket);
136
+ bucket.add(handler);
137
+ return () => off(event, handler);
138
+ }
139
+ function off(event, handler) {
140
+ const bucket = instanceHandlers.get(event);
141
+ if (!bucket) return;
142
+ bucket.delete(handler);
143
+ if (bucket.size === 0) instanceHandlers.delete(event);
144
+ }
145
+ return {
146
+ name,
147
+ isAnonymous,
148
+ description: config.description,
149
+ async execute(input, options) {
150
+ return new Execution(resolvedConfig, input, options, void 0, instanceHandlers).run();
151
+ },
152
+ stream(input, options) {
153
+ const { controller, stream } = createAgentStream();
154
+ new Execution(resolvedConfig, input, options, controller, instanceHandlers).run();
155
+ return stream;
156
+ },
157
+ on,
158
+ off
159
+ };
160
+ }
161
+ /**
162
+ * Per-call driver that owns the full lifecycle of a single
163
+ * `agent.execute()` or `agent.stream()` invocation.
164
+ *
165
+ * **Role.** An `Execution` is the short-lived state container and phase
166
+ * orchestrator for one agent run. The public `agent()` factory stays purely
167
+ * functional — all mutable bookkeeping (trips, tool calls, usage totals,
168
+ * message history, terminal error, parsed output) lives here so each call
169
+ * gets a fresh, isolated instance.
170
+ *
171
+ * **Responsibility.**
172
+ * - Owns: building the initial message list, driving the bounded trip loop,
173
+ * dispatching tool calls safely, parsing the final output against the
174
+ * caller's schema, emitting lifecycle events (to both the user handler
175
+ * and, in stream mode, the `StreamController`), and producing the
176
+ * `AgentResult`.
177
+ * - Does NOT own: how the model produces responses (delegated to
178
+ * `ModelContract.complete` / `ModelContract.stream`), how tools execute
179
+ * (delegated to `ToolContract.invoke`), the async-queue plumbing for
180
+ * streaming (delegated to `createAgentStream`), or any cross-call state
181
+ * (factory-level concerns live in `agent()`).
182
+ *
183
+ * Streaming mode is opt-in via the fourth constructor argument: pass a
184
+ * `StreamController` and every event is mirrored into it while model calls
185
+ * are driven via `model.stream()` instead of `model.complete()`. The public
186
+ * contract of `execute()` says it never throws — `Execution` enforces that
187
+ * by funneling every unexpected error into `this.error` and returning a
188
+ * well-formed result regardless of what went wrong.
189
+ *
190
+ * Not exported — consumers interact only with the `agent()` factory (see
191
+ * §4.2 of code-style.md — "per-call execution state across phases").
192
+ *
193
+ * @example
194
+ * // Non-streaming — inside agent.execute():
195
+ * const result = await new Execution(config, input, options).run();
196
+ *
197
+ * @example
198
+ * // Streaming — inside agent.stream():
199
+ * const { controller, stream } = createAgentStream();
200
+ * void new Execution(config, input, options, controller).run();
201
+ * return stream;
202
+ */
203
+ var Execution = class {
204
+ constructor(config, input, options, streamController, instanceHandlers) {
205
+ this.config = config;
206
+ this.input = input;
207
+ this.options = options;
208
+ this.streamController = streamController;
209
+ this.instanceHandlers = instanceHandlers;
210
+ this.trips = [];
211
+ this.toolCalls = [];
212
+ this.usage = {
213
+ input: 0,
214
+ output: 0,
215
+ total: 0
216
+ };
217
+ this.messages = [];
218
+ this.startedAt = /* @__PURE__ */ new Date();
219
+ this.start = performance.now();
220
+ this.runId = generateRunId("agent");
221
+ this.logger = log;
222
+ this.middlewareState = /* @__PURE__ */ new Map();
223
+ this.maxTrips = config.maxTrips ?? 10;
224
+ this.middleware = config.middleware ?? [];
225
+ }
226
+ /**
227
+ * Base middleware context shared by every level. `state` is the
228
+ * single mutable bag threaded through `execute`, `trip`, and `tool`
229
+ * hooks for the lifetime of this execution — fresh per `execute()`
230
+ * call, never reused across runs.
231
+ */
232
+ buildExecuteContext() {
233
+ return {
234
+ agent: {
235
+ name: this.config.name ?? this.config.model.name,
236
+ isAnonymous: !this.config.name
237
+ },
238
+ model: {
239
+ name: this.config.model.name,
240
+ provider: this.config.model.provider
241
+ },
242
+ input: this.input,
243
+ options: this.options,
244
+ state: this.middlewareState,
245
+ signal: this.options?.signal
246
+ };
247
+ }
248
+ /**
249
+ * Entry point for a single agent execution. Wraps the real work
250
+ * (`runCore`) in the `execute`-level middleware pipeline, then
251
+ * emits the terminal `agent.completed` / `agent.error` events and
252
+ * closes the stream (if any) with the post-pipeline result — so
253
+ * middleware that short-circuits or transforms the final result
254
+ * still produces a well-formed public outcome.
255
+ *
256
+ * Must never throw: any error that escapes the pipeline is
257
+ * converted into an `AgentResult` with `error` populated before
258
+ * returning, preserving the `agent.execute()` public contract.
259
+ */
260
+ async run() {
261
+ const context = this.buildExecuteContext();
262
+ let result;
263
+ try {
264
+ result = await runPipeline(this.middleware, "execute", context, () => this.runCore(), this.logger);
265
+ } catch (thrown) {
266
+ this.error = this.toAIError(thrown);
267
+ result = this.buildResult();
268
+ }
269
+ if (result.error) this.emit("agent.error", { error: result.error });
270
+ this.emit("agent.completed", { result });
271
+ await this.fireCompleteHook(result);
272
+ this.streamController?.end(result);
273
+ return result;
274
+ }
275
+ /**
276
+ * Inner body wrapped by the `execute`-level pipeline. Drives the
277
+ * full lifecycle — build messages → emit starting → run trip loop
278
+ * → parse output → build result. Catches any unexpected throw and
279
+ * funnels it into `this.error` so the returned result is always
280
+ * well-formed; `execute`-level `after` hooks receive the result,
281
+ * with `error` populated when things went wrong.
282
+ */
283
+ async runCore() {
284
+ try {
285
+ await this.buildInitialMessages();
286
+ this.emit("agent.starting", { input: this.input });
287
+ await this.runTripLoop();
288
+ if (await this.parseOutput() === "failed" && this.options?.repair) await this.runRepairLoop();
289
+ } catch (thrown) {
290
+ this.error = this.toAIError(thrown);
291
+ }
292
+ return this.buildResult();
293
+ }
294
+ /**
295
+ * Resolve the system prompt (string or `SystemPromptContract`), merge
296
+ * placeholders from config + execute options, inject a structured-output
297
+ * instruction when the caller wants typed output but the model can't
298
+ * enforce it natively, prepend any conversation history, and append the
299
+ * user input. Produces the initial `messages` array the first trip sends
300
+ * to the model. Runs exactly once per execution.
301
+ */
302
+ async buildInitialMessages() {
303
+ const { messages, responseSchema } = await buildAgentInputMessages({
304
+ config: this.config,
305
+ input: this.input,
306
+ options: this.options
307
+ });
308
+ this.messages.push(...messages);
309
+ this.responseSchema = responseSchema;
310
+ }
311
+ /**
312
+ * Drive sequential trips up to `maxTrips`. Each trip may stop the loop
313
+ * naturally (model returned a non-tool-call finish), abort it (model
314
+ * threw), or continue it (model requested tools). When the loop exits
315
+ * after the cap without a natural stop, records a "Max trips exceeded"
316
+ * error so the caller can distinguish runaway tool loops from a real result.
317
+ */
318
+ async runTripLoop() {
319
+ for (let tripIndex = 0; tripIndex < this.maxTrips; tripIndex++) {
320
+ if (this.options?.signal?.aborted) {
321
+ this.error = this.makeCancelledError();
322
+ return;
323
+ }
324
+ const tripInput = tripIndex === 0 ? this.input : "[tool results]";
325
+ const outcome = await this.runTrip(tripIndex, tripInput);
326
+ if (outcome === "error" || outcome === "stop") return;
327
+ }
328
+ if (this.trips[this.trips.length - 1]?.finishReason === "tool_calls") this.error = new AgentMaxTripsError("Max trips exceeded", { maxTrips: this.maxTrips });
329
+ }
330
+ /**
331
+ * Execute one round-trip to the model. Aggregates usage into the running
332
+ * total, dispatches any requested tool calls, appends the assistant +
333
+ * tool-result messages for the next trip, and records an `LLMTrip`.
334
+ * Returns an outcome that tells `runTripLoop` whether to continue, stop,
335
+ * or abort.
336
+ */
337
+ async runTrip(tripIndex, tripInput) {
338
+ this.emit("agent.trip.started", {
339
+ tripIndex,
340
+ input: tripInput
341
+ });
342
+ const tripStartedAt = /* @__PURE__ */ new Date();
343
+ const tripStart = performance.now();
344
+ let response;
345
+ try {
346
+ response = await this.runTripThroughPipeline(tripIndex);
347
+ } catch (thrown) {
348
+ this.error = this.toAIError(thrown);
349
+ const failedTrip = {
350
+ index: tripIndex,
351
+ input: tripInput,
352
+ output: "",
353
+ finishReason: "error",
354
+ startedAt: tripStartedAt.toISOString(),
355
+ endedAt: (/* @__PURE__ */ new Date()).toISOString(),
356
+ duration: performance.now() - tripStart,
357
+ usage: {
358
+ input: 0,
359
+ output: 0,
360
+ total: 0
361
+ },
362
+ error: this.error
363
+ };
364
+ this.trips.push(failedTrip);
365
+ this.emit("agent.trip.completed", { trip: failedTrip });
366
+ this.emit("agent.error", { error: this.error });
367
+ return "error";
368
+ }
369
+ if (response.usage.cost === void 0) response.usage.cost = computeCost(response.usage, this.config.model.pricing);
370
+ this.usage.input += response.usage.input;
371
+ this.usage.output += response.usage.output;
372
+ this.usage.total += response.usage.total;
373
+ if (response.usage.cachedTokens !== void 0) this.usage.cachedTokens = (this.usage.cachedTokens ?? 0) + response.usage.cachedTokens;
374
+ this.usage.cost = accumulateCost(this.usage.cost, response.usage.cost);
375
+ await this.fireUsageHook(tripIndex, response.usage);
376
+ const isToolCallTrip = response.finishReason === "tool_calls" && response.toolCalls !== void 0 && response.toolCalls.length > 0;
377
+ const tripToolCalls = [];
378
+ if (isToolCallTrip) {
379
+ this.messages.push({
380
+ role: "assistant",
381
+ content: response.content,
382
+ toolCalls: response.toolCalls
383
+ });
384
+ for (const toolCallRequest of response.toolCalls) {
385
+ const record = await this.dispatchToolCall(toolCallRequest, tripIndex);
386
+ tripToolCalls.push(record);
387
+ }
388
+ }
389
+ const trip = {
390
+ index: tripIndex,
391
+ input: tripInput,
392
+ output: response.content,
393
+ finishReason: response.finishReason,
394
+ startedAt: tripStartedAt.toISOString(),
395
+ endedAt: (/* @__PURE__ */ new Date()).toISOString(),
396
+ duration: performance.now() - tripStart,
397
+ usage: response.usage,
398
+ toolCalls: tripToolCalls.length > 0 ? tripToolCalls : void 0
399
+ };
400
+ this.trips.push(trip);
401
+ this.emit("agent.trip.completed", { trip });
402
+ if (!isToolCallTrip) return "stop";
403
+ return response.toolCalls.every((request) => {
404
+ return (this.config.tools?.find((tool) => tool.name === request.name))?.mode === "silent";
405
+ }) ? "stop" : "continue";
406
+ }
407
+ /**
408
+ * Route `getModelResponse` through the `trip`-level middleware
409
+ * pipeline. `trip.before` hooks can short-circuit the trip by
410
+ * returning a synthetic `ModelResponse` (semantic cache hit).
411
+ * `trip.after` hooks can transform the response before the trip
412
+ * record is built or any tool calls are dispatched. `trip.onError`
413
+ * hooks can recover from provider failures (fallback chain).
414
+ */
415
+ async runTripThroughPipeline(tripIndex) {
416
+ const context = {
417
+ ...this.buildExecuteContext(),
418
+ tripIndex,
419
+ messages: this.messages
420
+ };
421
+ return await runPipeline(this.middleware, "trip", context, () => this.getModelResponse(tripIndex), this.logger);
422
+ }
423
+ /**
424
+ * Produce the `ModelResponse` for the current trip. In non-streaming
425
+ * mode, delegates straight to `model.complete()`. In streaming mode,
426
+ * drains `model.stream()` while emitting `streaming` events per delta
427
+ * and accumulates the chunks into the same `ModelResponse` shape, so the
428
+ * rest of the trip pipeline (tool dispatch, trip record, usage
429
+ * aggregation) stays identical between the two modes.
430
+ */
431
+ async getModelResponse(tripIndex) {
432
+ const callOptions = {
433
+ ...this.config.modelOptions,
434
+ tools: this.config.tools ?? [],
435
+ ...this.responseSchema ? { responseSchema: this.responseSchema } : {},
436
+ ...this.options?.signal ? { signal: this.options.signal } : {}
437
+ };
438
+ if (!this.streamController) return this.config.model.complete(this.messages, callOptions);
439
+ let content = "";
440
+ let finishReason = "stop";
441
+ let usage = {
442
+ input: 0,
443
+ output: 0,
444
+ total: 0
445
+ };
446
+ const toolCalls = [];
447
+ const recoveredCalls = [];
448
+ const guardConfig = this.resolveStreamingToolGuard();
449
+ const guard = guardConfig ? new JsonStreamGuard({
450
+ tools: this.config.tools ?? [],
451
+ maxBufferBytes: guardConfig.maxBufferBytes,
452
+ onSafeDelta: (delta) => {
453
+ content += delta;
454
+ this.emit("agent.trip.streaming", {
455
+ delta,
456
+ tripIndex
457
+ });
458
+ },
459
+ onRecoveredCall: (request) => {
460
+ recoveredCalls.push(request);
461
+ }
462
+ }) : void 0;
463
+ for await (const chunk of this.config.model.stream(this.messages, callOptions)) {
464
+ if (this.options?.signal?.aborted) throw this.makeCancelledError();
465
+ if (chunk.type === "delta") {
466
+ if (guard) await guard.feed(chunk.content);
467
+ else {
468
+ content += chunk.content;
469
+ this.emit("agent.trip.streaming", {
470
+ delta: chunk.content,
471
+ tripIndex
472
+ });
473
+ }
474
+ continue;
475
+ }
476
+ if (chunk.type === "tool-call") {
477
+ toolCalls.push({
478
+ id: chunk.id,
479
+ name: chunk.name,
480
+ input: chunk.input,
481
+ ...chunk.providerMetadata ? { providerMetadata: chunk.providerMetadata } : {}
482
+ });
483
+ continue;
484
+ }
485
+ finishReason = chunk.finishReason;
486
+ usage = chunk.usage;
487
+ }
488
+ if (guard) await guard.finalize();
489
+ const dedupedRecovered = recoveredCalls.filter((recovered) => !isDuplicateToolCall(recovered, toolCalls));
490
+ const mergedToolCalls = [...toolCalls, ...dedupedRecovered];
491
+ const resolvedFinishReason = dedupedRecovered.length > 0 && finishReason === "stop" ? "tool_calls" : finishReason;
492
+ return {
493
+ content,
494
+ finishReason: resolvedFinishReason,
495
+ usage,
496
+ toolCalls: mergedToolCalls.length > 0 ? mergedToolCalls : void 0
497
+ };
498
+ }
499
+ /**
500
+ * Resolve the effective `streamingToolGuard` for this trip.
501
+ * Per-call options win over the agent-level config when the key is
502
+ * explicitly present on options (including the explicit `undefined`
503
+ * "disable for this call" form). Returns `undefined` when no guard
504
+ * should run.
505
+ */
506
+ resolveStreamingToolGuard() {
507
+ if (this.options !== void 0 && Object.prototype.hasOwnProperty.call(this.options, "streamingToolGuard")) return this.options.streamingToolGuard;
508
+ return this.config.streamingToolGuard;
509
+ }
510
+ /**
511
+ * Dispatch a single tool call requested by the model. Looks up the tool
512
+ * by name, invokes it via the safe `ToolContract.invoke` entry, pushes a
513
+ * matching tool-result message into `this.messages` so the next trip can
514
+ * see it, and emits the right lifecycle event (`tool-called` on success,
515
+ * `tool-calling-failed` when the tool is unregistered or invoke returned
516
+ * an error). Never throws — always returns a `ToolCall` record.
517
+ */
518
+ async dispatchToolCall(toolCallRequest, tripIndex) {
519
+ const registeredTool = this.config.tools?.find((tool) => tool.name === toolCallRequest.name);
520
+ if (!registeredTool) {
521
+ const error = new AgentExecutionError(`Tool not registered: ${toolCallRequest.name}`, { context: {
522
+ toolName: toolCallRequest.name,
523
+ tripIndex
524
+ } });
525
+ const nowIso = (/* @__PURE__ */ new Date()).toISOString();
526
+ const record = {
527
+ runId: generateRunId("tool"),
528
+ rootRunId: this.runId,
529
+ name: toolCallRequest.name,
530
+ type: "tool",
531
+ status: "failed",
532
+ startedAt: nowIso,
533
+ endedAt: nowIso,
534
+ duration: 0,
535
+ usage: {
536
+ input: 0,
537
+ output: 0,
538
+ total: 0
539
+ },
540
+ children: [],
541
+ tripIndex,
542
+ input: toolCallRequest.input,
543
+ error,
544
+ ...toolCallRequest.recoveredFrom ? { recoveredFrom: toolCallRequest.recoveredFrom } : {}
545
+ };
546
+ this.toolCalls.push(record);
547
+ this.messages.push({
548
+ role: "tool",
549
+ toolCallId: toolCallRequest.id,
550
+ content: JSON.stringify({ error: error.message })
551
+ });
552
+ this.emit("agent.tool.failed", {
553
+ tool: {
554
+ name: toolCallRequest.name,
555
+ description: "(unregistered tool — no description available)"
556
+ },
557
+ input: toolCallRequest.input,
558
+ error,
559
+ tripIndex
560
+ });
561
+ return record;
562
+ }
563
+ const toolMeta = {
564
+ name: registeredTool.name,
565
+ description: registeredTool.description,
566
+ action: resolveToolAction(registeredTool, toolCallRequest.input)
567
+ };
568
+ this.emit("agent.tool.calling", {
569
+ tool: toolMeta,
570
+ input: toolCallRequest.input,
571
+ tripIndex
572
+ });
573
+ const toolContext = {
574
+ ...this.buildExecuteContext(),
575
+ tripIndex,
576
+ messages: this.messages,
577
+ tool: {
578
+ name: registeredTool.name,
579
+ description: registeredTool.description,
580
+ mode: registeredTool.mode
581
+ },
582
+ request: toolCallRequest
583
+ };
584
+ let invokeResult;
585
+ try {
586
+ invokeResult = await runPipeline(this.middleware, "tool", toolContext, () => registeredTool.invoke(toolCallRequest.input, this.options?.toolCtx), this.logger);
587
+ } catch (thrown) {
588
+ const error = this.toAIError(thrown);
589
+ const nowIso = (/* @__PURE__ */ new Date()).toISOString();
590
+ const emptyUsage = {
591
+ input: 0,
592
+ output: 0,
593
+ total: 0
594
+ };
595
+ const failedRunId = generateRunId("tool");
596
+ invokeResult = {
597
+ error,
598
+ usage: emptyUsage,
599
+ report: {
600
+ runId: failedRunId,
601
+ rootRunId: failedRunId,
602
+ name: registeredTool.name,
603
+ version: registeredTool.version,
604
+ type: "tool",
605
+ status: "failed",
606
+ startedAt: nowIso,
607
+ endedAt: nowIso,
608
+ duration: 0,
609
+ usage: emptyUsage,
610
+ children: []
611
+ }
612
+ };
613
+ }
614
+ const innerReport = invokeResult.report;
615
+ const isComposite = innerReport.type !== "tool";
616
+ const record = {
617
+ runId: innerReport.runId,
618
+ rootRunId: this.runId,
619
+ name: toolCallRequest.name,
620
+ version: registeredTool.version,
621
+ type: "tool",
622
+ status: innerReport.status,
623
+ startedAt: innerReport.startedAt,
624
+ endedAt: innerReport.endedAt,
625
+ duration: innerReport.duration,
626
+ usage: invokeResult.usage,
627
+ children: isComposite ? [innerReport] : innerReport.children,
628
+ tripIndex,
629
+ input: toolCallRequest.input,
630
+ output: invokeResult.data,
631
+ error: invokeResult.error,
632
+ ...toolCallRequest.recoveredFrom ? { recoveredFrom: toolCallRequest.recoveredFrom } : {}
633
+ };
634
+ this.toolCalls.push(record);
635
+ this.usage.input += invokeResult.usage.input;
636
+ this.usage.output += invokeResult.usage.output;
637
+ this.usage.total += invokeResult.usage.total;
638
+ this.usage.cost = accumulateCost(this.usage.cost, invokeResult.usage.cost);
639
+ this.messages.push({
640
+ role: "tool",
641
+ toolCallId: toolCallRequest.id,
642
+ content: invokeResult.error ? JSON.stringify({ error: invokeResult.error.message }) : JSON.stringify(invokeResult.data ?? null)
643
+ });
644
+ if (invokeResult.error) this.emit("agent.tool.failed", {
645
+ tool: toolMeta,
646
+ input: toolCallRequest.input,
647
+ error: invokeResult.error,
648
+ tripIndex
649
+ });
650
+ else this.emit("agent.tool.called", {
651
+ ...record,
652
+ tool: toolMeta
653
+ });
654
+ return record;
655
+ }
656
+ /**
657
+ * Parse the final trip output against the user-supplied schema (if any).
658
+ * Failures populate `this.error` but never throw. Returns an outcome the
659
+ * caller uses to decide whether self-repair is worth attempting:
660
+ *
661
+ * - `"skipped"` — no schema, or a prior trip-level error already set
662
+ * `this.error` (model crash, max trips). Not repairable; the failure
663
+ * isn't a parse problem the model can fix by re-asking.
664
+ * - `"failed"` — schema present, output text either failed JSON.parse
665
+ * or failed `~standard.validate`. Repairable via `runRepairLoop`.
666
+ * - `"success"` — parsed and validated; `this.data` populated.
667
+ */
668
+ async parseOutput() {
669
+ const schema = this.options?.output ?? this.config.output;
670
+ if (!schema || this.error) return "skipped";
671
+ const text = this.trips[this.trips.length - 1]?.output ?? "";
672
+ if (!text) return "skipped";
673
+ const payload = extractJsonPayload(text);
674
+ const sentinel = Symbol("parse-failed");
675
+ const parsed = safeJsonParse(payload, sentinel);
676
+ if (parsed === sentinel) {
677
+ this.error = new SchemaValidationError("Failed to parse model output as JSON", { context: { text } });
678
+ return "failed";
679
+ }
680
+ const validation = await schema["~standard"].validate(parsed);
681
+ if (validation.issues) {
682
+ const summary = validation.issues.map((issue) => issue.message).join("; ");
683
+ this.error = new SchemaValidationError(summary, { issues: validation.issues });
684
+ return "failed";
685
+ }
686
+ this.data = validation.value;
687
+ return "success";
688
+ }
689
+ /**
690
+ * Opt-in self-repair loop for `output` schema failures. Triggered only
691
+ * when `options.repair` is set and `parseOutput()` returned `"failed"`.
692
+ *
693
+ * Each attempt:
694
+ * 1. Pushes the bad assistant response into `this.messages` (so the
695
+ * model can see what it just produced).
696
+ * 2. Pushes a corrective user message naming the validation/parse error.
697
+ * 3. Runs another trip — counted against the same `maxTrips` cap as
698
+ * normal trips so a stuck model can't loop forever.
699
+ * 4. Re-parses. Stops on success, on a trip-level error, or when
700
+ * either `maxAttempts` or `maxTrips` is exhausted.
701
+ *
702
+ * Resets `this.error` and `this.data` before each attempt so the final
703
+ * outcome (success or last failure) is what surfaces to the caller.
704
+ */
705
+ async runRepairLoop() {
706
+ const maxAttempts = this.options?.repair?.maxAttempts ?? 1;
707
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
708
+ if (this.trips.length >= this.maxTrips) return;
709
+ const badResponse = this.trips[this.trips.length - 1]?.output ?? "";
710
+ const failureReason = this.error?.message ?? "unknown validation failure";
711
+ this.error = void 0;
712
+ this.data = void 0;
713
+ this.messages.push({
714
+ role: "assistant",
715
+ content: badResponse
716
+ });
717
+ this.messages.push({
718
+ role: "user",
719
+ content: [`Your previous response failed validation: ${failureReason}.`, "Respond again with valid JSON only — no prose, no markdown fences, no commentary."].join(" ")
720
+ });
721
+ const tripIndex = this.trips.length;
722
+ this.logger.warn(LOG_MODULE, "repair.attempting", "retrying after validation failure", {
723
+ attempt: attempt + 1,
724
+ maxAttempts,
725
+ reason: failureReason
726
+ });
727
+ if (await this.runTrip(tripIndex, "[repair attempt]") === "error") return;
728
+ if (await this.parseOutput() === "success") return;
729
+ }
730
+ }
731
+ /**
732
+ * Build the final `AgentResult` snapshot from accumulated state
733
+ * (trips, tool calls, data/error, usage, timing).
734
+ *
735
+ * Pure — no side effects. `run()` owns terminal event emission and
736
+ * stream closure so the post-pipeline result (possibly transformed
737
+ * or short-circuited by an `execute`-level middleware) is what
738
+ * flows out to consumers and listeners.
739
+ *
740
+ * Trips, tool calls, status, and timing live under `report` so the
741
+ * root stays focused on the four things callers reach for most:
742
+ * `data`, `text`, `usage`, `error`.
743
+ */
744
+ buildResult() {
745
+ const finalTrip = this.trips[this.trips.length - 1];
746
+ const endedAt = /* @__PURE__ */ new Date();
747
+ const agentName = this.config.name ?? this.config.model.name;
748
+ const status = this.error ? this.error instanceof AgentCancelledError ? "cancelled" : "failed" : "completed";
749
+ const report = {
750
+ runId: this.runId,
751
+ rootRunId: this.runId,
752
+ name: agentName,
753
+ version: this.config.version,
754
+ type: "agent",
755
+ status,
756
+ startedAt: this.startedAt.toISOString(),
757
+ endedAt: endedAt.toISOString(),
758
+ duration: performance.now() - this.start,
759
+ usage: this.usage,
760
+ children: this.toolCalls,
761
+ model: {
762
+ name: this.config.model.name,
763
+ provider: this.config.model.provider
764
+ },
765
+ trips: this.trips
766
+ };
767
+ stampReportLineage(report, {
768
+ rootRunId: this.runId,
769
+ sessionId: this.options?.sessionId
770
+ });
771
+ return {
772
+ type: "agent",
773
+ data: this.data,
774
+ text: finalTrip?.output,
775
+ report,
776
+ usage: this.usage,
777
+ error: this.error
778
+ };
779
+ }
780
+ /**
781
+ * Normalize any thrown value into an `AIError`. `AIError` instances
782
+ * pass through untouched; provider-adapter SDK errors are caught by
783
+ * the adapter and already arrive typed, so this branch mainly
784
+ * handles runtime crashes (TypeError, ReferenceError) inside
785
+ * model.complete / model.stream and non-Error values (`throw "bad"`).
786
+ */
787
+ toAIError(thrown) {
788
+ if (thrown instanceof AIError) return thrown;
789
+ if (isAbortLike(thrown)) return this.makeCancelledError();
790
+ return new AgentExecutionError(thrown instanceof Error ? thrown.message : String(thrown), { cause: thrown });
791
+ }
792
+ /**
793
+ * Build the typed cancelled error that both the trip-loop guard
794
+ * and the mid-stream guard emit. Captures the abort reason when
795
+ * one was supplied to `controller.abort(reason)` so logs and
796
+ * telemetry can see what cancelled the run.
797
+ */
798
+ makeCancelledError() {
799
+ const reason = this.options?.signal?.reason;
800
+ const reasonText = reason === void 0 ? "" : String(reason);
801
+ return new AgentCancelledError("agent execution cancelled", {
802
+ cause: reason,
803
+ cancelledAt: (/* @__PURE__ */ new Date()).toISOString(),
804
+ reason: reasonText
805
+ });
806
+ }
807
+ /**
808
+ * Fire a single event through all three subscription tiers in order
809
+ * — factory → instance → per-call — and mirror it into the
810
+ * `StreamController` when streaming is active. A throwing user
811
+ * handler must never crash the agent, so every dispatch is wrapped
812
+ * in `safeCall`. Stream events are converted from the internal
813
+ * `AgentEventMap` payload to the public `StreamEvent` shape because
814
+ * some of them differ (e.g. the tool-called payload vs stream
815
+ * event).
816
+ */
817
+ emit(event, payload) {
818
+ const fullPayload = {
819
+ ...payload,
820
+ runId: this.runId,
821
+ rootRunId: this.runId
822
+ };
823
+ this.logEvent(event, fullPayload);
824
+ const factoryHandler = this.config.on?.[event];
825
+ if (factoryHandler) safeCall(factoryHandler, fullPayload);
826
+ const bucket = this.instanceHandlers?.get(event);
827
+ if (bucket) for (const handler of bucket) safeCall(handler, fullPayload);
828
+ const perCallHandler = this.options?.on?.[event];
829
+ if (perCallHandler) safeCall(perCallHandler, fullPayload);
830
+ if (this.streamController) {
831
+ const body = this.toStreamEvent(event, fullPayload);
832
+ if (body) this.streamController.push({
833
+ runId: this.runId,
834
+ rootRunId: this.runId,
835
+ ...body
836
+ });
837
+ }
838
+ }
839
+ /**
840
+ * Emit a structured log line for a lifecycle event. The action
841
+ * string mirrors the event name with the `agent.` prefix stripped
842
+ * (`agent.trip.started` → `trip.started`) so log grep filters and
843
+ * event handlers read the same vocabulary. Level mapping follows
844
+ * the convention documented on `@warlock.js/logger`'s `Logger`.
845
+ */
846
+ logEvent(event, payload) {
847
+ const agentName = this.config.name || this.config.model.name;
848
+ logAgentEvent(this.logger, {
849
+ module: `${LOG_MODULE}.${agentName}`,
850
+ maxTrips: this.maxTrips,
851
+ modelName: this.config.model.name,
852
+ totalUsage: this.usage,
853
+ totalDurationMs: performance.now() - this.start,
854
+ trips: this.trips,
855
+ toolCalls: this.toolCalls
856
+ }, event, payload);
857
+ }
858
+ toStreamEvent(event, payload) {
859
+ return agentEventToStreamEvent(event, payload);
860
+ }
861
+ /**
862
+ * Invoke the `onUsage` hook (when configured) with a flat payload
863
+ * carrying stable identity. Awaits the handler so async ledger
864
+ * writes complete before the next trip starts; swallows any throw
865
+ * so consumer bugs cannot crash the agent. Sync handlers wrapped
866
+ * via `Promise.resolve()` so the await is safe in either case.
867
+ */
868
+ async fireUsageHook(tripIndex, tripUsage) {
869
+ const handler = this.config.onUsage;
870
+ if (!handler) return;
871
+ const event = {
872
+ runId: this.runId,
873
+ tripIndex,
874
+ model: {
875
+ name: this.config.model.name,
876
+ provider: this.config.model.provider
877
+ },
878
+ usage: { ...tripUsage },
879
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
880
+ };
881
+ try {
882
+ await Promise.resolve(handler(event));
883
+ } catch (err) {
884
+ this.logger.warn(LOG_MODULE, "onUsage.hook.error", "onUsage handler threw", {
885
+ runId: this.runId,
886
+ tripIndex,
887
+ error: err instanceof Error ? err.message : String(err)
888
+ });
889
+ }
890
+ }
891
+ /**
892
+ * Invoke the `onComplete` hook (when configured) once at the end
893
+ * of every run. Receives the full `AgentResult` plus pre-extracted
894
+ * `runId` and `durationMs`. Same swallow-and-log error policy as
895
+ * `fireUsageHook`.
896
+ */
897
+ async fireCompleteHook(result) {
898
+ const handler = this.config.onComplete;
899
+ if (!handler) return;
900
+ const event = {
901
+ result,
902
+ runId: this.runId,
903
+ durationMs: performance.now() - this.start
904
+ };
905
+ try {
906
+ await Promise.resolve(handler(event));
907
+ } catch (err) {
908
+ this.logger.warn(LOG_MODULE, "onComplete.hook.error", "onComplete handler threw", {
909
+ runId: this.runId,
910
+ error: err instanceof Error ? err.message : String(err)
911
+ });
912
+ }
913
+ }
914
+ };
915
+ /**
916
+ * Decide whether a guard-synthesized tool call duplicates a real one
917
+ * the provider already streamed structurally. Match key is
918
+ * `name + key-sorted JSON of input` so identical calls (regardless of
919
+ * argument key order) collapse, but two legitimate calls to the same
920
+ * tool with different inputs still both dispatch.
921
+ */
922
+ function isDuplicateToolCall(recovered, realCalls) {
923
+ const recoveredKey = `${recovered.name}|${stableStringify(recovered.input)}`;
924
+ for (const real of realCalls) if (`${real.name}|${stableStringify(real.input)}` === recoveredKey) return true;
925
+ return false;
926
+ }
927
+ /**
928
+ * `JSON.stringify` variant that sorts object keys at every nesting
929
+ * level so structurally-equal inputs serialize to identical strings.
930
+ * Used only for dedupe-key comparison; never surfaces to consumers.
931
+ */
932
+ function stableStringify(value) {
933
+ return JSON.stringify(value, (_key, val) => {
934
+ if (val !== null && typeof val === "object" && !Array.isArray(val)) {
935
+ const source = val;
936
+ const sorted = {};
937
+ for (const key of Object.keys(source).sort()) sorted[key] = source[key];
938
+ return sorted;
939
+ }
940
+ return val;
941
+ });
942
+ }
943
+ /**
944
+ * Invoke a user-supplied event handler without letting exceptions
945
+ * escape the agent. Thrown errors are swallowed — structured logging
946
+ * attaches here in Phase 0.5 so operators still see the failure.
947
+ */
948
+ function safeCall(handler, payload) {
949
+ try {
950
+ handler(payload);
951
+ } catch {}
952
+ }
953
+ /**
954
+ * Resolve a tool's `action` declaration into a plain string for
955
+ * inclusion in `ToolEventMeta`. Static strings pass through;
956
+ * function-shaped actions are invoked with the validated input.
957
+ *
958
+ * Defensive: if the user's callback throws, swallow and return
959
+ * `undefined` rather than crashing the agent — UI strings are not
960
+ * worth aborting an LLM dispatch over.
961
+ */
962
+ function resolveToolAction(tool, input) {
963
+ if (tool.action === void 0) return void 0;
964
+ if (typeof tool.action === "string") return tool.action;
965
+ try {
966
+ return tool.action(input);
967
+ } catch {
968
+ return;
969
+ }
970
+ }
971
+
972
+ //#endregion
973
+ export { agent };
974
+ //# sourceMappingURL=agent.mjs.map