failproofai 1.0.7-beta.0 → 1.0.7-beta.2

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 (320) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +3 -3
  3. package/.next/standalone/.next/prerender-manifest.json +3 -3
  4. package/.next/standalone/.next/required-server-files.json +1 -1
  5. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  6. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  7. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  10. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
  11. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  12. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  13. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  15. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  16. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  17. package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
  18. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
  19. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +14 -14
  20. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  21. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  22. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  23. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  24. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  25. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  30. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  32. package/.next/standalone/.next/server/app/index.html +1 -1
  33. package/.next/standalone/.next/server/app/index.rsc +15 -15
  34. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +14 -14
  35. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
  36. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  37. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  38. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  40. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
  41. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  42. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  43. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  44. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  45. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  46. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  47. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  48. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  49. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  50. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  51. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  52. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  53. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +7 -7
  54. package/.next/standalone/.next/server/app/settings/page.js +2 -2
  55. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  56. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  57. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0l3yhx4._.js +2 -2
  58. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
  59. package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
  60. package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
  61. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  62. package/.next/standalone/.next/server/chunks/src_hooks_18qtd42._.js +1 -1
  63. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04usis8._.js +2 -2
  64. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__056wjo4._.js +2 -2
  65. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1p28m0u._.js → [root-of-the-server]__0l44ual._.js} +2 -2
  66. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n0xg95._.js +2 -2
  67. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0rwtwpm._.js +2 -2
  68. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s_yomn._.js +2 -2
  69. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11mayhe._.js +2 -2
  70. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1pprgri._.js +2 -2
  71. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1q4p5b8._.js +2 -2
  72. package/.next/standalone/.next/server/chunks/ssr/_042cgl1._.js +1 -1
  73. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  74. package/.next/standalone/.next/server/chunks/ssr/_0bqoto4._.js +1 -1
  75. package/.next/standalone/.next/server/chunks/ssr/{_0cf1olg._.js → _1mel6y1._.js} +2 -2
  76. package/.next/standalone/.next/server/chunks/ssr/{_135-c3y._.js → _1v-jvrv._.js} +1 -1
  77. package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +1 -1
  78. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +2 -2
  79. package/.next/standalone/.next/server/chunks/ssr/app_actions_get-scheduled-audit_ts_0ei9sni._.js +1 -1
  80. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
  81. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  82. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
  83. package/.next/standalone/.next/server/chunks/ssr/app_settings_02tf1h4._.js +1 -1
  84. package/.next/standalone/.next/server/chunks/ssr/src_hooks_15t8kqj._.js +1 -1
  85. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1fm2w5z._.js +1 -1
  86. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1j0zy3v._.js +1 -1
  87. package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +1 -1
  88. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  89. package/.next/standalone/.next/server/pages/404.html +1 -1
  90. package/.next/standalone/.next/server/pages/500.html +1 -1
  91. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  92. package/.next/standalone/.next/server/server-reference-manifest.json +22 -22
  93. package/.next/standalone/.next/static/chunks/043j99m8ykg__.css +2 -0
  94. package/.next/standalone/.next/static/chunks/{0289oapk24zql.js → 0fqd7m_u81mi5.js} +1 -1
  95. package/.next/standalone/.next/static/chunks/{2tqszh84mp_2l.js → 129ag2bw93bdh.js} +1 -1
  96. package/.next/standalone/.next/static/chunks/{0pyy9m5cm8zku.js → 1qd741hzlmjbo.js} +1 -1
  97. package/.next/standalone/.next/static/chunks/{3vwnzfx9q80yl.js → 2_pltstd8-xgs.js} +1 -1
  98. package/.next/standalone/.next/static/chunks/{3vp7c3knkh8mr.js → 2c8j9l6j_b1ci.js} +1 -1
  99. package/.next/standalone/.next/static/chunks/3-k569wzcli8q.js +1 -0
  100. package/.next/standalone/.next/static/chunks/{3cdkxrukvlvul.js → 3brze37td_wnc.js} +1 -1
  101. package/.next/standalone/.next/static/chunks/{3dnd-_29uiaj3.js → 3otmypm6j_xfo.js} +2 -2
  102. package/.next/standalone/.next/static/chunks/{00i9thnpht4l1.js → 3ugmd_7dyn0id.js} +1 -1
  103. package/.next/standalone/.next/static/chunks/3yxro_r2_o9ad.js +69 -0
  104. package/.next/standalone/PROBE-FOLLOWUP.md +186 -0
  105. package/.next/standalone/app/actions/get-jev-config.ts +38 -23
  106. package/.next/standalone/app/actions/update-jev-config.ts +1 -1
  107. package/.next/standalone/app/settings/jev-panel.tsx +33 -29
  108. package/.next/standalone/package.json +10 -10
  109. package/.next/standalone/sdk/python/skill/SKILL.md +60 -14
  110. package/.next/standalone/sdk/python/skill/agents/openai.yaml +2 -1
  111. package/.next/standalone/sdk/python/skill/references/evaluator.md +255 -0
  112. package/.next/standalone/sdk/python/skill/references/events.md +17 -8
  113. package/.next/standalone/sdk/python/skill/references/frameworks.md +3 -0
  114. package/.next/standalone/sdk/python/skill/references/install.md +3 -0
  115. package/.next/standalone/sdk/python/skill/references/integration.md +6 -2
  116. package/.next/standalone/sdk/python/skill/references/typescript.md +568 -0
  117. package/.next/standalone/sdk/typescript/CHANGELOG.md +119 -0
  118. package/.next/standalone/sdk/typescript/LICENSE +42 -0
  119. package/.next/standalone/sdk/typescript/README.md +552 -0
  120. package/.next/standalone/sdk/typescript/eslint.config.mjs +59 -0
  121. package/.next/standalone/sdk/typescript/examples/research-agent.ts +197 -0
  122. package/.next/standalone/sdk/typescript/integration/ai.test.ts +920 -0
  123. package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/agent.ts +337 -0
  124. package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/package-lock.json +281 -0
  125. package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/package.json +13 -0
  126. package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/surfaces.ts +605 -0
  127. package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/tsconfig.json +12 -0
  128. package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/tsconfig.surfaces.json +4 -0
  129. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/agent.ts +342 -0
  130. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/package-lock.json +168 -0
  131. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/package.json +13 -0
  132. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/surfaces.ts +628 -0
  133. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/tsconfig.json +12 -0
  134. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/tsconfig.surfaces.json +4 -0
  135. package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/agent.ts +346 -0
  136. package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/package-lock.json +156 -0
  137. package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/package.json +13 -0
  138. package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/surfaces.ts +651 -0
  139. package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/tsconfig.json +12 -0
  140. package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/tsconfig.surfaces.json +4 -0
  141. package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/agent.ts +350 -0
  142. package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/package-lock.json +153 -0
  143. package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/package.json +13 -0
  144. package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/surfaces.ts +651 -0
  145. package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/tsconfig.json +12 -0
  146. package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/tsconfig.surfaces.json +4 -0
  147. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-0.3/agent.ts +623 -0
  148. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-0.3/package-lock.json +463 -0
  149. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-0.3/package.json +15 -0
  150. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-0.3/tsconfig.json +12 -0
  151. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/agent-v1.ts +99 -0
  152. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/agent.ts +623 -0
  153. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/package-lock.json +336 -0
  154. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/package.json +15 -0
  155. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/tsconfig.json +12 -0
  156. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/agent.ts +96 -0
  157. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/package-lock.json +579 -0
  158. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/package.json +15 -0
  159. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/tsconfig.json +12 -0
  160. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/vendor/lc-weather-provider/index.cjs +53 -0
  161. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/vendor/lc-weather-provider/index.mjs +55 -0
  162. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/vendor/lc-weather-provider/package.json +18 -0
  163. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/agent.ts +659 -0
  164. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/package-lock.json +635 -0
  165. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/package.json +15 -0
  166. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/tsconfig.json +12 -0
  167. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/agent.ts +659 -0
  168. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/package-lock.json +553 -0
  169. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/package.json +15 -0
  170. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/tsconfig.json +12 -0
  171. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/agent.ts +877 -0
  172. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/mcp-server.mjs +66 -0
  173. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/package-lock.json +6417 -0
  174. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/package.json +15 -0
  175. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/tsconfig.json +12 -0
  176. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/agent.ts +872 -0
  177. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/mcp-server.mjs +66 -0
  178. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/package-lock.json +2540 -0
  179. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/package.json +15 -0
  180. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/tsconfig.json +12 -0
  181. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/actions.ts +18 -0
  182. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/ai/route.ts +42 -0
  183. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/edge/route.ts +29 -0
  184. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/langgraph/route.ts +21 -0
  185. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/llamaindex/route.ts +11 -0
  186. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/mastra/route.ts +19 -0
  187. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/status/route.ts +7 -0
  188. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/layout.tsx +9 -0
  189. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/page.tsx +15 -0
  190. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/instrumentation.ts +15 -0
  191. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/lib/ai.ts +61 -0
  192. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/lib/langgraph.ts +68 -0
  193. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/lib/llamaindex.ts +98 -0
  194. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/lib/mastra.ts +90 -0
  195. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/next.config.ts +52 -0
  196. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package-lock.json +4343 -0
  197. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package.json +28 -0
  198. package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/agent.ts +51 -0
  199. package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/deno-npm.ts +76 -0
  200. package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/package-lock.json +484 -0
  201. package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/package.json +15 -0
  202. package/.next/standalone/sdk/typescript/integration/fixtures/types/agent.ts +79 -0
  203. package/.next/standalone/sdk/typescript/integration/fixtures/types/package-lock.json +740 -0
  204. package/.next/standalone/sdk/typescript/integration/fixtures/types/package.json +11 -0
  205. package/.next/standalone/sdk/typescript/integration/fixtures/vanilla/agent.ts +197 -0
  206. package/.next/standalone/sdk/typescript/integration/fixtures/vanilla/package-lock.json +70 -0
  207. package/.next/standalone/sdk/typescript/integration/fixtures/vanilla/package.json +12 -0
  208. package/.next/standalone/sdk/typescript/integration/fixtures/vanilla/tsconfig.json +12 -0
  209. package/.next/standalone/sdk/typescript/integration/global-setup.ts +29 -0
  210. package/.next/standalone/sdk/typescript/integration/harness.ts +451 -0
  211. package/.next/standalone/sdk/typescript/integration/langchain.test.ts +682 -0
  212. package/.next/standalone/sdk/typescript/integration/llamaindex.test.ts +709 -0
  213. package/.next/standalone/sdk/typescript/integration/mastra-coverage.test.ts +386 -0
  214. package/.next/standalone/sdk/typescript/integration/mastra.test.ts +311 -0
  215. package/.next/standalone/sdk/typescript/integration/nextjs.test.ts +341 -0
  216. package/.next/standalone/sdk/typescript/integration/runtime-parity.ts +180 -0
  217. package/.next/standalone/sdk/typescript/integration/runtimes.bun.test.ts +15 -0
  218. package/.next/standalone/sdk/typescript/integration/runtimes.core.test.ts +113 -0
  219. package/.next/standalone/sdk/typescript/integration/runtimes.deno.test.ts +19 -0
  220. package/.next/standalone/sdk/typescript/integration/types.test.ts +141 -0
  221. package/.next/standalone/sdk/typescript/integration/vanilla.test.ts +255 -0
  222. package/.next/standalone/sdk/typescript/package-lock.json +2640 -0
  223. package/.next/standalone/sdk/typescript/package.json +401 -0
  224. package/.next/standalone/sdk/typescript/scripts/finalize-build.mjs +123 -0
  225. package/.next/standalone/sdk/typescript/scripts/release.mjs +177 -0
  226. package/.next/standalone/sdk/typescript/src/clock.ts +58 -0
  227. package/.next/standalone/sdk/typescript/src/context.ts +214 -0
  228. package/.next/standalone/sdk/typescript/src/edge/adapter.ts +18 -0
  229. package/.next/standalone/sdk/typescript/src/edge/ai.ts +116 -0
  230. package/.next/standalone/sdk/typescript/src/edge/index.ts +238 -0
  231. package/.next/standalone/sdk/typescript/src/edge/langchain.ts +18 -0
  232. package/.next/standalone/sdk/typescript/src/edge/llamaindex.ts +12 -0
  233. package/.next/standalone/sdk/typescript/src/edge/mastra.ts +17 -0
  234. package/.next/standalone/sdk/typescript/src/edge/notice.ts +33 -0
  235. package/.next/standalone/sdk/typescript/src/environment.ts +75 -0
  236. package/.next/standalone/sdk/typescript/src/evaluator/authoring.ts +480 -0
  237. package/.next/standalone/sdk/typescript/src/evaluator/cli.ts +96 -0
  238. package/.next/standalone/sdk/typescript/src/evaluator/client.ts +421 -0
  239. package/.next/standalone/sdk/typescript/src/evaluator/expression.ts +1292 -0
  240. package/.next/standalone/sdk/typescript/src/evaluator/index.ts +144 -0
  241. package/.next/standalone/sdk/typescript/src/evaluator/protocol.ts +747 -0
  242. package/.next/standalone/sdk/typescript/src/evaluator/runtime.ts +930 -0
  243. package/.next/standalone/sdk/typescript/src/evaluator/sandbox-worker.ts +171 -0
  244. package/.next/standalone/sdk/typescript/src/evaluator/source-limits.ts +27 -0
  245. package/.next/standalone/sdk/typescript/src/evaluator/source.ts +509 -0
  246. package/.next/standalone/sdk/typescript/src/events.ts +879 -0
  247. package/.next/standalone/sdk/typescript/src/exit.ts +117 -0
  248. package/.next/standalone/sdk/typescript/src/index.ts +186 -0
  249. package/.next/standalone/sdk/typescript/src/integrations/ai.ts +1566 -0
  250. package/.next/standalone/sdk/typescript/src/integrations/compat.ts +322 -0
  251. package/.next/standalone/sdk/typescript/src/integrations/core.ts +1321 -0
  252. package/.next/standalone/sdk/typescript/src/integrations/index.ts +355 -0
  253. package/.next/standalone/sdk/typescript/src/integrations/langchain.ts +2340 -0
  254. package/.next/standalone/sdk/typescript/src/integrations/llamaindex.ts +2111 -0
  255. package/.next/standalone/sdk/typescript/src/integrations/mastra.ts +1802 -0
  256. package/.next/standalone/sdk/typescript/src/logger.ts +98 -0
  257. package/.next/standalone/sdk/typescript/src/next.ts +115 -0
  258. package/.next/standalone/sdk/typescript/src/node-require.ts +446 -0
  259. package/.next/standalone/sdk/typescript/src/redact.ts +305 -0
  260. package/.next/standalone/sdk/typescript/src/resolver.ts +120 -0
  261. package/.next/standalone/sdk/typescript/src/runtime.ts +29 -0
  262. package/.next/standalone/sdk/typescript/src/schema.ts +410 -0
  263. package/.next/standalone/sdk/typescript/src/scopes.ts +701 -0
  264. package/.next/standalone/sdk/typescript/src/shared.ts +33 -0
  265. package/.next/standalone/sdk/typescript/src/version.ts +5 -0
  266. package/.next/standalone/sdk/typescript/src/writer.ts +934 -0
  267. package/.next/standalone/sdk/typescript/test/adapters.test.ts +397 -0
  268. package/.next/standalone/sdk/typescript/test/ai.test.ts +1076 -0
  269. package/.next/standalone/sdk/typescript/test/copies.test.ts +204 -0
  270. package/.next/standalone/sdk/typescript/test/edge.test.ts +183 -0
  271. package/.next/standalone/sdk/typescript/test/evaluator-client.test.ts +234 -0
  272. package/.next/standalone/sdk/typescript/test/evaluator-protocol.test.ts +225 -0
  273. package/.next/standalone/sdk/typescript/test/events.test.ts +193 -0
  274. package/.next/standalone/sdk/typescript/test/expression.test.ts +181 -0
  275. package/.next/standalone/sdk/typescript/test/global-setup.ts +26 -0
  276. package/.next/standalone/sdk/typescript/test/helpers.ts +130 -0
  277. package/.next/standalone/sdk/typescript/test/integrations.test.ts +369 -0
  278. package/.next/standalone/sdk/typescript/test/langchain-copies.test.ts +204 -0
  279. package/.next/standalone/sdk/typescript/test/langchain.test.ts +999 -0
  280. package/.next/standalone/sdk/typescript/test/llamaindex.test.ts +1760 -0
  281. package/.next/standalone/sdk/typescript/test/mastra-coverage.test.ts +501 -0
  282. package/.next/standalone/sdk/typescript/test/mastra-lifecycle.test.ts +479 -0
  283. package/.next/standalone/sdk/typescript/test/mastra.test.ts +285 -0
  284. package/.next/standalone/sdk/typescript/test/next.test.ts +109 -0
  285. package/.next/standalone/sdk/typescript/test/packaging.test.ts +312 -0
  286. package/.next/standalone/sdk/typescript/test/redaction.test.ts +171 -0
  287. package/.next/standalone/sdk/typescript/test/runtimes.test.ts +101 -0
  288. package/.next/standalone/sdk/typescript/test/sandbox.test.ts +189 -0
  289. package/.next/standalone/sdk/typescript/test/scopes.test.ts +271 -0
  290. package/.next/standalone/sdk/typescript/test/setup.ts +19 -0
  291. package/.next/standalone/sdk/typescript/test/skill-snippets.test.ts +73 -0
  292. package/.next/standalone/sdk/typescript/test/spool-contract.test.ts +124 -0
  293. package/.next/standalone/sdk/typescript/test/tracker-bounds.test.ts +191 -0
  294. package/.next/standalone/sdk/typescript/test/wire-format.test.ts +214 -0
  295. package/.next/standalone/sdk/typescript/test/writer.test.ts +407 -0
  296. package/.next/standalone/sdk/typescript/tsconfig.build.json +15 -0
  297. package/.next/standalone/sdk/typescript/tsconfig.cjs.json +19 -0
  298. package/.next/standalone/sdk/typescript/tsconfig.json +28 -0
  299. package/.next/standalone/sdk/typescript/vitest.config.ts +33 -0
  300. package/.next/standalone/sdk/typescript/vitest.integration.config.ts +23 -0
  301. package/.next/standalone/server.js +1 -1
  302. package/README.md +2 -2
  303. package/dist/cli.mjs +225 -30
  304. package/dist/worker.mjs +120 -14
  305. package/package.json +10 -10
  306. package/scripts/build-policy-pack.mjs +14 -0
  307. package/src/audit/features.ts +3 -2
  308. package/src/hooks/builtin-policies.ts +156 -5
  309. package/src/hooks/jev-cli.ts +57 -1
  310. package/src/hooks/manager.ts +1 -1
  311. package/src/hooks/pack-cli.ts +191 -24
  312. package/src/hooks/pack-store.ts +1 -1
  313. package/src/hooks/policy-catalog.ts +148 -9
  314. package/src/hooks/types.ts +1 -1
  315. package/.next/standalone/.next/static/chunks/15heikmy3yjzc.js +0 -1
  316. package/.next/standalone/.next/static/chunks/285spx855h_3r.css +0 -2
  317. package/.next/standalone/.next/static/chunks/2plg9qae1yejv.js +0 -69
  318. /package/.next/standalone/.next/static/{qbVI48kgBOf9CTOKcFIk2 → gbEOjBgZAxF2UIUwZVHNu}/_buildManifest.js +0 -0
  319. /package/.next/standalone/.next/static/{qbVI48kgBOf9CTOKcFIk2 → gbEOjBgZAxF2UIUwZVHNu}/_clientMiddlewareManifest.js +0 -0
  320. /package/.next/standalone/.next/static/{qbVI48kgBOf9CTOKcFIk2 → gbEOjBgZAxF2UIUwZVHNu}/_ssgManifest.js +0 -0
@@ -0,0 +1,1802 @@
1
+ /**
2
+ * Mastra (`@mastra/core`).
3
+ *
4
+ * ## The mapping
5
+ *
6
+ * Mastra has no Python counterpart, so this is derived from the rule every
7
+ * adapter follows — "a framework construct becomes an agent if and only if it
8
+ * owns an LLM decision loop and has its own goal; everything else with a start
9
+ * and an end becomes the closest kind of leaf" — with CrewAI (agents calling
10
+ * agents) and LlamaIndex (workflow steps) as the analogues:
11
+ *
12
+ * | Mastra | FailproofAI |
13
+ * |---|---|
14
+ * | `Agent.generate()` / `.stream()` (and the legacy / VNext variants) | `agent_start` / `agent_end`, `agent_id` = the agent's `name` (its `id` if unnamed), never a UUID |
15
+ * | a sub-agent another agent delegates to (`agents: {…}`) | nested `agent_start` / `agent_end`, `parent_id` = the caller, inside the caller's `agent-<name>` tool call |
16
+ * | each LLM step of the loop | `model_request` / `model_response`, paired on `request_id`, with the model id, integer tokens, a string `stop_reason` and `duration_ms` |
17
+ * | a tool the model calls | `tool_use` / `tool_result` carrying the MODEL's `toolCallId`, attributed to the agent whose loop called it |
18
+ * | a workflow run (`run.start()`, `.stream()`, `.resume()`) | `agent_start` / `agent_end`, `agent_id` = the workflow id |
19
+ * | a workflow step (incl. every branch taken, parallel step and loop iteration) | `hook_triggered` / `hook_completed`, `trigger_event="workflow_step"` |
20
+ * | a nested workflow, or an agent used as a step | a nested agent under the workflow, inside that step's hook |
21
+ * | a step's `suspend()` … `run.resume({ step, resumeData })` | `human_wait` + `agent_pause` … `agent_resume` + `human_input` on the SAME workflow span, which stays open while suspended; ids `<runId>:<step path>` |
22
+ * | `agent.network()` | ONE agent (`fw_method="network"`); the router Mastra builds per decision (`routing-agent`) is that agent's own model steps, and the agent it delegates to is nested under it |
23
+ * | a run an input or output processor blocks (`abort()` / tripwire) | `agent_end` `outcome="rejected"` |
24
+ * | Mastra's own machinery — the agentic loop and a network are built from internal workflows | nothing |
25
+ *
26
+ * **Sessions.** A root run (nothing enclosing it, no `failproofai.session()` /
27
+ * `agent()` scope) takes the conversation id Mastra gives it, the rule every
28
+ * adapter follows ("a conversation spanning runs is one session where the
29
+ * framework provides a conversation id"): an agent run's memory thread
30
+ * (`memory: { thread }`, 0.x `threadId`), so every turn of a thread is one
31
+ * session; a workflow run's run id, so a suspended run and its resume — in
32
+ * this process or another — are one session. Otherwise the session is new.
33
+ * An enclosing scope always wins, and a nested run is in its parent's.
34
+ *
35
+ * A streamed call finalises when Mastra finishes the stream — which it does as
36
+ * the caller consumes it — not when `stream()` returns: the model events carry
37
+ * the real token counts and stop reason, and `agent_end` is not emitted while
38
+ * the loop is still running. A failure is recorded once, on the event it
39
+ * happened in (the `model_response`, the `tool_result`, the `hook_completed`),
40
+ * and closes the enclosing agent `failed`; there is no separate `error` event
41
+ * for each layer the exception unwound through.
42
+ *
43
+ * Token counts are the provider's own, read off each step. A STREAMED step
44
+ * from an OpenAI-compatible endpoint carries none unless the request asked for
45
+ * them (`stream_options.include_usage`), and the model Mastra's router builds
46
+ * for a `{ id, url }` / custom provider does not ask — Mastra itself then
47
+ * reports zero usage — so such a step is recorded without tokens. Nothing a
48
+ * call passes turns it on (`providerOptions` cannot: the provider overwrites
49
+ * `stream_options`); a model built with usage on — `@ai-sdk/openai`, or
50
+ * `createOpenAICompatible({ includeUsage: true })` — is recorded with them.
51
+ *
52
+ * ## Why prototype patching, and where
53
+ *
54
+ * Mastra 1.x has a real tracing extension point — an `ObservabilityExporter`
55
+ * receiving `agent_run` / `model_step` / `tool_call` / `workflow_step` spans —
56
+ * but it only exists for agents and workflows registered on a `Mastra` instance
57
+ * configured with `@mastra/observability`. A bare `new Agent(...)` gets a no-op
58
+ * tracer and emits nothing to hook, and that is the most common way Mastra is
59
+ * used outside its dev server. It is also absent from 0.x in this shape. So the
60
+ * adapter patches the few PROTOTYPE methods every run goes through, on both
61
+ * lines alike:
62
+ *
63
+ * * `Agent.prototype.generate` / `.stream` (+ variants) and `.network` — the
64
+ * agent span.
65
+ * * `Agent.prototype.__runInputProcessors` — where an input processor's
66
+ * `abort()` lands. A blocked `stream()` calls none of its callbacks, so this
67
+ * is what ends it (1.x also exposes the stream's finish; 0.x does not).
68
+ * * `Agent.prototype.resolveModelConfig` — every model the agent will call
69
+ * passes through here, per run. The resolved model is handed back behind a
70
+ * proxy whose `doGenerate` / `doStream` are observed: that is the AI SDK
71
+ * `LanguageModel` contract (V1–V3), which Mastra itself calls once per LLM
72
+ * step, so each step is one pair with the provider's own usage and finish
73
+ * reason — rather than one collapsed pair read off the final result.
74
+ * * `Agent.prototype.convertTools` — the one step that turns every kind of tool
75
+ * (assigned, memory, toolset, client, sub-agent, workflow-as-tool) into what
76
+ * the loop executes. Wrapping its OUTPUT covers tools created before
77
+ * `instrument()` ran, which patching the `createTool` export never could: an
78
+ * ES-module namespace is read-only, and a Mastra tool's `execute` lives on
79
+ * the instance.
80
+ * * `Run.prototype._start` / `_resume` (+ `_restart`, `_timeTravel`) and
81
+ * `DefaultExecutionEngine.prototype.executeStep` — the workflow span and its
82
+ * steps. Runs Mastra marks internal (`isInternalWorkflow`, or a
83
+ * `tracingPolicy.internal` with the WORKFLOW bit) are skipped, which is what
84
+ * keeps the agentic loop's own `execution-workflow` / `agentic-loop` out.
85
+ *
86
+ * Every copy of `@mastra/core` the application loads is patched — see
87
+ * `compat.requireModuleCopies()`: the ES-module and CommonJS builds are two
88
+ * unrelated sets of classes.
89
+ *
90
+ * ## How events find their agent
91
+ *
92
+ * An adapter-private `AsyncLocalStorage` carries the Mastra run that is
93
+ * executing (`Frame`). It never binds FailproofAI identity — it only answers
94
+ * "which of OUR runs is this?", and every event is still emitted through the
95
+ * `RunTracker` with an explicit parent key. The model proxy and the tool
96
+ * wrappers capture the frame when the run builds them, so an event keeps its
97
+ * agent even when Mastra later executes it from a stream the caller is
98
+ * pulling on a different async path. A tool call runs its body inside a
99
+ * `tool` frame of the calling agent, which is what nests a sub-agent under the
100
+ * agent that delegated to it — and, inside a workflow step, what attributes a
101
+ * tool to the agent that called it rather than to the workflow.
102
+ */
103
+
104
+ import { AsyncLocalStorage } from "node:async_hooks";
105
+ import { randomUUID } from "node:crypto";
106
+
107
+ import { current as currentIdentity } from "../context.js";
108
+ import { agent as agentScope } from "../scopes.js";
109
+ import * as compat from "./compat.js";
110
+ import * as core from "./core.js";
111
+ import type { Adapter } from "./core.js";
112
+
113
+ const NAME = "mastra";
114
+ const PACKAGE = "@mastra/core";
115
+ const INSTALL = "npm install @mastra/core";
116
+
117
+ /**
118
+ * The oldest release the patch points above all exist in with this shape:
119
+ * `resolveModelConfig` and `Run._start` both arrived in the 0.20 line, when
120
+ * `generate` / `stream` became the loop that calls a `LanguageModelV2` once per
121
+ * step. Earlier releases route model calls through the AI SDK's own
122
+ * `generateText` and run workflows through a different `Run`, so nothing here
123
+ * would see a model step or a workflow step.
124
+ */
125
+ const MINIMUM = "0.20.0";
126
+
127
+ /*
128
+ * ## Lifetime
129
+ *
130
+ * `instrument()` hands Mastra objects that outlive it: a model behind a proxy,
131
+ * tools behind wrappers, a stream the caller is still reading. Restoring the
132
+ * prototypes does not reach any of them, so every recording path checks that
133
+ * the tracker it began on is still LIVE (`live()`), and nothing recreates a
134
+ * tracker behind `uninstrument()`'s back:
135
+ *
136
+ * * `tracker` exists exactly while `enabled` — created by `install()`, dropped
137
+ * by `uninstall()`. A proxy, wrapper, span or frame remembers the tracker it
138
+ * was built under; once that tracker is gone it is a pass-through for good,
139
+ * even after a later `instrument()` creates a new one.
140
+ * * `uninstall()` turns `enabled` off FIRST, then closes what is still open —
141
+ * model steps, tool calls, workflow steps (marked `fw_incomplete`), then
142
+ * agents `cancelled` — so the trace ends where the recording did instead of
143
+ * leaving spans `ongoing` forever.
144
+ * * Open spans are tracked only so teardown can close them. Every end path
145
+ * removes its own entry; a stream nobody ever consumes has no end path, so
146
+ * the registries are bounded like the tracker's own run table.
147
+ * * `wrapTool()` works without `instrument()` — it is the call-site helper for
148
+ * bundled applications — so a call with no live installation records on a
149
+ * `standalone` tracker, which is self-contained (its run opens and closes in
150
+ * the one call) and never touched by `uninstall()`.
151
+ */
152
+
153
+ let enabled = false;
154
+ let tracker: core.RunTracker | null = null;
155
+ let standalone: core.RunTracker | null = null;
156
+ let patcher: core.Patcher | null = null;
157
+
158
+ function newTracker(options: Record<string, unknown> = {}): core.RunTracker {
159
+ return new core.RunTracker(NAME, {
160
+ baseFields: core.frameworkFields(NAME, PACKAGE),
161
+ fieldLimit: typeof options.captureLimit === "number" ? options.captureLimit : undefined,
162
+ });
163
+ }
164
+
165
+ /** May something begun on `t` still record? */
166
+ function live(t: core.RunTracker | null | undefined): t is core.RunTracker {
167
+ return t !== null && t !== undefined && ((enabled && t === tracker) || t === standalone);
168
+ }
169
+
170
+ /** Same bound as `RunTracker`'s own run table. */
171
+ const MAX_OPEN = 10_000;
172
+
173
+ /** A span that is open until it is `closed`, on the tracker it began on. */
174
+ interface Span {
175
+ tracker: core.RunTracker;
176
+ closed: boolean;
177
+ }
178
+
179
+ /** Open spans, oldest first, forgetting the oldest past `MAX_OPEN`. */
180
+ class OpenSpans<T extends Span> {
181
+ private readonly items = new Set<T>();
182
+
183
+ add(item: T): void {
184
+ while (this.items.size >= MAX_OPEN) {
185
+ const oldest = this.items.values().next();
186
+ if (oldest.done) break;
187
+ this.items.delete(oldest.value);
188
+ }
189
+ this.items.add(item);
190
+ }
191
+
192
+ /** End `item`: true when it was still open on a live tracker. */
193
+ close(item: T): boolean {
194
+ this.items.delete(item);
195
+ if (item.closed) return false;
196
+ item.closed = true;
197
+ return live(item.tracker);
198
+ }
199
+
200
+ /** Remove and return everything still open, newest first. */
201
+ drain(): T[] {
202
+ const all = [...this.items].reverse().filter((item) => !item.closed);
203
+ this.items.clear();
204
+ for (const item of all) item.closed = true;
205
+ return all;
206
+ }
207
+
208
+ get size(): number {
209
+ return this.items.size;
210
+ }
211
+ }
212
+
213
+ /** The Mastra run currently executing, as far as this adapter is concerned. */
214
+ interface Frame {
215
+ /** The tracker the run was begun on; a frame from a dead one records nothing. */
216
+ tracker: core.RunTracker;
217
+ /** Our `RunTracker` key for the agent or workflow run. */
218
+ key: string;
219
+ /** The `Agent` or workflow `Run` instance that owns the run. */
220
+ owner: object;
221
+ /** `tool` while a tool the agent called is executing. */
222
+ kind: "agent" | "workflow" | "tool";
223
+ /** Set on the frame of an `agent.network()` run, whose router it absorbs. */
224
+ network?: boolean;
225
+ /** Ends the agent run this frame is, for an end no Mastra callback reports. */
226
+ close?: (outcome: string) => void;
227
+ }
228
+
229
+ const frames = new AsyncLocalStorage<Frame>();
230
+
231
+ /** Mastra workflow run id -> our key, so a step can find its workflow span. */
232
+ const workflowRuns = new Map<string, string>();
233
+
234
+ const WRAPPED = Symbol.for("failproofai.wrapped");
235
+
236
+ /**
237
+ * Our own model proxies and agent-tool wrappers, to what they wrap. A reused
238
+ * agent can hand a later run the proxy or tool an earlier run built; that one
239
+ * is bound to the earlier run (or a dead installation), so it is unwrapped and
240
+ * observed afresh rather than skipped as "already wrapped".
241
+ */
242
+ const modelProxies = new WeakMap<object, object>();
243
+ const toolWrappers = new WeakMap<object, (...args: unknown[]) => unknown>();
244
+
245
+ function markWrapped<T extends object>(wrapper: T, original: unknown): T {
246
+ (wrapper as Record<symbol, unknown>)[WRAPPED] = original;
247
+ return wrapper;
248
+ }
249
+
250
+ // ---------------------------------------------------------------------------
251
+ // Small readers. Each takes whatever Mastra or a provider handed us and
252
+ // returns a value the schema accepts, or undefined — never throws.
253
+ // ---------------------------------------------------------------------------
254
+
255
+ function errorOf(error: unknown): { type: string; message: string } {
256
+ if (error instanceof Error) return { type: error.name || "Error", message: error.message };
257
+ if (typeof error === "object" && error !== null) {
258
+ const value = error as { name?: unknown; message?: unknown };
259
+ if (typeof value.message === "string") {
260
+ return { type: typeof value.name === "string" ? value.name : "Error", message: value.message };
261
+ }
262
+ }
263
+ return { type: typeof error, message: String(error) };
264
+ }
265
+
266
+ const describeError = (error: unknown): string => {
267
+ const detail = errorOf(error);
268
+ return `${detail.type}: ${detail.message}`;
269
+ };
270
+
271
+ function asInt(value: unknown): number | undefined {
272
+ return typeof value === "number" && Number.isFinite(value) && value >= 0
273
+ ? Math.round(value)
274
+ : undefined;
275
+ }
276
+
277
+ /**
278
+ * A token count in any of the provider shapes: a number (V1 `promptTokens`,
279
+ * V2 `inputTokens`) or V3's `{ total, … }` breakdown.
280
+ */
281
+ function tokenCount(value: unknown): number | undefined {
282
+ if (typeof value === "object" && value !== null) return asInt((value as { total?: unknown }).total);
283
+ return asInt(value);
284
+ }
285
+
286
+ function usageOf(usage: unknown): { inputTokens?: number; outputTokens?: number } {
287
+ if (typeof usage !== "object" || usage === null) return {};
288
+ const value = usage as Record<string, unknown>;
289
+ return {
290
+ inputTokens: tokenCount(value.inputTokens ?? value.promptTokens),
291
+ outputTokens: tokenCount(value.outputTokens ?? value.completionTokens),
292
+ };
293
+ }
294
+
295
+ /** V1/V2 finish reasons are strings; V3's are `{ unified, raw }`. */
296
+ function finishReasonOf(value: unknown): string | undefined {
297
+ if (typeof value === "string" && value) return value;
298
+ if (typeof value === "object" && value !== null) {
299
+ const { unified, raw } = value as { unified?: unknown; raw?: unknown };
300
+ if (typeof unified === "string" && unified) return unified;
301
+ if (typeof raw === "string" && raw) return raw;
302
+ }
303
+ return undefined;
304
+ }
305
+
306
+ function agentLabel(instance: unknown): { label: string; rawId?: string } {
307
+ const value = instance as { name?: unknown; id?: unknown } | undefined;
308
+ const raw = typeof value?.name === "string" && value.name ? value.name : value?.id;
309
+ const label = core.normalizeAgentId(raw, "mastra-agent");
310
+ const rawId = typeof value?.id === "string" && value.id !== label ? value.id : undefined;
311
+ return { label, rawId };
312
+ }
313
+
314
+ /** The run's goal: the prompt, when the caller handed one over as text. */
315
+ function goalOf(input: unknown): string | undefined {
316
+ if (typeof input === "string") return input;
317
+ if (!Array.isArray(input)) return undefined;
318
+ for (let i = input.length - 1; i >= 0; i -= 1) {
319
+ const item = input[i] as unknown;
320
+ if (typeof item === "string") return item;
321
+ const message = item as { role?: unknown; content?: unknown } | null;
322
+ if (message?.role === "user" && typeof message.content === "string") return message.content;
323
+ }
324
+ return undefined;
325
+ }
326
+
327
+ /** One `LanguageModel` prompt part, reduced to what a reader needs. */
328
+ function partToWire(part: unknown): unknown {
329
+ const value = (part ?? {}) as Record<string, unknown>;
330
+ switch (value.type) {
331
+ case "text":
332
+ return { type: "text", text: value.text };
333
+ case "tool-call":
334
+ return { type: "tool_call", id: value.toolCallId, name: value.toolName, input: value.input ?? value.args };
335
+ case "tool-result":
336
+ return { type: "tool_result", id: value.toolCallId, name: value.toolName, output: value.output ?? value.result };
337
+ default:
338
+ return { type: value.type };
339
+ }
340
+ }
341
+
342
+ function contentToWire(content: unknown): unknown {
343
+ if (!Array.isArray(content)) return content;
344
+ if (content.every((part) => (part as { type?: unknown } | null)?.type === "text")) {
345
+ return content.map((part) => (part as { text?: unknown }).text).join("");
346
+ }
347
+ return content.map(partToWire);
348
+ }
349
+
350
+ /**
351
+ * A `LanguageModel` call's prompt as `{messages, system}`.
352
+ *
353
+ * The provider-level prompt is what the model actually receives — the agent's
354
+ * instructions as a system message, memory, the tool results of earlier steps
355
+ * — so it is recorded rather than what the caller passed to `generate()`.
356
+ */
357
+ function promptOf(options: unknown): {
358
+ messages?: Array<Record<string, unknown>>;
359
+ system?: unknown;
360
+ tools?: Array<Record<string, unknown>>;
361
+ } {
362
+ const value = (options ?? {}) as { prompt?: unknown; tools?: unknown; mode?: { tools?: unknown } };
363
+ const out: ReturnType<typeof promptOf> = {};
364
+ if (Array.isArray(value.prompt)) {
365
+ const system: unknown[] = [];
366
+ const messages: Array<Record<string, unknown>> = [];
367
+ for (const item of value.prompt) {
368
+ const message = (item ?? {}) as { role?: unknown; content?: unknown };
369
+ if (message.role === "system") system.push(message.content);
370
+ else messages.push({ role: message.role, content: contentToWire(message.content) });
371
+ }
372
+ out.messages = messages;
373
+ if (system.length > 0) out.system = system.length === 1 ? system[0] : system;
374
+ }
375
+ const tools = Array.isArray(value.tools) ? value.tools : value.mode?.tools;
376
+ if (Array.isArray(tools) && tools.length > 0) {
377
+ out.tools = tools.map((tool) => {
378
+ const entry = (tool ?? {}) as { name?: unknown; description?: unknown };
379
+ return { name: entry.name, description: entry.description };
380
+ });
381
+ }
382
+ return out;
383
+ }
384
+
385
+ // ---------------------------------------------------------------------------
386
+ // Model steps
387
+ // ---------------------------------------------------------------------------
388
+
389
+ interface ModelCall extends Span {
390
+ requestId: string;
391
+ runKey: string;
392
+ model?: string;
393
+ started: number;
394
+ }
395
+
396
+ const openModels = new OpenSpans<ModelCall>();
397
+
398
+ interface ModelOutcome {
399
+ model?: string;
400
+ finishReason?: string;
401
+ usage?: unknown;
402
+ text?: string;
403
+ toolCalls?: Array<Record<string, unknown>>;
404
+ error?: unknown;
405
+ }
406
+
407
+ function modelIdOf(model: object): string | undefined {
408
+ const id = (model as { modelId?: unknown }).modelId;
409
+ return typeof id === "string" && id ? id : undefined;
410
+ }
411
+
412
+ function beginModelCall(frame: Frame, model: object, options: unknown): ModelCall | undefined {
413
+ const t = frame.tracker;
414
+ if (!live(t)) return undefined;
415
+ const runKey = frame.key;
416
+ const requestId = randomUUID();
417
+ const modelId = modelIdOf(model);
418
+ const provider = (model as { provider?: unknown }).provider;
419
+ t.emit("modelRequest", requestId, {
420
+ parentKey: runKey,
421
+ model: modelId,
422
+ ...promptOf(options),
423
+ requestId,
424
+ ...core.fwFields({ provider: typeof provider === "string" ? provider : undefined }),
425
+ });
426
+ const call: ModelCall = { tracker: t, closed: false, requestId, runKey, model: modelId, started: Date.now() };
427
+ openModels.add(call);
428
+ return call;
429
+ }
430
+
431
+ function endModelCall(call: ModelCall, outcome: ModelOutcome): void {
432
+ // Already closed — by teardown, when its installation is gone.
433
+ if (!openModels.close(call)) return;
434
+ const usage = usageOf(outcome.usage);
435
+ call.tracker.emit("modelResponse", call.requestId, {
436
+ parentKey: call.runKey,
437
+ model: outcome.model ?? call.model,
438
+ stopReason: outcome.finishReason ?? (outcome.error !== undefined ? "error" : undefined),
439
+ inputTokens: usage.inputTokens,
440
+ outputTokens: usage.outputTokens,
441
+ content: outcome.text ? outcome.text : undefined,
442
+ role: "assistant",
443
+ requestId: call.requestId,
444
+ error: outcome.error === undefined ? undefined : describeError(outcome.error),
445
+ ...core.fwFields({
446
+ duration_ms: core.ms(Date.now() - call.started),
447
+ tool_calls: outcome.toolCalls?.length ? outcome.toolCalls : undefined,
448
+ }),
449
+ });
450
+ }
451
+
452
+ /** What a `doGenerate` result says, in any of the V1–V3 shapes. */
453
+ function generateOutcome(result: unknown): ModelOutcome {
454
+ const value = (result ?? {}) as {
455
+ content?: unknown;
456
+ text?: unknown;
457
+ toolCalls?: unknown;
458
+ finishReason?: unknown;
459
+ usage?: unknown;
460
+ response?: { modelId?: unknown };
461
+ };
462
+ let text = typeof value.text === "string" ? value.text : "";
463
+ const toolCalls: Array<Record<string, unknown>> = [];
464
+ if (Array.isArray(value.content)) {
465
+ for (const part of value.content) {
466
+ const entry = (part ?? {}) as Record<string, unknown>;
467
+ if (entry.type === "text" && typeof entry.text === "string") text += entry.text;
468
+ if (entry.type === "tool-call") {
469
+ toolCalls.push({ id: entry.toolCallId, name: entry.toolName, input: entry.input ?? entry.args });
470
+ }
471
+ }
472
+ }
473
+ if (Array.isArray(value.toolCalls)) {
474
+ for (const call of value.toolCalls) {
475
+ const entry = (call ?? {}) as Record<string, unknown>;
476
+ toolCalls.push({ id: entry.toolCallId, name: entry.toolName, input: entry.args ?? entry.input });
477
+ }
478
+ }
479
+ return {
480
+ model: typeof value.response?.modelId === "string" ? value.response.modelId : undefined,
481
+ finishReason: finishReasonOf(value.finishReason),
482
+ usage: value.usage,
483
+ text,
484
+ toolCalls,
485
+ };
486
+ }
487
+
488
+ /**
489
+ * Fold one `doStream` part into the step's outcome. The stream is the only
490
+ * place a streamed step's usage and finish reason exist, so they are read as
491
+ * they pass rather than from Mastra's aggregate afterwards.
492
+ */
493
+ function foldStreamPart(outcome: ModelOutcome, part: unknown): void {
494
+ const value = (part ?? {}) as Record<string, unknown>;
495
+ switch (value.type) {
496
+ case "text-delta": {
497
+ const delta = value.delta ?? value.textDelta;
498
+ if (typeof delta === "string") outcome.text = (outcome.text ?? "") + delta;
499
+ break;
500
+ }
501
+ case "tool-call":
502
+ (outcome.toolCalls ??= []).push({
503
+ id: value.toolCallId,
504
+ name: value.toolName,
505
+ input: value.input ?? value.args,
506
+ });
507
+ break;
508
+ case "response-metadata":
509
+ if (typeof value.modelId === "string" && value.modelId) outcome.model = value.modelId;
510
+ break;
511
+ case "finish":
512
+ outcome.finishReason = finishReasonOf(value.finishReason);
513
+ outcome.usage = value.usage;
514
+ break;
515
+ case "error":
516
+ outcome.error = value.error;
517
+ break;
518
+ default:
519
+ break;
520
+ }
521
+ }
522
+
523
+ type ModelMethod = (options: unknown) => PromiseLike<unknown>;
524
+
525
+ /**
526
+ * One observed `doGenerate` / `doStream` call: a step.
527
+ *
528
+ * The result decides how the step ends, not the method name. A provider's
529
+ * `doGenerate` answers with the finished content, but the model Mastra 0.x
530
+ * resolves is its own V5 wrapper, whose `doGenerate` ALSO answers with a
531
+ * `stream` — reading the result as a finished generation there records a step
532
+ * with no tokens and no stop reason. So a result carrying a readable stream is
533
+ * observed as one, whichever method produced it.
534
+ */
535
+ function observedCall(target: object, original: ModelMethod, frame: Frame, name: string): ModelMethod {
536
+ const observed = async function (options: unknown): Promise<unknown> {
537
+ // Built under an installation that is gone: the model, untouched.
538
+ if (!live(frame.tracker)) return original.call(target, options);
539
+ const call = core.callSafely(beginModelCall, [frame, target, options], `${NAME}.model`);
540
+ let result: unknown;
541
+ try {
542
+ result = await original.call(target, options);
543
+ } catch (error) {
544
+ if (call) core.callSafely(endModelCall, [call, { error }], `${NAME}.model`);
545
+ throw error;
546
+ }
547
+ if (!call) return result;
548
+ const stream = (result as { stream?: unknown } | null)?.stream;
549
+ if (typeof (stream as ReadableStream | undefined)?.getReader !== "function") {
550
+ core.callSafely(
551
+ (value: unknown) => endModelCall(call, generateOutcome(value)),
552
+ [result],
553
+ `${NAME}.model`,
554
+ );
555
+ return result;
556
+ }
557
+ const outcome: ModelOutcome = {};
558
+ return {
559
+ ...(result as object),
560
+ // Pull-based, so a consumer that cancels still closes the step (see
561
+ // core.observeStream). A cancel ends it with the cancel reason as its error.
562
+ stream: core.observeStream(
563
+ stream as ReadableStream<unknown>,
564
+ (part) => foldStreamPart(outcome, part),
565
+ (error) => endModelCall(call, error === undefined ? outcome : { ...outcome, error: outcome.error ?? error }),
566
+ `${NAME}.stream`,
567
+ ),
568
+ };
569
+ };
570
+ Object.defineProperty(observed, "name", { value: name, configurable: true });
571
+ return observed;
572
+ }
573
+
574
+ /**
575
+ * Hand a resolved model back behind a proxy that observes its two call
576
+ * methods and is otherwise the model.
577
+ *
578
+ * Every other method is bound to the real model, and every property read with
579
+ * the real model as receiver: a provider class that keeps state in `#private`
580
+ * fields throws when one of its methods runs with a proxy as `this`.
581
+ */
582
+ function observeModel(model: unknown, frame: Frame): unknown {
583
+ if (typeof model !== "object" || model === null) return model;
584
+ // One of ours from an earlier run: observe the model it wraps, for THIS run.
585
+ const target = modelProxies.get(model) ?? model;
586
+ const doGenerate = (target as { doGenerate?: unknown }).doGenerate;
587
+ const doStream = (target as { doStream?: unknown }).doStream;
588
+ if (typeof doGenerate !== "function" && typeof doStream !== "function") return model;
589
+ if ((target as Record<symbol, unknown>)[WRAPPED] !== undefined) return model;
590
+
591
+ const cache = new Map<PropertyKey, unknown>();
592
+ const proxy = new Proxy(target, {
593
+ get(object, property) {
594
+ if (property === WRAPPED) return target;
595
+ const value: unknown = Reflect.get(object, property);
596
+ if (typeof value !== "function" || property === "constructor") return value;
597
+ let bound = cache.get(property);
598
+ if (bound === undefined || (bound as { [WRAPPED]?: unknown })[WRAPPED] !== value) {
599
+ const method = value as ModelMethod;
600
+ bound =
601
+ property === "doGenerate" || property === "doStream"
602
+ ? observedCall(object, method, frame, property)
603
+ : (method as (...args: unknown[]) => unknown).bind(object);
604
+ markWrapped(bound as object, value);
605
+ cache.set(property, bound);
606
+ }
607
+ return bound;
608
+ },
609
+ });
610
+ modelProxies.set(proxy, target);
611
+ return proxy;
612
+ }
613
+
614
+ // ---------------------------------------------------------------------------
615
+ // Tools
616
+ // ---------------------------------------------------------------------------
617
+
618
+ /**
619
+ * A tool call that returned a failure instead of throwing it.
620
+ *
621
+ * Mastra 0.x catches a tool's exception and hands the model a `MastraError`
622
+ * (1.x re-throws it); both lines return a `{ error: true, message }` object
623
+ * for input that fails validation. Either way the call failed, and a
624
+ * `tool_result` recording it as output would say otherwise.
625
+ */
626
+ function failureOf(value: unknown): unknown {
627
+ if (value instanceof Error) return value;
628
+ if (typeof value === "object" && value !== null) {
629
+ const flagged = value as { error?: unknown; message?: unknown };
630
+ if (flagged.error === true && typeof flagged.message === "string") return flagged;
631
+ }
632
+ return undefined;
633
+ }
634
+
635
+ function inputRecord(input: unknown): Record<string, unknown> | undefined {
636
+ if (input === undefined || input === null) return undefined;
637
+ if (typeof input === "object" && !Array.isArray(input)) return input as Record<string, unknown>;
638
+ return { input };
639
+ }
640
+
641
+ interface ToolCall extends Span {
642
+ key: string;
643
+ toolName: string;
644
+ toolCallId: string;
645
+ parentKey?: string;
646
+ /** Set when the call opened its own root run, which it must close. */
647
+ ownRun?: string;
648
+ }
649
+
650
+ const openTools = new OpenSpans<ToolCall>();
651
+
652
+ function beginToolCall(
653
+ t: core.RunTracker,
654
+ toolName: string,
655
+ toolCallId: string,
656
+ input: unknown,
657
+ parentKey: string | undefined,
658
+ ): ToolCall | undefined {
659
+ if (!live(t)) return undefined;
660
+ let ownRun: string | undefined;
661
+ if (parentKey === undefined && currentIdentity().sessionId === null) {
662
+ // Nothing is running and no scope is open: a tool called on its own is its
663
+ // own run, exactly as a bare LangChain tool is, rather than an event
664
+ // dropped for want of a session.
665
+ ownRun = randomUUID();
666
+ t.startAgent(ownRun, { agentId: core.normalizeAgentId(toolName, "tool"), ...core.fwFields({ kind: "tool" }) });
667
+ parentKey = ownRun;
668
+ }
669
+ const key = `${parentKey ?? "ambient"}:tool:${toolCallId}:${randomUUID()}`;
670
+ t.emit("toolUse", key, { parentKey, toolName, toolCallId, input: inputRecord(input) });
671
+ const call: ToolCall = { tracker: t, closed: false, key, toolName, toolCallId, parentKey, ownRun };
672
+ openTools.add(call);
673
+ return call;
674
+ }
675
+
676
+ function endToolCall(call: ToolCall, output: unknown, error?: unknown): void {
677
+ // Already closed — by teardown, when its installation is gone.
678
+ if (!openTools.close(call)) return;
679
+ const t = call.tracker;
680
+ const failure = error ?? failureOf(output);
681
+ t.emit("toolResult", call.key, {
682
+ parentKey: call.parentKey,
683
+ toolName: call.toolName,
684
+ toolCallId: call.toolCallId,
685
+ output: failure === undefined ? output : undefined,
686
+ error: failure === undefined ? undefined : describeError(failure),
687
+ });
688
+ if (call.ownRun !== undefined) {
689
+ t.endAgent(call.ownRun, { outcome: failure === undefined ? "success" : "failed" });
690
+ }
691
+ }
692
+
693
+ /**
694
+ * Run `execute` bracketed by a tool span; the one `try` only re-throws.
695
+ * `frame` is what the tool's own body runs inside, when there is one.
696
+ */
697
+ function runTool(
698
+ begin: () => ToolCall | undefined,
699
+ execute: () => unknown,
700
+ frame: Frame | undefined,
701
+ ): unknown {
702
+ const call = core.callSafely(begin, [], `${NAME}.tool`);
703
+ if (!call) return execute();
704
+ const end = (output: unknown, error?: unknown): void => {
705
+ core.callSafely(endToolCall, [call, output, error], `${NAME}.tool`);
706
+ };
707
+ let result: unknown;
708
+ try {
709
+ result = frame ? frames.run(frame, execute) : execute();
710
+ } catch (error) {
711
+ end(undefined, error);
712
+ throw error;
713
+ }
714
+ if (typeof (result as PromiseLike<unknown> | null)?.then === "function") {
715
+ return (result as PromiseLike<unknown>).then(
716
+ (value) => {
717
+ end(value);
718
+ return value;
719
+ },
720
+ (error: unknown) => {
721
+ end(undefined, error);
722
+ throw error;
723
+ },
724
+ );
725
+ }
726
+ end(result);
727
+ return result;
728
+ }
729
+
730
+ /** A copy of `tool` with a new `execute`, keeping its prototype and fields. */
731
+ function withExecute<T extends object>(tool: T, execute: unknown): T {
732
+ return Object.assign(Object.create(Object.getPrototypeOf(tool) as object | null) as T, tool, { execute });
733
+ }
734
+
735
+ /**
736
+ * Wrap the tools one agent run is about to execute.
737
+ *
738
+ * These are the loop's converted tools, which all share the AI SDK signature
739
+ * `execute(input, { toolCallId, … })` whatever kind of tool they came from, on
740
+ * both major lines — so the input is the validated arguments and the id is the
741
+ * model's own.
742
+ */
743
+ function observeTools(tools: unknown, runFrame: Frame, agent: object): unknown {
744
+ if (typeof tools !== "object" || tools === null) return tools;
745
+ const out: Record<string, unknown> = { ...(tools as Record<string, unknown>) };
746
+ const frame: Frame = { tracker: runFrame.tracker, key: runFrame.key, owner: agent, kind: "tool" };
747
+ for (const [name, tool] of Object.entries(out)) {
748
+ const execute = (tool as { execute?: unknown } | null)?.execute;
749
+ if (typeof tool !== "object" || tool === null || typeof execute !== "function") continue;
750
+ // One of ours from an earlier run: wrap what it wraps, for THIS run.
751
+ const ours = toolWrappers.get(execute);
752
+ if (ours === undefined && (execute as unknown as Record<symbol, unknown>)[WRAPPED] !== undefined) continue;
753
+ const original = ours ?? (execute as (...args: unknown[]) => unknown);
754
+ const wrapped = function failproofaiToolExecute(this: unknown, ...args: unknown[]): unknown {
755
+ // Built under an installation that is gone: the tool, untouched.
756
+ if (!live(frame.tracker)) return original.apply(this, args);
757
+ const options = args[1] as { toolCallId?: unknown } | undefined;
758
+ const toolCallId = typeof options?.toolCallId === "string" ? options.toolCallId : randomUUID();
759
+ return runTool(
760
+ () => beginToolCall(frame.tracker, name, toolCallId, args[0], frame.key),
761
+ () => original.apply(this, args),
762
+ frame,
763
+ );
764
+ };
765
+ toolWrappers.set(wrapped, original);
766
+ out[name] = withExecute(tool, markWrapped(wrapped, original));
767
+ }
768
+ return out;
769
+ }
770
+
771
+ /**
772
+ * The input and call id of a direct `tool.execute(...)` call, in either
773
+ * major's signature: 1.x `execute(input, { agent: { toolCallId } })`, 0.x
774
+ * `execute({ context: input, runtimeContext, … }, { toolCallId })`.
775
+ */
776
+ function toolCallArgs(args: unknown[]): { input: unknown; toolCallId?: string } {
777
+ const [first, second] = args as [unknown, Record<string, unknown> | undefined];
778
+ const pick = (...values: unknown[]): string | undefined =>
779
+ values.find((value): value is string => typeof value === "string" && value !== "");
780
+ const legacy =
781
+ typeof first === "object" &&
782
+ first !== null &&
783
+ "context" in first &&
784
+ ("runtimeContext" in first || second === undefined || typeof second.toolCallId === "string");
785
+ if (legacy) {
786
+ const envelope = first as { context?: unknown; toolCallId?: unknown };
787
+ return { input: envelope.context, toolCallId: pick(second?.toolCallId, envelope.toolCallId) };
788
+ }
789
+ const agentContext = second?.agent as { toolCallId?: unknown } | undefined;
790
+ return { input: first, toolCallId: pick(agentContext?.toolCallId, second?.toolCallId) };
791
+ }
792
+
793
+ /**
794
+ * Wrap one Mastra tool's `execute` so a DIRECT call is recorded.
795
+ *
796
+ * A tool an agent executes is already recorded by `instrument()` — including
797
+ * tools built before it ran — so this is for the calls no agent makes: a tool
798
+ * invoked from your own code or a workflow step. Inside a Mastra run or a
799
+ * `failproofai` scope it records under that; with nothing open it records the
800
+ * call as its own run, named after the tool. A wrapped tool handed to an agent
801
+ * is not recorded twice.
802
+ */
803
+ export function wrapTool<T extends { id?: string; execute?: (...args: never[]) => unknown }>(
804
+ tool: T,
805
+ ): T {
806
+ const execute = tool.execute;
807
+ if (typeof execute !== "function" || core.isWrapped(execute)) return tool;
808
+ const toolName = typeof tool.id === "string" && tool.id ? tool.id : "tool";
809
+ const original = execute as unknown as (...args: unknown[]) => unknown;
810
+
811
+ const wrapped = function failproofaiToolExecute(this: unknown, ...args: unknown[]): unknown {
812
+ const frame = frames.getStore();
813
+ // The agent's own tool wrapper is already recording this very call; and
814
+ // inside a run whose installation is gone, nothing records.
815
+ if (frame?.kind === "tool" || (frame !== undefined && !live(frame.tracker))) {
816
+ return original.apply(this, args);
817
+ }
818
+ return runTool(
819
+ () => {
820
+ const { input, toolCallId } = toolCallArgs(args);
821
+ const t = frame?.tracker ?? (enabled && tracker !== null ? tracker : (standalone ??= newTracker()));
822
+ return beginToolCall(t, toolName, toolCallId ?? randomUUID(), input, frame?.key);
823
+ },
824
+ () => original.apply(this, args),
825
+ undefined,
826
+ );
827
+ };
828
+ // A new object rather than a mutation: a Mastra tool may be frozen, and
829
+ // assigning to a frozen object fails silently in sloppy mode. The prototype
830
+ // is kept so it is still a `Tool` to Mastra's own checks.
831
+ return withExecute(tool, markWrapped(wrapped, original));
832
+ }
833
+
834
+ // ---------------------------------------------------------------------------
835
+ // Agents
836
+ // ---------------------------------------------------------------------------
837
+
838
+ /**
839
+ * How an agent method is called: `generate` resolves with the finished run,
840
+ * `stream` resolves as soon as the loop starts and finishes as the caller
841
+ * consumes it, and `network` resolves with a stream that runs on its own.
842
+ */
843
+ type AgentCallMode = "generate" | "stream" | "network";
844
+
845
+ interface AgentRun {
846
+ tracker: core.RunTracker;
847
+ key: string;
848
+ frame: Frame;
849
+ args: unknown[];
850
+ started: number;
851
+ ended: boolean;
852
+ /**
853
+ * Set when this call is recorded as part of an enclosing span rather than as
854
+ * a span of its own — a network's router — so it never emits `agent_end`.
855
+ */
856
+ borrowed?: boolean;
857
+ }
858
+
859
+ function endAgentRun(run: AgentRun, outcome: string): void {
860
+ if (run.ended) return;
861
+ run.ended = true;
862
+ if (run.borrowed) return;
863
+ // Closed `cancelled` already, by the teardown that made it not live.
864
+ if (!live(run.tracker)) return;
865
+ run.tracker.endAgent(run.key, {
866
+ outcome,
867
+ ...core.fwFields({ duration_ms: core.ms(Date.now() - run.started) }),
868
+ });
869
+ }
870
+
871
+ /** How a finished `generate()` / `onFinish` result ended. */
872
+ function outcomeOf(result: unknown): string {
873
+ const value = (result ?? {}) as { error?: unknown; finishReason?: unknown; tripwire?: unknown };
874
+ if (value.tripwire) return "rejected";
875
+ if (value.error || value.finishReason === "error") return "failed";
876
+ return "success";
877
+ }
878
+
879
+ /**
880
+ * Compose our end-of-stream callbacks with the caller's.
881
+ *
882
+ * Mastra calls `onFinish` / `onError` / `onAbort` when the stream actually
883
+ * finishes — as it is consumed — which is the moment the run ends. Reading one
884
+ * of the output's promise getters instead would START consumption: Mastra
885
+ * drains the stream into a buffer the first time one is touched, so observing
886
+ * the run would change what it does.
887
+ */
888
+ function withStreamCallbacks(options: unknown, run: AgentRun): Record<string, unknown> {
889
+ const base = (typeof options === "object" && options !== null ? options : {}) as Record<string, unknown>;
890
+ const chain =
891
+ (name: string, ours: (...args: unknown[]) => void) =>
892
+ (...args: unknown[]): unknown => {
893
+ core.callSafely(ours, args, `${NAME}.${name}`);
894
+ const theirs = base[name];
895
+ return typeof theirs === "function" ? (theirs as (...a: unknown[]) => unknown).apply(base, args) : undefined;
896
+ };
897
+ return {
898
+ ...base,
899
+ onFinish: chain("onFinish", (result) => endAgentRun(run, outcomeOf(result))),
900
+ onError: chain("onError", () => endAgentRun(run, "failed")),
901
+ onAbort: chain("onAbort", () => endAgentRun(run, "cancelled")),
902
+ };
903
+ }
904
+
905
+ /**
906
+ * Close a streamed run that no callback will close.
907
+ *
908
+ * A stream a processor blocks — an input processor's `abort()`, or one on the
909
+ * output stream — ends with a `tripwire` chunk and calls none of `onFinish` /
910
+ * `onError` / `onAbort` (1.x and 0.x alike), so without this its agent stayed
911
+ * open forever. The output's `_waitUntilFinished()` settles when the stream
912
+ * does, without starting consumption the way its promise getters would; a run
913
+ * the callbacks already closed makes this a no-op.
914
+ */
915
+ function closeWhenFinished(run: AgentRun, output: unknown): void {
916
+ const wait = (output as { _waitUntilFinished?: unknown } | null)?._waitUntilFinished;
917
+ if (typeof wait !== "function") return;
918
+ const waiting = (wait as () => unknown).call(output);
919
+ const finish = (): void => {
920
+ endAgentRun(run, (output as { tripwire?: unknown }).tripwire ? "rejected" : "success");
921
+ };
922
+ Promise.resolve(waiting).then(
923
+ () => core.callSafely(finish, [], `${NAME}.stream`),
924
+ () => undefined,
925
+ );
926
+ }
927
+
928
+ /**
929
+ * Close a network run when its stream does.
930
+ *
931
+ * `network()` resolves with a stream that runs by itself — its workflow starts
932
+ * as the stream is constructed and does not wait on the reader — and whose
933
+ * `status` getter settles once it has finished, without consuming anything.
934
+ */
935
+ function closeNetworkWhenFinished(run: AgentRun, stream: unknown): void {
936
+ const status = (stream as { status?: unknown } | null)?.status;
937
+ if (typeof (status as PromiseLike<unknown> | undefined)?.then !== "function") {
938
+ endAgentRun(run, "success");
939
+ return;
940
+ }
941
+ const site = `${NAME}.network`;
942
+ Promise.resolve(status).then(
943
+ (value) => core.callSafely(endAgentRun, [run, workflowOutcome(value)], site),
944
+ () => core.callSafely(endAgentRun, [run, "failed"], site),
945
+ );
946
+ }
947
+
948
+ const nonEmpty = (value: unknown): string | undefined =>
949
+ typeof value === "string" && value !== "" ? value : undefined;
950
+
951
+ /**
952
+ * The conversation a call belongs to: its memory thread and resource, in the
953
+ * 1.x shape (`memory: { thread, resource }`, the thread a string or `{ id }`)
954
+ * or 0.x's older top-level `threadId` / `resourceId`.
955
+ */
956
+ function conversationOf(options: unknown): { thread?: string; resource?: string } {
957
+ const value = (typeof options === "object" && options !== null ? options : {}) as {
958
+ threadId?: unknown;
959
+ resourceId?: unknown;
960
+ memory?: unknown;
961
+ };
962
+ const memory = (typeof value.memory === "object" && value.memory !== null ? value.memory : {}) as {
963
+ thread?: unknown;
964
+ resource?: unknown;
965
+ };
966
+ const threadObject = (typeof memory.thread === "object" && memory.thread !== null ? memory.thread : {}) as {
967
+ id?: unknown;
968
+ };
969
+ return {
970
+ thread: nonEmpty(memory.thread) ?? nonEmpty(threadObject.id) ?? nonEmpty(value.threadId),
971
+ resource: nonEmpty(memory.resource) ?? nonEmpty(value.resourceId),
972
+ };
973
+ }
974
+
975
+ /**
976
+ * The agent an `agent.network()` builds for itself to route with.
977
+ *
978
+ * Every routing decision and completion check of a network is a fresh
979
+ * `routing-agent` running on the network agent's own model. It IS the
980
+ * network's decision loop, so its model calls are recorded as the network
981
+ * agent's own steps rather than as one more agent per decision.
982
+ */
983
+ function isRoutingAgent(agent: object): boolean {
984
+ const { id, name } = agent as { id?: unknown; name?: unknown };
985
+ return id === "routing-agent" || name === "routing-agent";
986
+ }
987
+
988
+ /**
989
+ * Whether a run is a root nothing has put in a session yet — then the
990
+ * conversation id the framework gives it is its session. An enclosing
991
+ * `failproofai.session()` / `agent()` scope always wins.
992
+ */
993
+ function isUnscopedRoot(parent: Frame | undefined): boolean {
994
+ return parent === undefined && currentIdentity().sessionId === null;
995
+ }
996
+
997
+ function beginAgentRun(agent: object, method: string, args: unknown[], mode: AgentCallMode): AgentRun | undefined {
998
+ const t = tracker;
999
+ if (!enabled || t === null) return undefined;
1000
+ const parent = frames.getStore();
1001
+ // Inside a run whose installation is gone: that whole tree is unrecorded.
1002
+ if (parent !== undefined && !live(parent.tracker)) return undefined;
1003
+ // Re-entry from inside the same run — 0.x's `generate` is `stream` under the
1004
+ // hood — is the same agent span, not a nested one.
1005
+ if (parent?.kind === "agent" && parent.owner === agent) return undefined;
1006
+ if (parent?.network === true && isRoutingAgent(agent)) {
1007
+ // The network's own router: recorded on the network's span, not its own.
1008
+ return {
1009
+ tracker: t,
1010
+ key: parent.key,
1011
+ frame: { tracker: t, key: parent.key, owner: agent, kind: "agent" },
1012
+ args,
1013
+ started: Date.now(),
1014
+ ended: false,
1015
+ borrowed: true,
1016
+ };
1017
+ }
1018
+ const key = randomUUID();
1019
+ const { label, rawId } = agentLabel(agent);
1020
+ const { thread, resource } = conversationOf(args[1]);
1021
+ t.startAgent(key, {
1022
+ agentId: label,
1023
+ parentKey: parent?.key,
1024
+ // A memory thread is a conversation that spans runs: the session, for a
1025
+ // run nothing else has put in one.
1026
+ sessionId: isUnscopedRoot(parent) ? thread : undefined,
1027
+ goal: goalOf(args[0]),
1028
+ ...core.fwFields({
1029
+ agent_id: rawId,
1030
+ method,
1031
+ streaming: mode === "stream" || undefined,
1032
+ thread_id: thread,
1033
+ resource_id: resource,
1034
+ }),
1035
+ });
1036
+ const run: AgentRun = {
1037
+ tracker: t,
1038
+ key,
1039
+ frame: { tracker: t, key, owner: agent, kind: "agent", network: mode === "network" || undefined },
1040
+ args,
1041
+ started: Date.now(),
1042
+ ended: false,
1043
+ };
1044
+ run.frame.close = (outcome: string): void => endAgentRun(run, outcome);
1045
+ if (mode === "stream") {
1046
+ const next = [...args];
1047
+ while (next.length < 2) next.push(undefined);
1048
+ next[1] = withStreamCallbacks(args[1], run);
1049
+ run.args = next;
1050
+ }
1051
+ return run;
1052
+ }
1053
+
1054
+ function patchAgentMethod(prototype: object, method: string, mode: AgentCallMode): boolean {
1055
+ const original = (prototype as Record<string, unknown>)[method];
1056
+ if (typeof original !== "function" || core.isWrapped(original)) return false;
1057
+ const fn = original as (...args: unknown[]) => unknown;
1058
+ const site = `${NAME}.${method}`;
1059
+
1060
+ const wrapper = function failproofaiAgentCall(this: object, ...args: unknown[]): unknown {
1061
+ const run = core.callSafely(beginAgentRun, [this, method, args, mode], site);
1062
+ if (!run) return fn.apply(this, args);
1063
+ const settle = (value: unknown): void => {
1064
+ if (run.borrowed) return;
1065
+ // A stream ends through its callbacks — `stream()` returning only means
1066
+ // the loop has started — or, when none will fire, as it finishes.
1067
+ if (mode === "stream") core.callSafely(closeWhenFinished, [run, value], site);
1068
+ else if (mode === "network") core.callSafely(closeNetworkWhenFinished, [run, value], site);
1069
+ else core.callSafely(endAgentRun, [run, outcomeOf(value)], site);
1070
+ };
1071
+ let result: unknown;
1072
+ try {
1073
+ result = frames.run(run.frame, () => fn.apply(this, run.args));
1074
+ } catch (error) {
1075
+ core.callSafely(endAgentRun, [run, "failed"], site);
1076
+ throw error;
1077
+ }
1078
+ if (typeof (result as PromiseLike<unknown> | null)?.then === "function") {
1079
+ return (result as PromiseLike<unknown>).then(
1080
+ (value) => {
1081
+ settle(value);
1082
+ return value;
1083
+ },
1084
+ (error: unknown) => {
1085
+ core.callSafely(endAgentRun, [run, "failed"], site);
1086
+ throw error;
1087
+ },
1088
+ );
1089
+ }
1090
+ settle(result);
1091
+ return result;
1092
+ };
1093
+ Object.defineProperty(wrapper, "name", { value: fn.name, configurable: true });
1094
+ return patcher!.patch(prototype, method, markWrapped(wrapper, original));
1095
+ }
1096
+
1097
+ /**
1098
+ * End a run the moment an input processor blocks its prompt.
1099
+ *
1100
+ * `__runInputProcessors` is where every input processor's `abort()` lands, and
1101
+ * its result says so (`tripwire` in 1.x, `tripwireTriggered` in 0.x). A
1102
+ * blocked `generate()` resolves with the tripwire and ends there anyway, but a
1103
+ * blocked `stream()` calls none of its callbacks — and 0.x's output offers no
1104
+ * other end signal — so without this its agent stayed open for good. Nothing
1105
+ * the run would have done follows a blocked prompt, so it ends here.
1106
+ */
1107
+ function patchInputProcessors(prototype: object): void {
1108
+ const method = "__runInputProcessors";
1109
+ const original = (prototype as Record<string, unknown>)[method];
1110
+ if (typeof original !== "function" || core.isWrapped(original)) return;
1111
+ const fn = original as (...args: unknown[]) => unknown;
1112
+ const site = `${NAME}.inputProcessors`;
1113
+ const blocked = (value: unknown): boolean => {
1114
+ const result = (value ?? {}) as { tripwire?: unknown; tripwireTriggered?: unknown };
1115
+ return result.tripwireTriggered === true || (result.tripwire !== undefined && result.tripwire !== null && result.tripwire !== false);
1116
+ };
1117
+ const wrapper = function failproofaiInputProcessors(this: object, ...args: unknown[]): unknown {
1118
+ const frame = frames.getStore();
1119
+ const result = fn.apply(this, args);
1120
+ const close = frame?.kind === "agent" && frame.owner === this ? frame.close : undefined;
1121
+ if (close === undefined) return result;
1122
+ const check = (value: unknown): void => {
1123
+ if (blocked(value)) close("rejected");
1124
+ };
1125
+ if (typeof (result as PromiseLike<unknown> | null)?.then === "function") {
1126
+ return (result as PromiseLike<unknown>).then((value) => {
1127
+ core.callSafely(check, [value], site);
1128
+ return value;
1129
+ });
1130
+ }
1131
+ core.callSafely(check, [result], site);
1132
+ return result;
1133
+ };
1134
+ Object.defineProperty(wrapper, "name", { value: fn.name, configurable: true });
1135
+ patcher!.patch(prototype, method, markWrapped(wrapper, original));
1136
+ }
1137
+
1138
+ /**
1139
+ * Patch a method that BUILDS something the run will use later, so the result
1140
+ * is observed with the run that built it. `observe` sees only calls made by
1141
+ * the agent's own run; any other caller gets Mastra's value untouched.
1142
+ */
1143
+ function patchBuilder(
1144
+ prototype: object,
1145
+ method: string,
1146
+ observe: (value: unknown, frame: Frame, agent: object) => unknown,
1147
+ ): boolean {
1148
+ const original = (prototype as Record<string, unknown>)[method];
1149
+ if (typeof original !== "function" || core.isWrapped(original)) return false;
1150
+ const fn = original as (...args: unknown[]) => unknown;
1151
+ const site = `${NAME}.${method}`;
1152
+ const wrapper = function failproofaiBuilder(this: object, ...args: unknown[]): unknown {
1153
+ const frame = frames.getStore();
1154
+ const result = fn.apply(this, args);
1155
+ if (frame?.kind !== "agent" || frame.owner !== this || !live(frame.tracker)) return result;
1156
+ const apply = (value: unknown): unknown => {
1157
+ const observed = core.callSafely(observe, [value, frame, this], site);
1158
+ return observed === undefined ? value : observed;
1159
+ };
1160
+ return typeof (result as PromiseLike<unknown> | null)?.then === "function"
1161
+ ? (result as PromiseLike<unknown>).then(apply)
1162
+ : apply(result);
1163
+ };
1164
+ Object.defineProperty(wrapper, "name", { value: fn.name, configurable: true });
1165
+ return patcher!.patch(prototype, method, markWrapped(wrapper, original));
1166
+ }
1167
+
1168
+ // ---------------------------------------------------------------------------
1169
+ // Workflows
1170
+ // ---------------------------------------------------------------------------
1171
+
1172
+ interface WorkflowRunLike {
1173
+ workflowId?: unknown;
1174
+ runId?: unknown;
1175
+ isInternalWorkflow?: unknown;
1176
+ tracingPolicy?: { internal?: unknown };
1177
+ }
1178
+
1179
+ /** `InternalSpans.WORKFLOW` — Mastra's own bit for "this workflow is plumbing". */
1180
+ const INTERNAL_WORKFLOW = 1;
1181
+
1182
+ function isInternalRun(run: WorkflowRunLike): boolean {
1183
+ if (run.isInternalWorkflow === true) return true;
1184
+ const internal = run.tracingPolicy?.internal;
1185
+ return typeof internal === "number" && (internal & INTERNAL_WORKFLOW) !== 0;
1186
+ }
1187
+
1188
+ /** A workflow's result status as an `agent_end` outcome. */
1189
+ function workflowOutcome(status: unknown): string {
1190
+ switch (status) {
1191
+ case "success":
1192
+ return "success";
1193
+ case "failed":
1194
+ return "failed";
1195
+ case "canceled":
1196
+ case "cancelled":
1197
+ return "cancelled";
1198
+ case "tripwire":
1199
+ return "rejected";
1200
+ default:
1201
+ return typeof status === "string" && status ? status : "success";
1202
+ }
1203
+ }
1204
+
1205
+ interface WorkflowSpan {
1206
+ tracker: core.RunTracker;
1207
+ key: string;
1208
+ frame: Frame;
1209
+ runId?: string;
1210
+ started: number;
1211
+ }
1212
+
1213
+ /**
1214
+ * The workflows `agent.network()` is built from. 1.x marks them internal
1215
+ * (`tracingPolicy.internal`); 0.x marks them nothing, so inside a network run
1216
+ * they are recognised by id — anywhere else a workflow of that name is the
1217
+ * user's and recorded as usual.
1218
+ */
1219
+ const NETWORK_WORKFLOWS: ReadonlySet<unknown> = new Set([
1220
+ "agent-loop-main-workflow",
1221
+ "Agent-Network-Outer-Workflow",
1222
+ "iteration-with-validation",
1223
+ ]);
1224
+
1225
+ // ---------------------------------------------------------------------------
1226
+ // Suspend / resume (human in the loop)
1227
+ // ---------------------------------------------------------------------------
1228
+
1229
+ /**
1230
+ * A workflow run that suspended and waits to be resumed.
1231
+ *
1232
+ * A suspended run deliberately keeps its agent open, as a LangGraph interrupt
1233
+ * does: closing it would close the pause with it, zeroing the one interval
1234
+ * that measures how long the human took. The resume continues the SAME span.
1235
+ * A resume that lands in another process — the ordinary deployment shape, one
1236
+ * worker suspends and whichever picks up the approval resumes from storage —
1237
+ * finds nothing here, starts a new span in the same session (a root workflow's
1238
+ * session is its run id) and closes the pause by its deterministic id.
1239
+ */
1240
+ interface PausedRun {
1241
+ tracker: core.RunTracker;
1242
+ key: string;
1243
+ started: number;
1244
+ /** Open pause id -> the step path it waits on. */
1245
+ pauses: Map<string, string>;
1246
+ }
1247
+
1248
+ /** Mastra workflow run id -> its paused span. */
1249
+ const pausedRuns = new Map<string, PausedRun>();
1250
+
1251
+ function rememberPaused(runId: string, paused: PausedRun): void {
1252
+ pausedRuns.delete(runId);
1253
+ while (pausedRuns.size >= MAX_OPEN) {
1254
+ const oldest = pausedRuns.entries().next();
1255
+ if (oldest.done) break;
1256
+ pausedRuns.delete(oldest.value[0]);
1257
+ // Never closed from here: the resume may still come, in any process.
1258
+ oldest.value[1].tracker.forget(oldest.value[1].key);
1259
+ }
1260
+ pausedRuns.set(runId, paused);
1261
+ }
1262
+
1263
+ /** A suspend payload or resume answer as the text a human read or wrote. */
1264
+ function humanText(value: unknown): string | undefined {
1265
+ if (value === undefined || value === null) return undefined;
1266
+ if (typeof value === "string") return value;
1267
+ if (typeof value === "object" && !Array.isArray(value)) {
1268
+ const { prompt, question, message } = value as Record<string, unknown>;
1269
+ const text = prompt ?? question ?? message;
1270
+ if (typeof text === "string") return text;
1271
+ }
1272
+ try {
1273
+ return JSON.stringify(value);
1274
+ } catch {
1275
+ return undefined;
1276
+ }
1277
+ }
1278
+
1279
+ /** The steps a `suspended` result waits on: their path, and what each asked. */
1280
+ function suspendedStepsOf(result: unknown): Array<{ path: string; payload: unknown }> {
1281
+ const value = (result ?? {}) as {
1282
+ suspended?: unknown;
1283
+ steps?: Record<string, { status?: unknown; suspendPayload?: unknown } | undefined>;
1284
+ suspendPayload?: Record<string, unknown>;
1285
+ };
1286
+ const payloadOf = (id: string): unknown => value.steps?.[id]?.suspendPayload ?? value.suspendPayload?.[id];
1287
+ const out: Array<{ path: string; payload: unknown }> = [];
1288
+ if (Array.isArray(value.suspended)) {
1289
+ for (const entry of value.suspended) {
1290
+ const ids = (Array.isArray(entry) ? entry : [entry]).filter(
1291
+ (id): id is string => typeof id === "string" && id !== "",
1292
+ );
1293
+ if (ids.length > 0) out.push({ path: ids.join("."), payload: payloadOf(ids[0]!) });
1294
+ }
1295
+ }
1296
+ if (out.length === 0 && typeof value.steps === "object" && value.steps !== null) {
1297
+ for (const [id, step] of Object.entries(value.steps)) {
1298
+ if (step?.status === "suspended") out.push({ path: id, payload: step.suspendPayload });
1299
+ }
1300
+ }
1301
+ return out;
1302
+ }
1303
+
1304
+ /**
1305
+ * The step a `run.resume({ step, resumeData })` resumes, as a path: a step id,
1306
+ * a `Step`, or an array of either for a step inside a nested workflow.
1307
+ */
1308
+ function resumeTargetOf(params: unknown): { path?: string; answer: unknown } {
1309
+ const value = (params ?? {}) as { step?: unknown; resumeData?: unknown };
1310
+ const ids = (Array.isArray(value.step) ? value.step : [value.step])
1311
+ .map((step: unknown) => (typeof step === "string" ? step : (step as { id?: unknown } | null)?.id))
1312
+ .filter((id): id is string => typeof id === "string" && id !== "");
1313
+ return { path: ids.length > 0 ? ids.join(".") : undefined, answer: value.resumeData };
1314
+ }
1315
+
1316
+ const pauseIdOf = (runId: string, path: string): string => `${runId}:${path}`;
1317
+
1318
+ /** `human_wait` + `agent_pause` for each step newly suspended, in that order. */
1319
+ function suspendRun(span: WorkflowSpan, runId: string, result: unknown): void {
1320
+ const existing = pausedRuns.get(runId);
1321
+ const paused: PausedRun =
1322
+ existing !== undefined && existing.key === span.key
1323
+ ? existing
1324
+ : { tracker: span.tracker, key: span.key, started: span.started, pauses: new Map() };
1325
+ for (const { path, payload } of suspendedStepsOf(result)) {
1326
+ const pauseId = pauseIdOf(runId, path);
1327
+ if (paused.pauses.has(pauseId)) continue;
1328
+ paused.pauses.set(pauseId, path);
1329
+ const marker = core.fwFields({ step_id: path, workflow_run_id: runId });
1330
+ span.tracker.emit("humanWait", span.key, {
1331
+ inputId: pauseId,
1332
+ prompt: humanText(payload),
1333
+ reason: "mastra_suspend",
1334
+ ...marker,
1335
+ });
1336
+ span.tracker.emit("agentPause", span.key, { pauseId, reason: "mastra_suspend", ...marker });
1337
+ }
1338
+ rememberPaused(runId, paused);
1339
+ }
1340
+
1341
+ /**
1342
+ * `agent_resume` + `human_input` for the pauses a resume answers: the step it
1343
+ * names (and anything nested under it), or every open pause when it names
1344
+ * none. With no pause open in this process, the one the named step must have
1345
+ * opened elsewhere — the same id, since it is derived from the run and step.
1346
+ */
1347
+ function resumeRun(span: WorkflowSpan, runId: string, params: unknown, paused: PausedRun | undefined): void {
1348
+ const { path, answer } = resumeTargetOf(params);
1349
+ const response = humanText(answer);
1350
+ const emit = (pauseId: string, stepPath: string, elsewhere: boolean): void => {
1351
+ const marker = core.fwFields({
1352
+ step_id: stepPath,
1353
+ workflow_run_id: runId,
1354
+ resumed_elsewhere: elsewhere || undefined,
1355
+ });
1356
+ span.tracker.emit("agentResume", span.key, { pauseId, reason: "mastra_resume", ...marker });
1357
+ span.tracker.emit("humanInput", span.key, { inputId: pauseId, response, ...marker });
1358
+ };
1359
+ if (paused === undefined) {
1360
+ if (path !== undefined) emit(pauseIdOf(runId, path), path, true);
1361
+ return;
1362
+ }
1363
+ for (const [pauseId, stepPath] of [...paused.pauses]) {
1364
+ if (path !== undefined && stepPath !== path && !stepPath.startsWith(`${path}.`)) continue;
1365
+ paused.pauses.delete(pauseId);
1366
+ emit(pauseId, stepPath, false);
1367
+ }
1368
+ }
1369
+
1370
+ function patchRunMethod(prototype: object, method: string): boolean {
1371
+ const original = (prototype as Record<string, unknown>)[method];
1372
+ if (typeof original !== "function" || core.isWrapped(original)) return false;
1373
+ const fn = original as (...args: unknown[]) => unknown;
1374
+ const site = `${NAME}.workflow`;
1375
+ const resuming = method === "_resume";
1376
+
1377
+ const begin = (run: WorkflowRunLike & object, args: unknown[]): WorkflowSpan | undefined => {
1378
+ const t = tracker;
1379
+ if (!enabled || t === null || isInternalRun(run)) return undefined;
1380
+ const parent = frames.getStore();
1381
+ if (parent !== undefined && !live(parent.tracker)) return undefined;
1382
+ if (parent?.kind === "workflow" && parent.owner === run) return undefined;
1383
+ // A network's own machinery (0.x marks it nothing): its agents land on
1384
+ // the network's span.
1385
+ if (parent?.network === true && NETWORK_WORKFLOWS.has(run.workflowId)) return undefined;
1386
+ const runId = typeof run.runId === "string" ? run.runId : undefined;
1387
+
1388
+ const paused = resuming && runId !== undefined ? pausedRuns.get(runId) : undefined;
1389
+ if (paused !== undefined && paused.tracker === t && t.isOpen(paused.key)) {
1390
+ // Resuming a run this process suspended: the same span, continued.
1391
+ const span: WorkflowSpan = {
1392
+ tracker: t,
1393
+ key: paused.key,
1394
+ frame: { tracker: t, key: paused.key, owner: run, kind: "workflow" },
1395
+ runId,
1396
+ started: paused.started,
1397
+ };
1398
+ workflowRuns.set(runId!, paused.key);
1399
+ resumeRun(span, runId!, args[0], paused);
1400
+ return span;
1401
+ }
1402
+
1403
+ const key = randomUUID();
1404
+ t.startAgent(key, {
1405
+ agentId: core.normalizeAgentId(run.workflowId, "workflow"),
1406
+ parentKey: parent?.key,
1407
+ // A root run's session is its run id — the one thing its resume, in
1408
+ // this process or another, is sure to share with it.
1409
+ sessionId: isUnscopedRoot(parent) ? runId : undefined,
1410
+ ...core.fwFields({ kind: "workflow", workflow_run_id: runId, method: method.replace(/^_/, "") }),
1411
+ });
1412
+ const span: WorkflowSpan = {
1413
+ tracker: t,
1414
+ key,
1415
+ frame: { tracker: t, key, owner: run, kind: "workflow" },
1416
+ runId,
1417
+ started: Date.now(),
1418
+ };
1419
+ if (runId !== undefined) {
1420
+ workflowRuns.set(runId, key);
1421
+ if (resuming) resumeRun(span, runId, args[0], undefined);
1422
+ }
1423
+ return span;
1424
+ };
1425
+ const end = (span: WorkflowSpan, value: unknown, failed = false): void => {
1426
+ if (span.runId !== undefined && workflowRuns.get(span.runId) === span.key) workflowRuns.delete(span.runId);
1427
+ // Closed `cancelled` already, by the teardown that made it not live.
1428
+ if (!live(span.tracker)) return;
1429
+ const status = failed ? "failed" : (value as { status?: unknown } | null)?.status;
1430
+ if (status === "suspended" && span.runId !== undefined) {
1431
+ suspendRun(span, span.runId, value);
1432
+ return;
1433
+ }
1434
+ if (span.runId !== undefined && pausedRuns.get(span.runId)?.key === span.key) pausedRuns.delete(span.runId);
1435
+ span.tracker.endAgent(span.key, {
1436
+ outcome: workflowOutcome(status),
1437
+ ...core.fwFields({ duration_ms: core.ms(Date.now() - span.started) }),
1438
+ });
1439
+ };
1440
+
1441
+ const wrapper = function failproofaiWorkflowRun(this: WorkflowRunLike & object, ...args: unknown[]): unknown {
1442
+ const span = core.callSafely(begin, [this, args], site);
1443
+ if (!span) return fn.apply(this, args);
1444
+ let result: unknown;
1445
+ try {
1446
+ result = frames.run(span.frame, () => fn.apply(this, args));
1447
+ } catch (error) {
1448
+ core.callSafely(end, [span, undefined, true], site);
1449
+ throw error;
1450
+ }
1451
+ if (typeof (result as PromiseLike<unknown> | null)?.then === "function") {
1452
+ return (result as PromiseLike<unknown>).then(
1453
+ (value) => {
1454
+ core.callSafely(end, [span, value], site);
1455
+ return value;
1456
+ },
1457
+ (error: unknown) => {
1458
+ core.callSafely(end, [span, undefined, true], site);
1459
+ throw error;
1460
+ },
1461
+ );
1462
+ }
1463
+ core.callSafely(end, [span, result], site);
1464
+ return result;
1465
+ };
1466
+ Object.defineProperty(wrapper, "name", { value: fn.name, configurable: true });
1467
+ return patcher!.patch(prototype, method, markWrapped(wrapper, original));
1468
+ }
1469
+
1470
+ let stepSequence = 0;
1471
+
1472
+ interface StepSpan extends Span {
1473
+ runKey: string;
1474
+ hookName: string;
1475
+ hookId: string;
1476
+ }
1477
+
1478
+ const openSteps = new OpenSpans<StepSpan>();
1479
+
1480
+ function beginStep(params: unknown): StepSpan | undefined {
1481
+ const t = tracker;
1482
+ if (!enabled || t === null) return undefined;
1483
+ const value = (params ?? {}) as {
1484
+ step?: { id?: unknown };
1485
+ runId?: unknown;
1486
+ executionContext?: { runId?: unknown };
1487
+ prevOutput?: unknown;
1488
+ };
1489
+ const runId = value.executionContext?.runId ?? value.runId;
1490
+ const runKey = typeof runId === "string" ? workflowRuns.get(runId) : undefined;
1491
+ const hookName = value.step?.id;
1492
+ if (runKey === undefined || typeof hookName !== "string" || !hookName) return undefined;
1493
+ // Only a step of the recorded run ITSELF. An agent that runs inside it
1494
+ // executes its own loop as internal workflows, and one called with the
1495
+ // run's id — as 0.x's network calls its sub-agents — hands those internal
1496
+ // steps the same run id; they execute in the agent's frame, not the run's.
1497
+ const frame = frames.getStore();
1498
+ if (frame?.kind !== "workflow" || frame.key !== runKey) return undefined;
1499
+ stepSequence += 1;
1500
+ const hookId = `${runKey}:${hookName}:${stepSequence}`;
1501
+ t.emit("hookTriggered", runKey, {
1502
+ hookName,
1503
+ hookId,
1504
+ triggerEvent: "workflow_step",
1505
+ input: value.prevOutput,
1506
+ });
1507
+ const span: StepSpan = { tracker: t, closed: false, runKey, hookName, hookId };
1508
+ openSteps.add(span);
1509
+ return span;
1510
+ }
1511
+
1512
+ interface StepResult {
1513
+ status?: unknown;
1514
+ output?: unknown;
1515
+ error?: unknown;
1516
+ }
1517
+
1518
+ /**
1519
+ * The step result inside what `executeStep` resolved with: `{ result: {…} }`
1520
+ * from 0.24 on, the bare `{ status, output, error }` before that.
1521
+ */
1522
+ function stepResultOf(value: unknown): StepResult {
1523
+ if (typeof value !== "object" || value === null) return {};
1524
+ const wrapped = (value as { result?: unknown }).result;
1525
+ if (typeof wrapped === "object" && wrapped !== null && "status" in wrapped) return wrapped;
1526
+ return value;
1527
+ }
1528
+
1529
+ /**
1530
+ * A failed step does not throw out of `executeStep` — Mastra catches it and
1531
+ * resolves with `status: "failed"` — so the failure is read off the result.
1532
+ * 0.x hands the error over as a rendered string with its stack attached; only
1533
+ * the first line is the error.
1534
+ */
1535
+ function stepOutcome(value: unknown, thrown?: unknown): { outcome: string; output?: unknown; error?: string } {
1536
+ const result = stepResultOf(value);
1537
+ const error = thrown ?? (result.status === "failed" ? (result.error ?? "step failed") : undefined);
1538
+ if (error !== undefined) {
1539
+ return { outcome: "failed", error: typeof error === "string" ? error.split("\n")[0] : describeError(error) };
1540
+ }
1541
+ return {
1542
+ outcome: typeof result.status === "string" && result.status ? workflowOutcome(result.status) : "success",
1543
+ output: result.output,
1544
+ };
1545
+ }
1546
+
1547
+ function endStep(span: StepSpan, value: unknown, thrown?: unknown): void {
1548
+ // Already closed — by teardown, when its installation is gone.
1549
+ if (!openSteps.close(span)) return;
1550
+ span.tracker.emit("hookCompleted", span.runKey, {
1551
+ hookName: span.hookName,
1552
+ hookId: span.hookId,
1553
+ ...stepOutcome(value, thrown),
1554
+ });
1555
+ }
1556
+
1557
+ function patchExecuteStep(prototype: object): boolean {
1558
+ const original = (prototype as Record<string, unknown>).executeStep;
1559
+ if (typeof original !== "function" || core.isWrapped(original)) return false;
1560
+ const fn = original as (...args: unknown[]) => unknown;
1561
+ const site = `${NAME}.step`;
1562
+ const wrapper = function failproofaiStep(this: unknown, ...args: unknown[]): unknown {
1563
+ const span = core.callSafely(beginStep, [args[0]], site);
1564
+ if (!span) return fn.apply(this, args);
1565
+ let result: unknown;
1566
+ try {
1567
+ result = fn.apply(this, args);
1568
+ } catch (error) {
1569
+ core.callSafely(endStep, [span, undefined, error], site);
1570
+ throw error;
1571
+ }
1572
+ if (typeof (result as PromiseLike<unknown> | null)?.then === "function") {
1573
+ return (result as PromiseLike<unknown>).then(
1574
+ (value) => {
1575
+ core.callSafely(endStep, [span, value], site);
1576
+ return value;
1577
+ },
1578
+ (error: unknown) => {
1579
+ core.callSafely(endStep, [span, undefined, error], site);
1580
+ throw error;
1581
+ },
1582
+ );
1583
+ }
1584
+ core.callSafely(endStep, [span, result], site);
1585
+ return result;
1586
+ };
1587
+ Object.defineProperty(wrapper, "name", { value: fn.name, configurable: true });
1588
+ return patcher!.patch(prototype, "executeStep", markWrapped(wrapper, original));
1589
+ }
1590
+
1591
+ /**
1592
+ * Run `body` inside an agent span named for a workflow.
1593
+ *
1594
+ * Mastra workflow runs are recorded automatically once `instrument("mastra")`
1595
+ * has run — the run as an agent, its steps as hooks — so this is not needed
1596
+ * for them. It stays for grouping work that is not a Mastra workflow (or runs
1597
+ * where the adapter is not installed) under one named span.
1598
+ */
1599
+ export function workflow<T>(workflowName: string, body: () => T): T {
1600
+ return agentScope(core.normalizeAgentId(workflowName, "workflow"), { fw_kind: "workflow" }, body);
1601
+ }
1602
+
1603
+ // ---------------------------------------------------------------------------
1604
+ // Install
1605
+ // ---------------------------------------------------------------------------
1606
+
1607
+ type ClassLike = { prototype: object };
1608
+
1609
+ const AGENT_METHODS = [
1610
+ ["generate", "generate"],
1611
+ ["stream", "stream"],
1612
+ ["generateVNext", "generate"],
1613
+ ["streamVNext", "stream"],
1614
+ ["generateLegacy", "generate"],
1615
+ ["streamLegacy", "stream"],
1616
+ ["network", "network"],
1617
+ ] as const;
1618
+
1619
+ function installAgent(Agent: ClassLike): number {
1620
+ let patched = 0;
1621
+ for (const [method, mode] of AGENT_METHODS) {
1622
+ if (patchAgentMethod(Agent.prototype, method, mode)) patched += 1;
1623
+ }
1624
+ const proto = Agent.prototype as Record<string, unknown>;
1625
+ if (compat.probe(NAME, "Agent.resolveModelConfig", () => typeof proto.resolveModelConfig === "function")) {
1626
+ patchBuilder(Agent.prototype, "resolveModelConfig", (model, frame) => observeModel(model, frame));
1627
+ }
1628
+ if (compat.probe(NAME, "Agent.convertTools", () => typeof proto.convertTools === "function")) {
1629
+ patchBuilder(Agent.prototype, "convertTools", (tools, frame, agent) => observeTools(tools, frame, agent));
1630
+ }
1631
+ // Optional, and silent when absent: without it a blocked stream is closed
1632
+ // by its finish (1.x) or at teardown (0.x), rather than never recorded.
1633
+ patchInputProcessors(Agent.prototype);
1634
+ return patched;
1635
+ }
1636
+
1637
+ function installWorkflows(module: unknown): void {
1638
+ const { Run, DefaultExecutionEngine } = (module ?? {}) as {
1639
+ Run?: ClassLike;
1640
+ DefaultExecutionEngine?: ClassLike;
1641
+ };
1642
+ if (compat.probe(NAME, "workflows Run._start", () => typeof (Run?.prototype as Record<string, unknown> | undefined)?._start === "function")) {
1643
+ for (const method of ["_start", "_resume", "_restart", "_timeTravel"]) patchRunMethod(Run!.prototype, method);
1644
+ }
1645
+ if (
1646
+ compat.probe(
1647
+ NAME,
1648
+ "workflows DefaultExecutionEngine.executeStep",
1649
+ () => typeof (DefaultExecutionEngine?.prototype as Record<string, unknown> | undefined)?.executeStep === "function",
1650
+ )
1651
+ ) {
1652
+ patchExecuteStep(DefaultExecutionEngine!.prototype);
1653
+ }
1654
+ }
1655
+
1656
+ export const adapter: Adapter = {
1657
+ name: NAME,
1658
+
1659
+ async install(options: Record<string, unknown> = {}): Promise<void> {
1660
+ compat.checkVersion(NAME, PACKAGE, {
1661
+ minimum: MINIMUM,
1662
+ below: "2.0.0",
1663
+ reason: "model steps are observed at resolveModelConfig and workflow runs at Run._start",
1664
+ });
1665
+ const agentCopies = await compat.requireModuleCopies("@mastra/core/agent", INSTALL);
1666
+ // Workflows are optional: an app with no workflows is ordinary, and a
1667
+ // workflow module that fails to load must not cost the agent patches below.
1668
+ const workflowCopies = await compat
1669
+ .requireModuleCopies("@mastra/core/workflows", INSTALL)
1670
+ .catch(() => [] as unknown[]);
1671
+
1672
+ // A fresh tracker per installation, never one left over: whatever an
1673
+ // earlier installation built stays bound to ITS tracker, which is dead.
1674
+ teardown();
1675
+ tracker = newTracker(options);
1676
+ patcher = new core.Patcher();
1677
+
1678
+ let patched = 0;
1679
+ for (const copy of agentCopies) {
1680
+ const Agent = (copy as { Agent?: unknown }).Agent;
1681
+ if (typeof Agent === "function") patched += installAgent(Agent);
1682
+ }
1683
+ if (patched === 0) {
1684
+ teardown();
1685
+ throw new Error(
1686
+ "could not patch any Agent generate/stream method — this build of @mastra/core " +
1687
+ "exposes none of them under a writable name.",
1688
+ );
1689
+ }
1690
+ for (const copy of workflowCopies) installWorkflows(copy);
1691
+ enabled = true;
1692
+ },
1693
+
1694
+ uninstall(): void {
1695
+ teardown();
1696
+ },
1697
+ };
1698
+
1699
+ /**
1700
+ * Stop recording and close what is still open, on the tracker it opened on.
1701
+ * The switch goes FIRST: nothing may begin a span while the rest are closed.
1702
+ */
1703
+ function teardown(): void {
1704
+ enabled = false;
1705
+ patcher?.restoreAll();
1706
+ patcher = null;
1707
+ workflowRuns.clear();
1708
+ pausedRuns.clear();
1709
+ const t = tracker;
1710
+ tracker = null;
1711
+ const models = openModels.drain();
1712
+ const tools = openTools.drain();
1713
+ const steps = openSteps.drain();
1714
+ if (t === null) return;
1715
+ const site = `${NAME}.uninstall`;
1716
+ const incomplete = core.fwFields({ incomplete: true });
1717
+ // Innermost first — a step's model calls and tools before the step — and
1718
+ // every leaf before the agents that own it.
1719
+ for (const call of models) {
1720
+ if (call.tracker !== t) continue;
1721
+ core.callSafely(
1722
+ () =>
1723
+ t.emit("modelResponse", call.requestId, {
1724
+ parentKey: call.runKey,
1725
+ model: call.model,
1726
+ stopReason: "incomplete", // the LangChain adapter's word for a model call cut off mid-flight
1727
+ requestId: call.requestId,
1728
+ ...core.fwFields({ duration_ms: core.ms(Date.now() - call.started), incomplete: true }),
1729
+ }),
1730
+ [],
1731
+ site,
1732
+ );
1733
+ }
1734
+ for (const call of tools) {
1735
+ if (call.tracker !== t) continue;
1736
+ core.callSafely(
1737
+ () =>
1738
+ t.emit("toolResult", call.key, {
1739
+ parentKey: call.parentKey,
1740
+ toolName: call.toolName,
1741
+ toolCallId: call.toolCallId,
1742
+ ...incomplete,
1743
+ }),
1744
+ [],
1745
+ site,
1746
+ );
1747
+ }
1748
+ for (const span of steps) {
1749
+ if (span.tracker !== t) continue;
1750
+ core.callSafely(
1751
+ () =>
1752
+ t.emit("hookCompleted", span.runKey, {
1753
+ hookName: span.hookName,
1754
+ hookId: span.hookId,
1755
+ outcome: "cancelled",
1756
+ ...incomplete,
1757
+ }),
1758
+ [],
1759
+ site,
1760
+ );
1761
+ }
1762
+ core.callSafely(() => t.closeOpenAgents("cancelled"), [], site);
1763
+ t.reset();
1764
+ }
1765
+
1766
+ /**
1767
+ * The pure readers above and two lifecycle probes, for this package's own
1768
+ * unit tests.
1769
+ *
1770
+ * @internal Not part of the public API — `stripInternal` drops it from the
1771
+ * published declarations: their shapes follow Mastra's and the providers' internals, and
1772
+ * change whenever those do. Nothing exported references it.
1773
+ */
1774
+ export const _internals = {
1775
+ /** Whether an installation is live. */
1776
+ isEnabled: (): boolean => enabled,
1777
+ /** How many suspended workflow runs are waiting on a resume. */
1778
+ pausedRuns: (): number => pausedRuns.size,
1779
+ /** How many spans of each kind are open, for the bookkeeping tests. */
1780
+ openSpans: (): Record<string, number> => ({
1781
+ models: openModels.size,
1782
+ tools: openTools.size,
1783
+ steps: openSteps.size,
1784
+ workflowRuns: workflowRuns.size,
1785
+ agents: tracker?.openAgents().length ?? 0,
1786
+ }),
1787
+ usageOf,
1788
+ finishReasonOf,
1789
+ promptOf,
1790
+ generateOutcome,
1791
+ foldStreamPart,
1792
+ toolCallArgs,
1793
+ isInternalRun,
1794
+ workflowOutcome,
1795
+ stepResultOf,
1796
+ stepOutcome,
1797
+ conversationOf,
1798
+ isRoutingAgent,
1799
+ suspendedStepsOf,
1800
+ resumeTargetOf,
1801
+ humanText,
1802
+ };