failproofai 1.0.7-beta.1 → 1.0.7

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 (429) 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 +4 -4
  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 +4 -4
  7. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  8. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  11. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
  12. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  13. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  15. package/.next/standalone/.next/server/app/_not-found/page.js +4 -4
  16. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  17. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  18. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  19. package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
  20. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
  21. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +14 -14
  22. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  23. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  24. package/.next/standalone/.next/server/app/api/audit/run/route.js +7 -8
  25. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  33. package/.next/standalone/.next/server/app/audit/page.js +5 -7
  34. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  36. package/.next/standalone/.next/server/app/index.html +1 -1
  37. package/.next/standalone/.next/server/app/index.rsc +15 -15
  38. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +14 -14
  39. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
  40. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  41. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  42. package/.next/standalone/.next/server/app/page.js +6 -6
  43. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  45. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
  46. package/.next/standalone/.next/server/app/policies/page.js +11 -13
  47. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  48. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  49. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  50. package/.next/standalone/.next/server/app/project/[name]/page.js +7 -8
  51. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  52. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  53. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  54. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  55. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +7 -7
  56. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  57. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  58. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  59. package/.next/standalone/.next/server/app/projects/page.js +6 -7
  60. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  61. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  62. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +8 -41
  63. package/.next/standalone/.next/server/app/settings/page.js +9 -12
  64. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  65. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  66. package/.next/standalone/.next/server/chunks/{[externals]__1j-zsg5._.js → [externals]__1_bftcl._.js} +1 -1
  67. package/.next/standalone/.next/server/chunks/{[externals]__19_pzeq._.js → [externals]__1msfs-h._.js} +1 -1
  68. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
  69. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1bf34x4._.js → [root-of-the-server]__1_r2rbg._.js} +7 -5
  70. package/.next/standalone/.next/server/chunks/_09dz7xv._.js +21 -21
  71. package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
  72. package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
  73. package/.next/standalone/.next/server/chunks/{_1q5i8mb._.js → _1c3k-8x._.js} +2 -2
  74. package/.next/standalone/.next/server/chunks/_1ek68ln._.js +16 -16
  75. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_09z9-p7._.js +1 -1
  76. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  77. package/.next/standalone/.next/server/chunks/src_hooks_0iu54mz._.js +3 -0
  78. package/.next/standalone/.next/server/chunks/src_hooks_custom-hooks-loader_ts_0lnb3n3._.js +2 -4
  79. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0-_ki57._.js +4 -0
  80. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__013jr2b._.js +4 -0
  81. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01wy8d-._.js +4 -0
  82. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02npjtd._.js +4 -0
  83. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0yxwl6j._.js → [root-of-the-server]__0bd3mje._.js} +2 -2
  84. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0cg-bgc._.js +5 -0
  85. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0cpu_mj._.js +3 -0
  86. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1mf3zp6._.js → [root-of-the-server]__0cxe_2_._.js} +3 -3
  87. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0da85px._.js +4 -0
  88. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ftmoxc._.js +4 -0
  89. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0p-5p8u._.js +4 -0
  90. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0u3w0ll._.js +22 -0
  91. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__17d_ffl._.js +3 -0
  92. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__19d9tgz._.js +5 -0
  93. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ctpynv._.js +3 -0
  94. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1jiwfsj._.js +3 -0
  95. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1p2otjt._.js +4 -0
  96. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1phc187._.js +3 -0
  97. package/.next/standalone/.next/server/chunks/ssr/_06imw3p._.js +5 -0
  98. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  99. package/.next/standalone/.next/server/chunks/ssr/{_1w_5l7t._.js → _0h_douw._.js} +1 -1
  100. package/.next/standalone/.next/server/chunks/ssr/{_214wgrp._.js → _1-i_gzc._.js} +2 -2
  101. package/.next/standalone/.next/server/chunks/ssr/{_0bn2oo8._.js → _166t73i._.js} +1 -1
  102. package/.next/standalone/.next/server/chunks/ssr/{_1q46vxx._.js → _1_qswah._.js} +2 -2
  103. package/.next/standalone/.next/server/chunks/ssr/{_1gb0ifp._.js → _1es2j7i._.js} +5 -5
  104. package/.next/standalone/.next/server/chunks/ssr/_1u8-lu2._.js +3 -0
  105. package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +1 -1
  106. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +2 -2
  107. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
  108. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  109. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +2 -2
  110. package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +3 -0
  111. package/.next/standalone/.next/server/chunks/ssr/{node_modules_next_dist_18_d8l1._.js → node_modules_next_dist_0drixxt._.js} +4 -4
  112. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1cv9_c4._.js +10 -0
  113. package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +1 -1
  114. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-home_ts_0je3xkv._.js +1 -1
  115. package/.next/standalone/.next/server/chunks/ssr/src_hooks_pack-cli_ts_0t7me65._.js +1 -1
  116. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  117. package/.next/standalone/.next/server/pages/404.html +1 -1
  118. package/.next/standalone/.next/server/pages/500.html +1 -1
  119. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  120. package/.next/standalone/.next/server/server-reference-manifest.json +23 -56
  121. package/.next/standalone/.next/static/chunks/094xgi4owxaqf.js +1 -0
  122. package/.next/standalone/.next/static/chunks/0__8a7m868fvf.js +1 -0
  123. package/.next/standalone/.next/static/chunks/{12tvm75t5ffui.js → 0o6qlkgubtoex.js} +1 -1
  124. package/.next/standalone/.next/static/chunks/13i7-9is-vhys.js +1 -0
  125. package/.next/standalone/.next/static/chunks/1rz20_pz828f3.js +6 -0
  126. package/.next/standalone/.next/static/chunks/2k9f4tyv04809.css +1 -0
  127. package/.next/standalone/.next/static/chunks/{0vmd180qfntfb.js → 2klitrtzpaoe0.js} +1 -1
  128. package/.next/standalone/.next/static/chunks/{258668t68du6b.js → 2mdh397ghgnvv.js} +1 -1
  129. package/.next/standalone/.next/static/chunks/2rshywgeqsyzk.css +2 -0
  130. package/.next/standalone/.next/static/chunks/3pzx4chkhko9k.js +1 -0
  131. package/.next/standalone/.next/static/chunks/{0qrbdkv9qmvli.js → 3rh5o7e16irrm.js} +1 -1
  132. package/.next/standalone/.next/static/chunks/{29fql3nbnfc9q.js → 43ufqrz8qo3h-.js} +1 -1
  133. package/.next/standalone/SECURITY.md +53 -0
  134. package/.next/standalone/app/actions/pack-actions.ts +0 -12
  135. package/.next/standalone/app/policies/hooks-client.tsx +0 -9
  136. package/.next/standalone/app/settings/page.tsx +1 -20
  137. package/.next/standalone/app/settings/settings-client.tsx +1 -27
  138. package/.next/standalone/app/settings/settings.css +0 -79
  139. package/.next/standalone/package.json +9 -9
  140. package/.next/standalone/sdk/python/skill/SKILL.md +60 -14
  141. package/.next/standalone/sdk/python/skill/agents/openai.yaml +2 -1
  142. package/.next/standalone/sdk/python/skill/references/evaluator.md +255 -0
  143. package/.next/standalone/sdk/python/skill/references/events.md +17 -8
  144. package/.next/standalone/sdk/python/skill/references/frameworks.md +3 -0
  145. package/.next/standalone/sdk/python/skill/references/install.md +3 -0
  146. package/.next/standalone/sdk/python/skill/references/integration.md +6 -2
  147. package/.next/standalone/sdk/python/skill/references/typescript.md +568 -0
  148. package/.next/standalone/sdk/typescript/CHANGELOG.md +133 -0
  149. package/.next/standalone/sdk/typescript/LICENSE +42 -0
  150. package/.next/standalone/sdk/typescript/README.md +552 -0
  151. package/.next/standalone/sdk/typescript/eslint.config.mjs +59 -0
  152. package/.next/standalone/sdk/typescript/examples/research-agent.ts +197 -0
  153. package/.next/standalone/sdk/typescript/integration/ai.test.ts +920 -0
  154. package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/agent.ts +337 -0
  155. package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/package-lock.json +261 -0
  156. package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/package.json +16 -0
  157. package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/surfaces.ts +605 -0
  158. package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/tsconfig.json +12 -0
  159. package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/tsconfig.surfaces.json +4 -0
  160. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/agent.ts +342 -0
  161. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/package-lock.json +156 -0
  162. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/package.json +16 -0
  163. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/surfaces.ts +628 -0
  164. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/tsconfig.json +12 -0
  165. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/tsconfig.surfaces.json +4 -0
  166. package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/agent.ts +346 -0
  167. package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/package-lock.json +156 -0
  168. package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/package.json +13 -0
  169. package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/surfaces.ts +651 -0
  170. package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/tsconfig.json +12 -0
  171. package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/tsconfig.surfaces.json +4 -0
  172. package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/agent.ts +350 -0
  173. package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/package-lock.json +153 -0
  174. package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/package.json +13 -0
  175. package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/surfaces.ts +651 -0
  176. package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/tsconfig.json +12 -0
  177. package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/tsconfig.surfaces.json +4 -0
  178. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-0.3/agent.ts +623 -0
  179. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-0.3/package-lock.json +344 -0
  180. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-0.3/package.json +19 -0
  181. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-0.3/tsconfig.json +12 -0
  182. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/agent-v1.ts +99 -0
  183. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/agent.ts +623 -0
  184. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/package-lock.json +336 -0
  185. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/package.json +15 -0
  186. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/tsconfig.json +12 -0
  187. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/agent.ts +96 -0
  188. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/package-lock.json +441 -0
  189. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/package.json +19 -0
  190. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/tsconfig.json +12 -0
  191. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/vendor/lc-weather-provider/index.cjs +53 -0
  192. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/vendor/lc-weather-provider/index.mjs +55 -0
  193. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/vendor/lc-weather-provider/package.json +18 -0
  194. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/agent.ts +659 -0
  195. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/package-lock.json +635 -0
  196. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/package.json +15 -0
  197. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/tsconfig.json +12 -0
  198. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/agent.ts +659 -0
  199. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/package-lock.json +553 -0
  200. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/package.json +15 -0
  201. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/tsconfig.json +12 -0
  202. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/agent.ts +877 -0
  203. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/mcp-server.mjs +66 -0
  204. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/package-lock.json +6797 -0
  205. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/package.json +24 -0
  206. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/tsconfig.json +12 -0
  207. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/agent.ts +872 -0
  208. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/mcp-server.mjs +66 -0
  209. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/package-lock.json +2540 -0
  210. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/package.json +15 -0
  211. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/tsconfig.json +12 -0
  212. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/actions.ts +18 -0
  213. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/ai/route.ts +42 -0
  214. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/edge/route.ts +29 -0
  215. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/langgraph/route.ts +21 -0
  216. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/llamaindex/route.ts +11 -0
  217. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/mastra/route.ts +19 -0
  218. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/status/route.ts +7 -0
  219. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/layout.tsx +9 -0
  220. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/page.tsx +15 -0
  221. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/instrumentation.ts +15 -0
  222. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/lib/ai.ts +61 -0
  223. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/lib/langgraph.ts +68 -0
  224. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/lib/llamaindex.ts +98 -0
  225. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/lib/mastra.ts +90 -0
  226. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/next.config.ts +52 -0
  227. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package-lock.json +4343 -0
  228. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package.json +28 -0
  229. package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/agent.ts +51 -0
  230. package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/deno-npm.ts +76 -0
  231. package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/package-lock.json +484 -0
  232. package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/package.json +15 -0
  233. package/.next/standalone/sdk/typescript/integration/fixtures/types/agent.ts +79 -0
  234. package/.next/standalone/sdk/typescript/integration/fixtures/types/package-lock.json +740 -0
  235. package/.next/standalone/sdk/typescript/integration/fixtures/types/package.json +11 -0
  236. package/.next/standalone/sdk/typescript/integration/fixtures/vanilla/agent.ts +197 -0
  237. package/.next/standalone/sdk/typescript/integration/fixtures/vanilla/package-lock.json +70 -0
  238. package/.next/standalone/sdk/typescript/integration/fixtures/vanilla/package.json +12 -0
  239. package/.next/standalone/sdk/typescript/integration/fixtures/vanilla/tsconfig.json +12 -0
  240. package/.next/standalone/sdk/typescript/integration/global-setup.ts +29 -0
  241. package/.next/standalone/sdk/typescript/integration/harness.ts +451 -0
  242. package/.next/standalone/sdk/typescript/integration/langchain.test.ts +682 -0
  243. package/.next/standalone/sdk/typescript/integration/llamaindex.test.ts +709 -0
  244. package/.next/standalone/sdk/typescript/integration/mastra-coverage.test.ts +386 -0
  245. package/.next/standalone/sdk/typescript/integration/mastra.test.ts +311 -0
  246. package/.next/standalone/sdk/typescript/integration/nextjs.test.ts +341 -0
  247. package/.next/standalone/sdk/typescript/integration/runtime-parity.ts +180 -0
  248. package/.next/standalone/sdk/typescript/integration/runtimes.bun.test.ts +15 -0
  249. package/.next/standalone/sdk/typescript/integration/runtimes.core.test.ts +113 -0
  250. package/.next/standalone/sdk/typescript/integration/runtimes.deno.test.ts +19 -0
  251. package/.next/standalone/sdk/typescript/integration/types.test.ts +141 -0
  252. package/.next/standalone/sdk/typescript/integration/vanilla.test.ts +255 -0
  253. package/.next/standalone/sdk/typescript/package-lock.json +2640 -0
  254. package/.next/standalone/sdk/typescript/package.json +401 -0
  255. package/.next/standalone/sdk/typescript/scripts/finalize-build.mjs +123 -0
  256. package/.next/standalone/sdk/typescript/scripts/release.mjs +177 -0
  257. package/.next/standalone/sdk/typescript/src/clock.ts +58 -0
  258. package/.next/standalone/sdk/typescript/src/context.ts +214 -0
  259. package/.next/standalone/sdk/typescript/src/edge/adapter.ts +18 -0
  260. package/.next/standalone/sdk/typescript/src/edge/ai.ts +116 -0
  261. package/.next/standalone/sdk/typescript/src/edge/index.ts +238 -0
  262. package/.next/standalone/sdk/typescript/src/edge/langchain.ts +18 -0
  263. package/.next/standalone/sdk/typescript/src/edge/llamaindex.ts +12 -0
  264. package/.next/standalone/sdk/typescript/src/edge/mastra.ts +17 -0
  265. package/.next/standalone/sdk/typescript/src/edge/notice.ts +33 -0
  266. package/.next/standalone/sdk/typescript/src/environment.ts +75 -0
  267. package/.next/standalone/sdk/typescript/src/evaluator/authoring.ts +480 -0
  268. package/.next/standalone/sdk/typescript/src/evaluator/cli.ts +96 -0
  269. package/.next/standalone/sdk/typescript/src/evaluator/client.ts +421 -0
  270. package/.next/standalone/sdk/typescript/src/evaluator/expression.ts +1292 -0
  271. package/.next/standalone/sdk/typescript/src/evaluator/index.ts +144 -0
  272. package/.next/standalone/sdk/typescript/src/evaluator/protocol.ts +747 -0
  273. package/.next/standalone/sdk/typescript/src/evaluator/runtime.ts +930 -0
  274. package/.next/standalone/sdk/typescript/src/evaluator/sandbox-worker.ts +171 -0
  275. package/.next/standalone/sdk/typescript/src/evaluator/source-limits.ts +27 -0
  276. package/.next/standalone/sdk/typescript/src/evaluator/source.ts +509 -0
  277. package/.next/standalone/sdk/typescript/src/events.ts +879 -0
  278. package/.next/standalone/sdk/typescript/src/exit.ts +117 -0
  279. package/.next/standalone/sdk/typescript/src/index.ts +186 -0
  280. package/.next/standalone/sdk/typescript/src/integrations/ai.ts +1566 -0
  281. package/.next/standalone/sdk/typescript/src/integrations/compat.ts +322 -0
  282. package/.next/standalone/sdk/typescript/src/integrations/core.ts +1321 -0
  283. package/.next/standalone/sdk/typescript/src/integrations/index.ts +355 -0
  284. package/.next/standalone/sdk/typescript/src/integrations/langchain.ts +2340 -0
  285. package/.next/standalone/sdk/typescript/src/integrations/llamaindex.ts +2111 -0
  286. package/.next/standalone/sdk/typescript/src/integrations/mastra.ts +1802 -0
  287. package/.next/standalone/sdk/typescript/src/logger.ts +98 -0
  288. package/.next/standalone/sdk/typescript/src/next.ts +115 -0
  289. package/.next/standalone/sdk/typescript/src/node-require.ts +446 -0
  290. package/.next/standalone/sdk/typescript/src/redact.ts +305 -0
  291. package/.next/standalone/sdk/typescript/src/resolver.ts +120 -0
  292. package/.next/standalone/sdk/typescript/src/runtime.ts +29 -0
  293. package/.next/standalone/sdk/typescript/src/schema.ts +410 -0
  294. package/.next/standalone/sdk/typescript/src/scopes.ts +701 -0
  295. package/.next/standalone/sdk/typescript/src/shared.ts +33 -0
  296. package/.next/standalone/sdk/typescript/src/version.ts +5 -0
  297. package/.next/standalone/sdk/typescript/src/writer.ts +934 -0
  298. package/.next/standalone/sdk/typescript/test/adapters.test.ts +397 -0
  299. package/.next/standalone/sdk/typescript/test/ai.test.ts +1076 -0
  300. package/.next/standalone/sdk/typescript/test/copies.test.ts +204 -0
  301. package/.next/standalone/sdk/typescript/test/edge.test.ts +183 -0
  302. package/.next/standalone/sdk/typescript/test/evaluator-client.test.ts +234 -0
  303. package/.next/standalone/sdk/typescript/test/evaluator-protocol.test.ts +225 -0
  304. package/.next/standalone/sdk/typescript/test/events.test.ts +193 -0
  305. package/.next/standalone/sdk/typescript/test/expression.test.ts +181 -0
  306. package/.next/standalone/sdk/typescript/test/global-setup.ts +26 -0
  307. package/.next/standalone/sdk/typescript/test/helpers.ts +130 -0
  308. package/.next/standalone/sdk/typescript/test/integrations.test.ts +369 -0
  309. package/.next/standalone/sdk/typescript/test/langchain-copies.test.ts +204 -0
  310. package/.next/standalone/sdk/typescript/test/langchain.test.ts +999 -0
  311. package/.next/standalone/sdk/typescript/test/llamaindex.test.ts +1760 -0
  312. package/.next/standalone/sdk/typescript/test/mastra-coverage.test.ts +501 -0
  313. package/.next/standalone/sdk/typescript/test/mastra-lifecycle.test.ts +479 -0
  314. package/.next/standalone/sdk/typescript/test/mastra.test.ts +285 -0
  315. package/.next/standalone/sdk/typescript/test/next.test.ts +109 -0
  316. package/.next/standalone/sdk/typescript/test/packaging.test.ts +312 -0
  317. package/.next/standalone/sdk/typescript/test/redaction.test.ts +171 -0
  318. package/.next/standalone/sdk/typescript/test/runtimes.test.ts +101 -0
  319. package/.next/standalone/sdk/typescript/test/sandbox.test.ts +189 -0
  320. package/.next/standalone/sdk/typescript/test/scopes.test.ts +271 -0
  321. package/.next/standalone/sdk/typescript/test/setup.ts +19 -0
  322. package/.next/standalone/sdk/typescript/test/skill-snippets.test.ts +73 -0
  323. package/.next/standalone/sdk/typescript/test/spool-contract.test.ts +124 -0
  324. package/.next/standalone/sdk/typescript/test/tracker-bounds.test.ts +191 -0
  325. package/.next/standalone/sdk/typescript/test/wire-format.test.ts +214 -0
  326. package/.next/standalone/sdk/typescript/test/writer.test.ts +407 -0
  327. package/.next/standalone/sdk/typescript/tsconfig.build.json +15 -0
  328. package/.next/standalone/sdk/typescript/tsconfig.cjs.json +19 -0
  329. package/.next/standalone/sdk/typescript/tsconfig.json +28 -0
  330. package/.next/standalone/sdk/typescript/vitest.config.ts +33 -0
  331. package/.next/standalone/sdk/typescript/vitest.integration.config.ts +23 -0
  332. package/.next/standalone/server.js +1 -1
  333. package/bin/failproofai.mjs +2 -115
  334. package/dist/cli.mjs +6538 -13686
  335. package/dist/index.js +1 -19
  336. package/dist/worker.mjs +2085 -8012
  337. package/package.json +9 -9
  338. package/pi-extension/index.ts +0 -11
  339. package/scripts/build-policy-pack.mjs +2 -39
  340. package/src/hooks/builtin-policies.ts +3 -21
  341. package/src/hooks/cloud-enrollment-cli.ts +1 -1
  342. package/src/hooks/cloud-managed-policies.ts +0 -22
  343. package/src/hooks/custom-hooks-loader.ts +7 -45
  344. package/src/hooks/custom-hooks-registry.ts +1 -45
  345. package/src/hooks/first-run-gate.ts +0 -5
  346. package/src/hooks/fp-home.ts +0 -23
  347. package/src/hooks/handler.ts +6 -265
  348. package/src/hooks/hook-activity-store.ts +1 -105
  349. package/src/hooks/hook-telemetry.ts +0 -41
  350. package/src/hooks/loader-utils.ts +0 -6
  351. package/src/hooks/pack-cli.ts +17 -278
  352. package/src/hooks/pack-manifest.ts +7 -479
  353. package/src/hooks/pack-store.ts +10 -156
  354. package/src/hooks/policy-catalog.ts +0 -65
  355. package/src/hooks/policy-evaluator.ts +796 -940
  356. package/src/hooks/policy-registry.ts +0 -25
  357. package/src/hooks/policy-types.ts +0 -126
  358. package/src/hooks/worker-server.ts +26 -119
  359. package/src/index.ts +0 -6
  360. package/.next/standalone/.next/server/chunks/src_hooks_01frwmb._.js +0 -5
  361. package/.next/standalone/.next/server/chunks/src_hooks_18qtd42._.js +0 -3
  362. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01bmjsj._.js +0 -3
  363. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04usis8._.js +0 -4
  364. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__056wjo4._.js +0 -4
  365. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__059yza8._.js +0 -3
  366. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0eip4_k._.js +0 -22
  367. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n0xg95._.js +0 -4
  368. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qcb0mg._.js +0 -3
  369. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qxnccm._.js +0 -5
  370. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0rwtwpm._.js +0 -4
  371. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s_yomn._.js +0 -4
  372. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0soxz2z._.js +0 -3
  373. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0yrsbd_._.js +0 -3
  374. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11mayhe._.js +0 -4
  375. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__13d-wb6._.js +0 -3
  376. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1dinjii._.js +0 -3
  377. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1pprgri._.js +0 -4
  378. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1q4p5b8._.js +0 -4
  379. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1qiz0e4._.js +0 -3
  380. package/.next/standalone/.next/server/chunks/ssr/_042cgl1._.js +0 -3
  381. package/.next/standalone/.next/server/chunks/ssr/_0bqoto4._.js +0 -3
  382. package/.next/standalone/.next/server/chunks/ssr/_0uyu3jf._.js +0 -3
  383. package/.next/standalone/.next/server/chunks/ssr/_1feuvhb._.js +0 -5
  384. package/.next/standalone/.next/server/chunks/ssr/app_actions_get-scheduled-audit_ts_0ei9sni._.js +0 -3
  385. package/.next/standalone/.next/server/chunks/ssr/app_settings_02tf1h4._.js +0 -3
  386. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_0w6mzq5._.js +0 -151
  387. package/.next/standalone/.next/server/chunks/ssr/src_hooks_095a_79._.js +0 -5
  388. package/.next/standalone/.next/server/chunks/ssr/src_hooks_15t8kqj._.js +0 -3
  389. package/.next/standalone/.next/server/chunks/ssr/src_hooks_18k8rl0._.js +0 -12
  390. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1fm2w5z._.js +0 -3
  391. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1j0zy3v._.js +0 -3
  392. package/.next/standalone/.next/static/chunks/0cd-_8-c-m1ea.js +0 -6
  393. package/.next/standalone/.next/static/chunks/0uldbut9y2-e8.js +0 -1
  394. package/.next/standalone/.next/static/chunks/1u5zsejmgrir_.js +0 -1
  395. package/.next/standalone/.next/static/chunks/285spx855h_3r.css +0 -2
  396. package/.next/standalone/.next/static/chunks/2qv4hshejedtx.css +0 -1
  397. package/.next/standalone/.next/static/chunks/2vkvu9-opa_1z.js +0 -1
  398. package/.next/standalone/.next/static/chunks/37lhv7wa3ywt6.js +0 -1
  399. package/.next/standalone/app/actions/get-jev-config.ts +0 -409
  400. package/.next/standalone/app/actions/update-jev-config.ts +0 -420
  401. package/.next/standalone/app/components/jev-notices.tsx +0 -96
  402. package/.next/standalone/app/settings/jev-panel.tsx +0 -469
  403. package/src/hooks/effective-reviewers.ts +0 -79
  404. package/src/hooks/jev-activity.ts +0 -385
  405. package/src/hooks/jev-cli.ts +0 -1193
  406. package/src/hooks/policy-authority.ts +0 -333
  407. package/src/hooks/policy-reviewability.ts +0 -229
  408. package/src/hooks/semantic/combine.ts +0 -541
  409. package/src/hooks/semantic/compile.ts +0 -176
  410. package/src/hooks/semantic/decide.ts +0 -392
  411. package/src/hooks/semantic/envelope.ts +0 -1296
  412. package/src/hooks/semantic/evaluator.ts +0 -547
  413. package/src/hooks/semantic/facts.ts +0 -292
  414. package/src/hooks/semantic/intent.ts +0 -1190
  415. package/src/hooks/semantic/jev-client.ts +0 -643
  416. package/src/hooks/semantic/jev-config.ts +0 -594
  417. package/src/hooks/semantic/jev-review.ts +0 -374
  418. package/src/hooks/semantic/jev-stats.ts +0 -289
  419. package/src/hooks/semantic/jev-throttle.ts +0 -421
  420. package/src/hooks/semantic/pack-policies.ts +0 -251
  421. package/src/hooks/semantic/policies.ts +0 -596
  422. package/src/hooks/semantic/precondition-names.ts +0 -60
  423. package/src/hooks/semantic/preconditions.ts +0 -58
  424. package/src/hooks/semantic/redact.ts +0 -2910
  425. package/src/hooks/semantic/types.ts +0 -145
  426. package/src/hooks/semver-precedence.ts +0 -128
  427. /package/.next/standalone/.next/static/{T8YAYM9h_64fKv705vug7 → PgeWCHmyVbjRznv2VO7KF}/_buildManifest.js +0 -0
  428. /package/.next/standalone/.next/static/{T8YAYM9h_64fKv705vug7 → PgeWCHmyVbjRznv2VO7KF}/_clientMiddlewareManifest.js +0 -0
  429. /package/.next/standalone/.next/static/{T8YAYM9h_64fKv705vug7 → PgeWCHmyVbjRznv2VO7KF}/_ssgManifest.js +0 -0
@@ -0,0 +1,999 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+
3
+ import * as core from "../src/integrations/core.js";
4
+ import {
5
+ ABANDONED_ROOT_GRACE_MS,
6
+ adapter,
7
+ captureLimitOf,
8
+ interruptIdOf,
9
+ isCancellation,
10
+ isControlFlow,
11
+ langchainHandler,
12
+ nodeOf,
13
+ promptOf,
14
+ readOptions,
15
+ resetOrphanWarning,
16
+ usageOf,
17
+ } from "../src/integrations/langchain.js";
18
+ import { setLogger } from "../src/logger.js";
19
+ import { agent, session } from "../src/scopes.js";
20
+ import { flushed, useSpool } from "./helpers.js";
21
+ import type { Spool } from "./helpers.js";
22
+
23
+ /**
24
+ * The LangChain adapter's translation table, driven with the callback
25
+ * sequences LangChain.js and LangGraph.js actually dispatch — argument order,
26
+ * metadata keys, tags and error shapes copied from recorded runs of
27
+ * `@langchain/core` 0.3.80 / 1.2.12 and `@langchain/langgraph` 0.4.10 / 1.4.17.
28
+ *
29
+ * Every expectation is the Python adapter's output for the same run
30
+ * (`sdk/python/failproofai_sdk/integrations/langchain.py`); many of these
31
+ * are ports of `sdk/python/tests/integrations/test_langchain.py`, named after
32
+ * the Python test they mirror. The real frameworks are exercised end to end in
33
+ * `integration/langchain.test.ts`; this file pins the rules one at a time, fast
34
+ * and with no framework installed.
35
+ */
36
+
37
+ type Handler = Record<string | symbol, (...args: unknown[]) => unknown>;
38
+ type Event = Record<string, unknown>;
39
+
40
+ let spool: Spool;
41
+ let h: Handler;
42
+
43
+ beforeEach(() => {
44
+ spool = useSpool();
45
+ core.setStrict(true);
46
+ core.resetFailures();
47
+ h = langchainHandler() as Handler;
48
+ });
49
+ afterEach(async () => {
50
+ adapter.uninstall();
51
+ await spool.cleanup();
52
+ core.setStrict(null);
53
+ setLogger(null);
54
+ });
55
+
56
+ // -- a tiny LangChain -------------------------------------------------------
57
+
58
+ const msg = (type: string, content: unknown, extra: Record<string, unknown> = {}) => ({
59
+ getType: () => type,
60
+ content,
61
+ ...extra,
62
+ });
63
+ const human = (content: string) => msg("human", content);
64
+ const callWeather = (id = "call_1", city = "Paris") =>
65
+ msg("ai", "", { tool_calls: [{ id, name: "get_weather", args: { city }, type: "tool_call" }] });
66
+
67
+ const GRAPH = { lc: 1, type: "not_implemented", id: ["langgraph", "pregel", "CompiledStateGraph"] };
68
+ const MODEL = { lc: 1, type: "not_implemented", id: ["langchain", "chat_models", "scripted", "ScriptedModel"] };
69
+ const TOOL = { lc: 1, type: "not_implemented", id: ["langchain", "tools", "DynamicStructuredTool"] };
70
+
71
+ /** `handleChainStart(serialized, inputs, runId, parentRunId, tags, metadata, runType, runName)`. */
72
+ function chain(
73
+ id: string,
74
+ parent: string | undefined,
75
+ name: string,
76
+ opts: { inputs?: unknown; tags?: string[]; meta?: Record<string, unknown>; serialized?: unknown } = {},
77
+ ): void {
78
+ h.handleChainStart!(
79
+ opts.serialized ?? { lc: 1, type: "constructor", id: ["langchain_core", "runnables", "RunnableSequence"] },
80
+ opts.inputs ?? {},
81
+ id,
82
+ parent,
83
+ opts.tags ?? [],
84
+ opts.meta ?? {},
85
+ undefined,
86
+ name,
87
+ );
88
+ }
89
+
90
+ function root(id: string, name: string, meta: Record<string, unknown> = {}, inputs: unknown = { messages: [human("weather?")] }) {
91
+ chain(id, undefined, name, { inputs, meta: { ls_integration: "langgraph", ...meta }, serialized: GRAPH });
92
+ }
93
+
94
+ /** A LangGraph node's own run: named after the node, tagged `graph:step:N`. */
95
+ function node(id: string, parent: string, name: string, step: number, extra: Record<string, unknown> = {}) {
96
+ chain(id, parent, name, {
97
+ inputs: extra.inputs ?? { messages: [human("weather?")] },
98
+ tags: [`graph:step:${step}`],
99
+ meta: {
100
+ langgraph_node: name,
101
+ langgraph_step: step,
102
+ langgraph_checkpoint_ns: (extra.ns) ?? `${name}:${id}`,
103
+ ...(extra.meta as Record<string, unknown> | undefined),
104
+ },
105
+ });
106
+ }
107
+
108
+ function end(id: string, outputs: unknown = {}): void {
109
+ h.handleChainEnd!(outputs, id);
110
+ }
111
+
112
+ function fail(id: string, error: unknown): void {
113
+ h.handleChainError!(error, id);
114
+ }
115
+
116
+ function modelStart(id: string, parent: string | undefined, meta: Record<string, unknown> = {}, messages = [human("weather?")]) {
117
+ h.handleChatModelStart!(MODEL, [messages], id, parent, { invocation_params: {} }, [], meta, undefined);
118
+ }
119
+
120
+ function modelEnd(id: string, message: Record<string, unknown> = msg("ai", "hi"), llmOutput?: Record<string, unknown>) {
121
+ h.handleLLMEnd!({ generations: [[{ text: "", message }]], llmOutput }, id);
122
+ }
123
+
124
+ function toolStart(id: string, parent: string | undefined, input = '{"city":"Paris"}', toolCallId?: string, meta = {}) {
125
+ h.handleToolStart!(TOOL, input, id, parent, [], meta, "get_weather", toolCallId);
126
+ }
127
+
128
+ function toolEnd(id: string, output: unknown = "sunny in Paris"): void {
129
+ h.handleToolEnd!(output, id);
130
+ }
131
+
132
+ const events = (): Promise<Event[]> => flushed(spool);
133
+ const shape = (list: Event[]): string[] =>
134
+ list.map((e) => [e.agent_id, e.type, e.hook_name ?? e.tool_name ?? ""].join(" ").trim());
135
+ const ofType = (list: Event[], type: string): Event[] => list.filter((e) => e.type === type);
136
+
137
+ /** The weather graph, exactly as LangGraph.js 1.x dispatches it. */
138
+ function weatherGraph(opts: { toolCallId?: boolean; meta?: Record<string, unknown> } = {}): void {
139
+ const withId = opts.toolCallId ?? true;
140
+ root("g", "weather_graph", opts.meta);
141
+ chain("start", "g", "__start__", { tags: ["graph:step:0", "langsmith:hidden"], meta: { langgraph_node: "__start__", langgraph_step: 0 } });
142
+ end("start");
143
+ node("n1", "g", "agent", 1);
144
+ modelStart("m1", "n1", { langgraph_node: "agent", langgraph_step: 1 });
145
+ modelEnd("m1", msg("ai", "", {
146
+ tool_calls: [{ id: "call_1", name: "get_weather", args: { city: "Paris" }, type: "tool_call" }],
147
+ usage_metadata: { input_tokens: 12, output_tokens: 5, total_tokens: 17 },
148
+ }));
149
+ chain("route1", "n1", "RunnableLambda", { meta: { langgraph_node: "agent", langgraph_step: 1 } });
150
+ end("route1", { output: "tools" });
151
+ end("n1");
152
+ node("n2", "g", "tools", 2, { inputs: { messages: [human("weather?"), callWeather()] } });
153
+ toolStart("t1", "n2", '{"city":"Paris"}', withId ? "call_1" : undefined, { langgraph_node: "tools" });
154
+ toolEnd("t1", msg("tool", "sunny in Paris", { tool_call_id: "call_1", status: "success" }));
155
+ end("n2");
156
+ node("n3", "g", "agent", 3);
157
+ modelStart("m2", "n3", { langgraph_node: "agent", langgraph_step: 3 });
158
+ modelEnd("m2", msg("ai", "It is sunny in Paris.", {
159
+ usage_metadata: { input_tokens: 30, output_tokens: 7, total_tokens: 37 },
160
+ response_metadata: { finish_reason: "stop" },
161
+ }));
162
+ end("n3");
163
+ end("g");
164
+ }
165
+
166
+ const GRAPH_SHAPE = [
167
+ "weather_graph agent_start",
168
+ "weather_graph hook_triggered agent",
169
+ "weather_graph model_request",
170
+ "weather_graph model_response",
171
+ "weather_graph hook_completed agent",
172
+ "weather_graph hook_triggered tools",
173
+ "weather_graph tool_use get_weather",
174
+ "weather_graph tool_result get_weather",
175
+ "weather_graph hook_completed tools",
176
+ "weather_graph hook_triggered agent",
177
+ "weather_graph model_request",
178
+ "weather_graph model_response",
179
+ "weather_graph hook_completed agent",
180
+ "weather_graph agent_end",
181
+ ];
182
+
183
+ class GraphInterrupt extends Error {
184
+ interrupts: unknown[];
185
+ constructor(interrupts: unknown[]) {
186
+ super(JSON.stringify(interrupts));
187
+ this.name = "GraphInterrupt";
188
+ this.interrupts = interrupts;
189
+ }
190
+ get is_bubble_up(): boolean {
191
+ return true;
192
+ }
193
+ }
194
+
195
+ const command = (resume: unknown) => ({ lg_name: "Command", resume, goto: [] });
196
+
197
+ // -- the mapping ------------------------------------------------------------
198
+
199
+ describe("the graph mapping", () => {
200
+ it("a_langgraph_node_is_a_hook_not_a_nested_agent", async () => {
201
+ weatherGraph();
202
+ const list = await events();
203
+ expect(shape(list)).toEqual(GRAPH_SHAPE);
204
+ for (const hook of ofType(list, "hook_triggered")) expect(hook.trigger_event).toBe("graph_node");
205
+ // One agent, named after the graph, never a run id.
206
+ expect(new Set(list.map((e) => e.agent_id))).toEqual(new Set(["weather_graph"]));
207
+ });
208
+
209
+ it("the root agent_start is the session's first event and every event carries one session", async () => {
210
+ weatherGraph();
211
+ const list = await events();
212
+ expect(list[0]!.type).toBe("agent_start");
213
+ expect(new Set(list.map((e) => e.session_id)).size).toBe(1);
214
+ expect(list.every((e) => e.framework === "langchain")).toBe(true);
215
+ });
216
+
217
+ it("intermediate runnables, edge functions and hidden nodes emit nothing", async () => {
218
+ weatherGraph();
219
+ const names = (await events()).map((e) => e.hook_name).filter(Boolean);
220
+ expect(names).not.toContain("__start__");
221
+ expect(names).not.toContain("RunnableLambda");
222
+ });
223
+
224
+ it("carries the langgraph ids as fw_* extras, never as declared fields", async () => {
225
+ weatherGraph();
226
+ const hook = ofType(await events(), "hook_triggered")[0]!;
227
+ expect(hook.fw_node).toBe("agent");
228
+ expect(hook.fw_step).toBe(1);
229
+ expect(hook.fw_run_id).toBe("n1");
230
+ expect(hook.fw_parent_run_id).toBe("g");
231
+ expect(hook.fw_tags).toEqual(["graph:step:1"]);
232
+ });
233
+
234
+ it("model events pair on request_id and always carry an int duration and the tokens", async () => {
235
+ weatherGraph();
236
+ const list = await events();
237
+ const requests = ofType(list, "model_request");
238
+ const responses = ofType(list, "model_response");
239
+ expect(responses.map((r) => r.request_id)).toEqual(requests.map((r) => r.request_id));
240
+ for (const response of responses) expect(Number.isInteger(response.duration_ms)).toBe(true);
241
+ expect(responses.map((r) => [r.input_tokens, r.output_tokens])).toEqual([
242
+ [12, 5],
243
+ [30, 7],
244
+ ]);
245
+ expect(responses[1]!.usage).toEqual({ input_tokens: 30, output_tokens: 7, total_tokens: 37 });
246
+ expect(responses[1]!.stop_reason).toBe("stop");
247
+ expect(requests[0]!.model).toBe("ScriptedModel");
248
+ });
249
+
250
+ it("a node that returns a Command renders the messages inside it, not their serialization envelope", async () => {
251
+ // `langchain`'s `createAgent` model node returns `{ output: [Command] }`.
252
+ // A Command is neither a message nor LangChain `Serializable` (no
253
+ // `lc_kwargs`), so the payload view used to hand it to `truncate` whole,
254
+ // which dumps it through `toJSON()` — and the messages in its `update`
255
+ // then through THEIRS, LangChain's `{lc, type: "constructor", id, kwargs}`
256
+ // envelope: class paths with the content buried one level down.
257
+ class Message {
258
+ lc_kwargs = { content: "hi" };
259
+ content = "hi";
260
+ getType(): string {
261
+ return "ai";
262
+ }
263
+ toJSON(): unknown {
264
+ return { lc: 1, type: "constructor", id: ["langchain_core", "messages", "AIMessage"], kwargs: this.lc_kwargs };
265
+ }
266
+ }
267
+ class Command {
268
+ lg_name = "Command";
269
+ update = { messages: [new Message()] };
270
+ goto: string[] = [];
271
+ toJSON(): unknown {
272
+ return { lg_name: this.lg_name, update: this.update, resume: undefined, goto: this.goto };
273
+ }
274
+ }
275
+ root("g", "weather_agent");
276
+ node("n", "g", "model_request", 1);
277
+ end("n", { output: [new Command()] });
278
+ end("g");
279
+ const done = ofType(await events(), "hook_completed")[0]!;
280
+ expect(done.output).toEqual({
281
+ output: [{ lg_name: "Command", update: { messages: [{ type: "ai", content: "hi" }] }, resume: null, goto: [] }],
282
+ });
283
+ expect(JSON.stringify(done.output)).not.toContain('"lc":1');
284
+ });
285
+
286
+ it("model_request carries normalized messages with their roles", async () => {
287
+ root("g", "weather_graph");
288
+ node("n", "g", "agent", 1);
289
+ modelStart("m", "n", {}, [
290
+ msg("system", "be brief"),
291
+ human("weather?"),
292
+ callWeather(),
293
+ msg("tool", "sunny in Paris", { tool_call_id: "call_1" }),
294
+ ]);
295
+ modelEnd("m");
296
+ end("n");
297
+ end("g");
298
+ expect(ofType(await events(), "model_request")[0]!.messages).toEqual([
299
+ { role: "system", content: "be brief" },
300
+ { role: "user", content: "weather?" },
301
+ {
302
+ role: "assistant",
303
+ content: "",
304
+ tool_calls: [{ id: "call_1", name: "get_weather", args: { city: "Paris" }, type: "tool_call" }],
305
+ },
306
+ { role: "tool", content: "sunny in Paris" },
307
+ ]);
308
+ });
309
+
310
+ it("tool_use carries the MODEL's tool_call_id, and the tool's content not the message object", async () => {
311
+ weatherGraph();
312
+ const list = await events();
313
+ expect(ofType(list, "tool_use")[0]!.tool_call_id).toBe("call_1");
314
+ expect(ofType(list, "tool_use")[0]!.input).toEqual({ city: "Paris" });
315
+ const result = ofType(list, "tool_result")[0]!;
316
+ expect(result.tool_call_id).toBe("call_1");
317
+ expect(result.output).toBe("sunny in Paris");
318
+ expect(result.error).toBeUndefined();
319
+ });
320
+
321
+ it("recovers the tool_call_id on a core that does not pass one (0.3)", async () => {
322
+ weatherGraph({ toolCallId: false });
323
+ expect(ofType(await events(), "tool_use")[0]!.tool_call_id).toBe("call_1");
324
+ });
325
+
326
+ it("gives two identical tool calls their two different ids (0.3)", async () => {
327
+ root("g", "weather_graph");
328
+ node("n", "g", "tools", 1, {
329
+ inputs: {
330
+ messages: [
331
+ msg("ai", "", {
332
+ tool_calls: [
333
+ { id: "call_a", name: "get_weather", args: { city: "Paris" } },
334
+ { id: "call_b", name: "get_weather", args: { city: "Paris" } },
335
+ ],
336
+ }),
337
+ ],
338
+ },
339
+ });
340
+ toolStart("t1", "n");
341
+ toolStart("t2", "n");
342
+ toolEnd("t1");
343
+ toolEnd("t2");
344
+ end("n");
345
+ end("g");
346
+ const ids = ofType(await events(), "tool_use").map((e) => e.tool_call_id);
347
+ expect(ids.sort()).toEqual(["call_a", "call_b"]);
348
+ });
349
+
350
+ it("falls back to the run id when no ancestor asked for the call", async () => {
351
+ root("g", "weather_graph");
352
+ node("n", "g", "tools", 1, { inputs: { messages: [human("hi")] } });
353
+ toolStart("t1", "n");
354
+ toolEnd("t1");
355
+ end("n");
356
+ end("g");
357
+ expect(ofType(await events(), "tool_use")[0]!.tool_call_id).toBe("t1");
358
+ });
359
+
360
+ it("a_compiled_subgraph_becomes_a_nested_agent", async () => {
361
+ root("p", "parent_graph", {}, { trail: [] });
362
+ node("pre", "p", "pre", 1, { inputs: { trail: [] } });
363
+ end("pre");
364
+ node("host", "p", "child", 2, { ns: "child:aaa" });
365
+ chain("sub", "host", "child_graph", { meta: { langgraph_node: "child" }, serialized: GRAPH });
366
+ node("inner", "sub", "inner", 1, { ns: "child:aaa|inner:bbb" });
367
+ end("inner");
368
+ end("sub");
369
+ end("host");
370
+ end("p");
371
+ const list = await events();
372
+ expect(shape(list)).toEqual([
373
+ "parent_graph agent_start",
374
+ "parent_graph hook_triggered pre",
375
+ "parent_graph hook_completed pre",
376
+ "parent_graph hook_triggered child",
377
+ "parent_graph/child agent_start",
378
+ "parent_graph/child hook_triggered inner",
379
+ "parent_graph/child hook_completed inner",
380
+ "parent_graph/child agent_end",
381
+ "parent_graph hook_completed child",
382
+ "parent_graph agent_end",
383
+ ]);
384
+ expect(ofType(list, "agent_start")[1]!.parent_id).toBe("parent_graph");
385
+ });
386
+
387
+ it("records a bare model call as a root agent with its model pair inside", async () => {
388
+ modelStart("m", undefined);
389
+ modelEnd("m", msg("ai", "hi", { usage_metadata: { input_tokens: 1, output_tokens: 2, total_tokens: 3 } }));
390
+ const list = await events();
391
+ expect(shape(list)).toEqual([
392
+ "ScriptedModel agent_start",
393
+ "ScriptedModel model_request",
394
+ "ScriptedModel model_response",
395
+ "ScriptedModel agent_end",
396
+ ]);
397
+ expect(ofType(list, "model_request")[0]!.request_id).toBe(ofType(list, "model_response")[0]!.request_id);
398
+ expect(ofType(list, "agent_start")[0]!.goal).toBe("weather?");
399
+ });
400
+
401
+ it("records a bare tool call as a root agent with its tool pair inside", async () => {
402
+ toolStart("t", undefined, '{"city":"Rome"}');
403
+ toolEnd("t", "sunny in Rome");
404
+ expect(shape(await events())).toEqual([
405
+ "get_weather agent_start",
406
+ "get_weather tool_use get_weather",
407
+ "get_weather tool_result get_weather",
408
+ "get_weather agent_end",
409
+ ]);
410
+ });
411
+
412
+ it("two_overlapping_roots_in_one_session_are_two_agents", async () => {
413
+ // `.batch()` opens one root per input, concurrently.
414
+ const handler = langchainHandler({ sessionId: "shared" }) as Handler;
415
+ expect(handler).toBe(h);
416
+ modelStart("a", undefined);
417
+ modelStart("b", undefined);
418
+ modelEnd("a");
419
+ modelEnd("b");
420
+ const list = await events();
421
+ expect(ofType(list, "agent_start")).toHaveLength(2);
422
+ expect(ofType(list, "agent_end")).toHaveLength(2);
423
+ expect(ofType(list, "model_response")).toHaveLength(2);
424
+ expect(ofType(list, "human_input")).toHaveLength(0);
425
+ });
426
+
427
+ it("retriever output is summarized, never the document text", async () => {
428
+ root("g", "rag");
429
+ h.handleRetrieverStart!({ id: ["x", "VectorStoreRetriever"] }, "kites", "r", "g", [], {}, undefined);
430
+ h.handleRetrieverEnd!(
431
+ [
432
+ { pageContent: "a very long document", metadata: { source: "a.txt" } },
433
+ { pageContent: "another", metadata: {} },
434
+ ],
435
+ "r",
436
+ );
437
+ end("g");
438
+ const list = await events();
439
+ expect(ofType(list, "tool_use")[0]!.tool_name).toBe("retriever:VectorStoreRetriever");
440
+ expect(ofType(list, "tool_use")[0]!.input).toEqual({ query: "kites" });
441
+ expect(ofType(list, "tool_result")[0]!.output).toEqual({ n: 2, sources: ["a.txt", "doc[1]"] });
442
+ });
443
+
444
+ it("streaming never emits per-token events; it folds into the model_response", async () => {
445
+ modelStart("m", undefined);
446
+ for (let i = 0; i < 5; i += 1) h.handleLLMNewToken!("x", {}, "m");
447
+ modelEnd("m", msg("ai", "xxxxx"));
448
+ const list = await events();
449
+ expect(list.map((e) => e.type)).toEqual(["agent_start", "model_request", "model_response", "agent_end"]);
450
+ const response = ofType(list, "model_response")[0]!;
451
+ expect(response.fw_streamed).toBe(true);
452
+ expect(response.fw_chunks).toBe(5);
453
+ expect(Number.isInteger(response.fw_ttft_ms)).toBe(true);
454
+ });
455
+
456
+ it("records an intermediate chain only when includeChains names it", async () => {
457
+ adapter.uninstall();
458
+ h = langchainHandler({ includeChains: ["summarise"] }) as Handler;
459
+ chain("p", undefined, "pipeline", { inputs: { input: "abc" } });
460
+ chain("s1", "p", "RunnableLambda", { tags: ["seq:step:1"] });
461
+ end("s1");
462
+ chain("s2", "p", "summarise", { tags: ["seq:step:2"], inputs: { input: "abc" } });
463
+ end("s2", { output: "ABC" });
464
+ end("p");
465
+ const list = await events();
466
+ expect(shape(list)).toEqual([
467
+ "pipeline agent_start",
468
+ "pipeline hook_triggered summarise",
469
+ "pipeline hook_completed summarise",
470
+ "pipeline agent_end",
471
+ ]);
472
+ expect(ofType(list, "hook_triggered")[0]!.trigger_event).toBe("pipeline");
473
+ });
474
+ });
475
+
476
+ describe("the node filter", () => {
477
+ const meta = { langgraph_node: "lookup" };
478
+
479
+ it("matches a node's own run", () => {
480
+ expect(nodeOf({ name: "lookup", runType: "chain", tags: ["graph:step:1"] }, meta)).toBe("lookup");
481
+ });
482
+
483
+ it("a_node_named_after_its_tool_still_records_the_tool", () => {
484
+ expect(nodeOf({ name: "lookup", runType: "tool", tags: [] }, meta)).toBeNull();
485
+ });
486
+
487
+ it("a_node_named_after_its_model_still_records_the_model", () => {
488
+ expect(nodeOf({ name: "lookup", runType: "chat_model", tags: [] }, meta)).toBeNull();
489
+ });
490
+
491
+ it("an_inner_runnable_sharing_the_node_name_is_not_a_second_visit", () => {
492
+ expect(nodeOf({ name: "lookup", runType: "chain", tags: ["seq:step:2"] }, meta)).toBeNull();
493
+ });
494
+
495
+ it("an inner runnable that merely inherits the metadata is not the node", () => {
496
+ expect(nodeOf({ name: "RunnableLambda", runType: "chain", tags: [] }, meta)).toBeNull();
497
+ });
498
+
499
+ it("records the tool pair when a ToolNode is named after its tool", async () => {
500
+ root("g", "graph");
501
+ node("n", "g", "get_weather", 1, { inputs: { messages: [callWeather()] } });
502
+ // The tool's own run has the SAME name and inherits the node metadata.
503
+ h.handleToolStart!(TOOL, '{"city":"Paris"}', "t", "n", [], { langgraph_node: "get_weather" }, "get_weather", "call_1");
504
+ toolEnd("t");
505
+ end("n");
506
+ end("g");
507
+ expect(shape(await events())).toEqual([
508
+ "graph agent_start",
509
+ "graph hook_triggered get_weather",
510
+ "graph tool_use get_weather",
511
+ "graph tool_result get_weather",
512
+ "graph hook_completed get_weather",
513
+ "graph agent_end",
514
+ ]);
515
+ });
516
+ });
517
+
518
+ // -- failure ----------------------------------------------------------------
519
+
520
+ describe("failure", () => {
521
+ it("a_failed_model_call_is_reported_on_the_model_span_and_counted_once", async () => {
522
+ root("g", "weather_graph");
523
+ node("n", "g", "agent", 1);
524
+ modelStart("m", "n");
525
+ h.handleLLMError!(new Error("model exploded"), "m");
526
+ fail("n", new Error("model exploded"));
527
+ fail("g", new Error("model exploded"));
528
+ const list = await events();
529
+ expect(shape(list)).toEqual([
530
+ "weather_graph agent_start",
531
+ "weather_graph hook_triggered agent",
532
+ "weather_graph model_request",
533
+ "weather_graph model_response",
534
+ "weather_graph hook_completed agent",
535
+ "weather_graph agent_end",
536
+ ]);
537
+ const response = ofType(list, "model_response")[0]!;
538
+ expect(response.error).toBe("Error: model exploded");
539
+ expect(response.stop_reason).toBe("error");
540
+ expect(ofType(list, "hook_completed")[0]!.outcome).toBe("failed");
541
+ const endEvent = ofType(list, "agent_end")[0]!;
542
+ expect(endEvent.outcome).toBe("failed");
543
+ expect(endEvent.summary).toBe("Error: model exploded");
544
+ expect(ofType(list, "error")).toHaveLength(0);
545
+ });
546
+
547
+ it("a_failure_no_span_owns_produces_exactly_one_error_event", async () => {
548
+ // `prompt | model | parser` whose parser raised: no span owns it.
549
+ chain("p", undefined, "RunnableSequence", { inputs: { input: "x" } });
550
+ chain("parser", "p", "StrOutputParser", { tags: ["seq:step:3"] });
551
+ fail("parser", new TypeError("cannot parse"));
552
+ fail("p", new TypeError("cannot parse"));
553
+ const list = await events();
554
+ expect(list.map((e) => e.type)).toEqual(["agent_start", "error", "agent_end"]);
555
+ const error = ofType(list, "error")[0]!;
556
+ expect(error.error_type).toBe("TypeError");
557
+ // The bare message: the server prefixes the type itself.
558
+ expect(error.message).toBe("cannot parse");
559
+ expect(ofType(list, "agent_end")[0]!.outcome).toBe("failed");
560
+ });
561
+
562
+ it("a_failing_bare_tool_reports_its_error_once", async () => {
563
+ toolStart("t", undefined);
564
+ h.handleToolError!(new Error("no weather"), "t");
565
+ const list = await events();
566
+ expect(ofType(list, "tool_result")[0]!.error).toBe("Error: no weather");
567
+ expect(ofType(list, "error")).toHaveLength(0);
568
+ expect(ofType(list, "agent_end")[0]!.outcome).toBe("failed");
569
+ });
570
+
571
+ it("a_tool_that_fails_without_raising_is_still_an_error", async () => {
572
+ root("g", "graph");
573
+ node("n", "g", "tools", 1, { inputs: { messages: [callWeather()] } });
574
+ toolStart("t", "n", '{"city":"Paris"}', "call_1");
575
+ toolEnd("t", msg("tool", "Error: no weather\n Please fix your mistakes.", { status: "error", tool_call_id: "call_1" }));
576
+ end("n");
577
+ end("g");
578
+ const result = ofType(await events(), "tool_result")[0]!;
579
+ expect(result.error).toBe("Error: no weather\n Please fix your mistakes.");
580
+ expect(result.output).toBe("Error: no weather\n Please fix your mistakes.");
581
+ });
582
+
583
+ it("a cancelled run ends cancelled, with no error event", async () => {
584
+ root("g", "graph");
585
+ node("n", "g", "agent", 1);
586
+ const abort = new Error("This operation was aborted");
587
+ abort.name = "AbortError";
588
+ fail("n", abort);
589
+ fail("g", abort);
590
+ const list = await events();
591
+ expect(ofType(list, "hook_completed")[0]!.outcome).toBe("cancelled");
592
+ expect(ofType(list, "agent_end")[0]!.outcome).toBe("cancelled");
593
+ expect(ofType(list, "error")).toHaveLength(0);
594
+ });
595
+
596
+ it("closes a root LangGraph abandoned after an abort, once it has been silent", async () => {
597
+ vi.useFakeTimers();
598
+ try {
599
+ root("g", "abort_graph");
600
+ node("n", "g", "slow", 1);
601
+ const abort = new Error("This operation was aborted");
602
+ abort.name = "AbortError";
603
+ fail("n", abort);
604
+ // LangGraph.js 1.x: no end callback for the root, ever.
605
+ vi.advanceTimersByTime(ABANDONED_ROOT_GRACE_MS - 1);
606
+ expect(ofType(await events(), "agent_end")).toHaveLength(0);
607
+ vi.advanceTimersByTime(1);
608
+ const list = await events();
609
+ expect(list.map((e) => e.type)).toEqual(["agent_start", "hook_triggered", "hook_completed", "agent_end"]);
610
+ expect(ofType(list, "agent_end")[0]!.outcome).toBe("cancelled");
611
+ expect(ofType(list, "error")).toHaveLength(0);
612
+ } finally {
613
+ vi.useRealTimers();
614
+ }
615
+ });
616
+
617
+ it("does not reap a root that carried on after a node's own abort (a retry)", async () => {
618
+ vi.useFakeTimers();
619
+ try {
620
+ root("g", "graph");
621
+ node("n1", "g", "fetch", 1);
622
+ const abort = new Error("timed out");
623
+ abort.name = "AbortError";
624
+ fail("n1", abort);
625
+ vi.advanceTimersByTime(500);
626
+ node("n2", "g", "fetch", 1); // the retry
627
+ vi.advanceTimersByTime(ABANDONED_ROOT_GRACE_MS * 2);
628
+ expect(ofType(await events(), "agent_end")).toHaveLength(0);
629
+ end("n2");
630
+ end("g");
631
+ const list = await events();
632
+ expect(ofType(list, "agent_end").map((e) => e.outcome)).toEqual(["success"]);
633
+ } finally {
634
+ vi.useRealTimers();
635
+ }
636
+ });
637
+
638
+ it("classifies control flow and cancellation", () => {
639
+ expect(isControlFlow(new GraphInterrupt([]))).toBe(true);
640
+ const named = new Error("x");
641
+ named.name = "ParentCommand";
642
+ expect(isControlFlow(named)).toBe(true);
643
+ expect(isControlFlow(new Error("x"))).toBe(false);
644
+ expect(isCancellation(new Error("Aborted"))).toBe(true);
645
+ expect(isCancellation(new Error("Abort"))).toBe(true);
646
+ expect(isCancellation(Object.assign(new Error("x"), { code: "ABORT_ERR" }))).toBe(true);
647
+ expect(isCancellation(new Error("x"))).toBe(false);
648
+ });
649
+
650
+ it("open leaves are closed when the root run ends without them", async () => {
651
+ root("g", "graph");
652
+ node("n", "g", "tools", 1, { inputs: { messages: [callWeather()] } });
653
+ toolStart("t", "n", '{"city":"Paris"}', "call_1");
654
+ // The framework skipped both end callbacks.
655
+ end("g");
656
+ const list = await events();
657
+ const result = ofType(list, "tool_result")[0]!;
658
+ expect(result.fw_incomplete).toBe(true);
659
+ expect(ofType(list, "hook_completed")[0]!.outcome).toBe("cancelled");
660
+ expect(list.at(-1)!.type).toBe("agent_end");
661
+ });
662
+ });
663
+
664
+ // -- human in the loop ------------------------------------------------------
665
+
666
+ function interruptRun(rootId = "r1", threadId = "t-1"): void {
667
+ root(rootId, "hitl_graph", { thread_id: threadId }, { trail: [] });
668
+ node(`${rootId}-approve`, rootId, "approve", 2, { inputs: { trail: ["plan"] } });
669
+ fail(`${rootId}-approve`, new GraphInterrupt([{ id: "int-1", value: { prompt: "ship it?", options: ["yes", "no"] } }]));
670
+ end(rootId, { trail: ["plan"] });
671
+ }
672
+
673
+ describe("human in the loop", () => {
674
+ it("interrupt_and_resume_emit_both_pairs_in_order", async () => {
675
+ interruptRun();
676
+ root("r2", "hitl_graph", { thread_id: "t-1" }, command("yes"));
677
+ node("r2-approve", "r2", "approve", 2);
678
+ end("r2-approve", { trail: ["approve:yes"] });
679
+ end("r2");
680
+ const list = await events();
681
+ expect(shape(list)).toEqual([
682
+ "hitl_graph agent_start",
683
+ "hitl_graph hook_triggered approve",
684
+ "hitl_graph hook_completed approve",
685
+ "hitl_graph human_wait",
686
+ "hitl_graph agent_pause",
687
+ "hitl_graph agent_resume",
688
+ "hitl_graph human_input",
689
+ "hitl_graph hook_triggered approve",
690
+ "hitl_graph hook_completed approve",
691
+ "hitl_graph agent_end",
692
+ ]);
693
+ expect(ofType(list, "hook_completed")[0]!.outcome).toBe("paused");
694
+ const wait = ofType(list, "human_wait")[0]!;
695
+ expect([wait.input_id, wait.prompt, wait.options]).toEqual(["int-1", "ship it?", ["yes", "no"]]);
696
+ const answer = ofType(list, "human_input")[0]!;
697
+ expect([answer.input_id, answer.response, answer.fw_prompt]).toEqual(["int-1", "yes", "ship it?"]);
698
+ expect(ofType(list, "agent_end")[0]!.outcome).toBe("success");
699
+ expect(new Set(list.map((e) => e.session_id))).toEqual(new Set(["t-1"]));
700
+ });
701
+
702
+ it("an_interrupt_is_control_flow_not_an_error", async () => {
703
+ interruptRun();
704
+ const list = await events();
705
+ expect(ofType(list, "error")).toHaveLength(0);
706
+ // Deliberately still open: the resume closes it.
707
+ expect(ofType(list, "agent_end")).toHaveLength(0);
708
+ });
709
+
710
+ it("the_two_interrupt_paths_do_not_double_emit", async () => {
711
+ root("r1", "hitl_graph", { thread_id: "t-1" }, { trail: [] });
712
+ node("a", "r1", "approve", 2);
713
+ const interrupts = [{ id: "int-1", value: "ok?" }];
714
+ fail("a", new GraphInterrupt(interrupts));
715
+ // LangGraph.js >= 1 also delivers it through the lifecycle callback.
716
+ h.handleInterrupt!({ runId: "r1", status: "pending", checkpointNs: [], interrupts });
717
+ end("r1");
718
+ const list = await events();
719
+ expect(ofType(list, "human_wait")).toHaveLength(1);
720
+ expect(ofType(list, "agent_pause")).toHaveLength(1);
721
+ });
722
+
723
+ it("interrupt events survive without the graph lifecycle callbacks", async () => {
724
+ adapter.uninstall();
725
+ h = langchainHandler({ graphCallbacks: false }) as Handler;
726
+ expect(h[Symbol.for("langgraph.graph_callback_handler")]).toBe(false);
727
+ interruptRun();
728
+ expect(ofType(await events(), "human_wait")).toHaveLength(1);
729
+ });
730
+
731
+ it("carries the LangGraph lifecycle marker by default", () => {
732
+ expect(h[Symbol.for("langgraph.graph_callback_handler")]).toBe(true);
733
+ });
734
+
735
+ it("an_unrelated_run_during_a_pause_is_not_read_as_the_approval", async () => {
736
+ interruptRun();
737
+ // A different graph on the same thread, with FRESH state.
738
+ root("other", "other", { thread_id: "t-1" }, { vals: [] });
739
+ end("other");
740
+ const list = await events();
741
+ expect(ofType(list, "agent_resume")).toHaveLength(0);
742
+ expect(ofType(list, "human_input")).toHaveLength(0);
743
+ expect(ofType(list, "agent_start").map((e) => e.agent_id)).toContain("other");
744
+ });
745
+
746
+ it("a_none_input_is_still_a_continuation_of_the_pause", async () => {
747
+ interruptRun();
748
+ root("r2", "hitl_graph", { thread_id: "t-1" }, { input: null });
749
+ end("r2");
750
+ const list = await events();
751
+ expect(ofType(list, "agent_start")).toHaveLength(1);
752
+ expect(ofType(list, "agent_resume")).toHaveLength(1);
753
+ });
754
+
755
+ it("an_unrelated_runnable_invoked_with_none_is_not_the_humans_approval", async () => {
756
+ interruptRun();
757
+ // `someRunnable.invoke(null)` inside the same session scope: the same
758
+ // `{input: null}` shape, but no graph metadata.
759
+ langchainHandler({ sessionId: "t-1" });
760
+ chain("hb", undefined, "heartbeat", { inputs: { input: null } });
761
+ end("hb");
762
+ const list = await events();
763
+ expect(ofType(list, "agent_resume")).toHaveLength(0);
764
+ });
765
+
766
+ it("closes a paused agent as cancelled at uninstall", async () => {
767
+ interruptRun();
768
+ adapter.uninstall();
769
+ const list = await events();
770
+ expect(list.at(-1)!.type).toBe("agent_end");
771
+ expect(list.at(-1)!.outcome).toBe("cancelled");
772
+ });
773
+
774
+ it("drops the prompt and the answer under captureContent: false", async () => {
775
+ adapter.uninstall();
776
+ h = langchainHandler({ captureContent: false }) as Handler;
777
+ interruptRun();
778
+ root("r2", "hitl_graph", { thread_id: "t-1" }, command("yes"));
779
+ end("r2");
780
+ const list = await events();
781
+ expect(ofType(list, "human_wait")[0]!.prompt).toBeUndefined();
782
+ expect(ofType(list, "human_wait")[0]!.options).toBeUndefined();
783
+ expect(ofType(list, "human_input")[0]!.response).toBeUndefined();
784
+ expect(ofType(list, "human_input")[0]!.fw_prompt).toBeUndefined();
785
+ });
786
+
787
+ it("reads a prompt out of the interrupt payload", () => {
788
+ expect(promptOf({ question: "ok?", options: ["y", 2] })).toEqual({ prompt: "ok?", options: ["y", "2"] });
789
+ expect(promptOf("plain")).toEqual({ prompt: "plain" });
790
+ expect(promptOf({ record: 1 })).toEqual({ prompt: '{"record":1}', options: undefined });
791
+ });
792
+
793
+ it("derives no cross-process pause id when LangGraph is not installed", () => {
794
+ // The remote path degrades to "no resume pair", never to a made-up id.
795
+ expect(interruptIdOf("approve:1234")).toBeNull();
796
+ });
797
+ });
798
+
799
+ // -- sessions ---------------------------------------------------------------
800
+
801
+ describe("session resolution", () => {
802
+ it("an explicit sessionId option wins over everything", async () => {
803
+ adapter.uninstall();
804
+ h = langchainHandler({ sessionId: "opt" }) as Handler;
805
+ weatherGraph({ meta: { failproofai_sdk_session_id: "meta", thread_id: "th" } });
806
+ expect(new Set((await events()).map((e) => e.session_id))).toEqual(new Set(["opt"]));
807
+ });
808
+
809
+ it("session_id_prefers_the_documented_metadata_key_over_thread_id", async () => {
810
+ weatherGraph({ meta: { failproofai_sdk_session_id: "meta", thread_id: "th" } });
811
+ expect(new Set((await events()).map((e) => e.session_id))).toEqual(new Set(["meta"]));
812
+ });
813
+
814
+ it("session_id_falls_back_to_thread_id", async () => {
815
+ weatherGraph({ meta: { thread_id: "th" } });
816
+ expect(new Set((await events()).map((e) => e.session_id))).toEqual(new Set(["th"]));
817
+ });
818
+
819
+ it("session_id_falls_back_to_the_root_run_id", async () => {
820
+ weatherGraph();
821
+ expect(new Set((await events()).map((e) => e.session_id))).toEqual(new Set(["g"]));
822
+ });
823
+
824
+ it("an_ambient_agent_scope_and_the_adapter_produce_one_tree", async () => {
825
+ await session({ sessionId: "req-1" }, () =>
826
+ agent("planner", () => {
827
+ weatherGraph({ meta: { thread_id: "th" } });
828
+ }),
829
+ );
830
+ const list = await events();
831
+ expect(new Set(list.map((e) => e.session_id))).toEqual(new Set(["req-1"]));
832
+ const graphStart = ofType(list, "agent_start").find((e) => e.agent_id === "weather_graph")!;
833
+ expect(graphStart.parent_id).toBe("planner");
834
+ });
835
+
836
+ it("a graph wrapped in an agent() of its own name joins it instead of nesting a copy", async () => {
837
+ // The wrap every tester reached for — to own the session id and print it.
838
+ // It used to give each run two agent_start/agent_end pairs, the graph's
839
+ // listing the wrapper (itself) as its parent.
840
+ await session({ sessionId: "req-2" }, () =>
841
+ agent("weather_graph", () => {
842
+ weatherGraph({ meta: { thread_id: "th" } });
843
+ }),
844
+ );
845
+ const list = await events();
846
+ expect(ofType(list, "agent_start").map((e) => [e.agent_id, e.parent_id ?? null])).toEqual([
847
+ ["weather_graph", null],
848
+ ]);
849
+ expect(ofType(list, "agent_end")).toHaveLength(1);
850
+ expect(list[0]!.type).toBe("agent_start");
851
+ expect(list.at(-1)!.type).toBe("agent_end");
852
+ // Everything the graph recorded is still there, on the one agent.
853
+ expect(ofType(list, "tool_use").length).toBeGreaterThan(0);
854
+ expect(new Set(list.map((e) => e.agent_id))).toEqual(new Set(["weather_graph"]));
855
+ });
856
+ });
857
+
858
+ // -- options and teardown ---------------------------------------------------
859
+
860
+ describe("options", () => {
861
+ it("captureContent: false keeps structure, durations and tokens, and drops the rest", async () => {
862
+ adapter.uninstall();
863
+ h = langchainHandler({ captureContent: false }) as Handler;
864
+ weatherGraph();
865
+ const list = await events();
866
+ expect(shape(list)).toEqual(GRAPH_SHAPE);
867
+ for (const event of list) {
868
+ for (const key of ["goal", "input", "output", "messages", "content"]) {
869
+ expect(event[key], `${String(event.type)}.${key}`).toBeUndefined();
870
+ }
871
+ }
872
+ expect(ofType(list, "model_response").map((e) => e.output_tokens)).toEqual([5, 7]);
873
+ });
874
+
875
+ it("captureLimit bounds captured values", async () => {
876
+ adapter.uninstall();
877
+ h = langchainHandler({ captureLimit: 20 }) as Handler;
878
+ toolStart("t", undefined);
879
+ toolEnd("t", "x".repeat(200));
880
+ const output = ofType(await events(), "tool_result")[0]!.output as string;
881
+ expect(output.length).toBeLessThanOrEqual(20);
882
+ expect(output.endsWith(core.TRUNCATION_MARKER)).toBe(true);
883
+ });
884
+
885
+ it("says so, once, when a run's parent was never seen — the unawaited-instrument() trace", () => {
886
+ // `void instrument()` then `graph.invoke()`: the root starts before the
887
+ // callback exists, so its nodes arrive under a parent nobody saw and one
888
+ // of them became the session's agent with nothing said.
889
+ resetOrphanWarning();
890
+ const warn = vi.fn();
891
+ setLogger({ debug: vi.fn(), info: vi.fn(), warn, error: vi.fn() });
892
+ node("n1", "never-seen-root", "bump", 1);
893
+ node("n2", "never-seen-root", "bump", 2);
894
+ const orphan = warn.mock.calls.map((c) => String(c[0])).filter((m) => m.includes("never saw"));
895
+ expect(orphan).toHaveLength(1);
896
+ expect(orphan[0]).toContain("await failproofai.instrument()");
897
+ });
898
+
899
+ it("says so when a graph node arrives as a root — the other shape of an unawaited instrument()", () => {
900
+ // Live: the graph's root started before the callback existed, so the
901
+ // handler it built never reached the nodes' parent chain, and each node
902
+ // arrived with no parent at all and became the session's agent.
903
+ resetOrphanWarning();
904
+ const warn = vi.fn();
905
+ setLogger({ debug: vi.fn(), info: vi.fn(), warn, error: vi.fn() });
906
+ chain("n1", undefined, "agent", { tags: ["graph:step:1"], meta: { langgraph_node: "agent", langgraph_step: 1 } });
907
+ expect(warn.mock.calls.filter((c) => String(c[0]).includes("never saw"))).toHaveLength(1);
908
+ });
909
+
910
+ it("does not warn about orphans on an ordinary graph run", () => {
911
+ resetOrphanWarning();
912
+ const warn = vi.fn();
913
+ setLogger({ debug: vi.fn(), info: vi.fn(), warn, error: vi.fn() });
914
+ root("r", "support");
915
+ node("n1", "r", "agent", 1);
916
+ end("n1");
917
+ end("r");
918
+ expect(warn.mock.calls.filter((c) => String(c[0]).includes("never saw"))).toEqual([]);
919
+ });
920
+
921
+ it("an unusable captureLimit falls back rather than throwing", () => {
922
+ setLogger({ debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() });
923
+ expect(captureLimitOf(undefined)).toBe(core.FIELD_LIMIT);
924
+ expect(captureLimitOf("4096")).toBe(4096);
925
+ for (const bad of [Infinity, Number.NaN, -1, 0, 1.5, "lots", {}]) {
926
+ expect(captureLimitOf(bad)).toBe(core.FIELD_LIMIT);
927
+ }
928
+ });
929
+
930
+ it("reads Python's option names in camelCase, and ignores other adapters' options", () => {
931
+ const options = readOptions({
932
+ sessionId: "s",
933
+ includeChains: "one",
934
+ captureContent: false,
935
+ graphCallbacks: false,
936
+ steps: false,
937
+ });
938
+ expect(options.sessionId).toBe("s");
939
+ expect([...options.includeChains]).toEqual(["one"]);
940
+ expect(options.captureContent).toBe(false);
941
+ expect(options.graphCallbacks).toBe(false);
942
+ expect(readOptions({ includeChains: ["a", "b"] }).includeChains).toEqual(new Set(["a", "b"]));
943
+ });
944
+
945
+ it("uninstall stops recording, even through a handler already handed out", async () => {
946
+ adapter.uninstall();
947
+ modelStart("m", undefined);
948
+ modelEnd("m");
949
+ expect(await events()).toEqual([]);
950
+ });
951
+
952
+ it("asking for the handler again after uninstall records again", async () => {
953
+ adapter.uninstall();
954
+ h = langchainHandler() as Handler;
955
+ modelStart("m", undefined);
956
+ modelEnd("m");
957
+ expect((await events()).map((e) => e.type)).toEqual([
958
+ "agent_start",
959
+ "model_request",
960
+ "model_response",
961
+ "agent_end",
962
+ ]);
963
+ });
964
+
965
+ it("follows strict mode for LangChain's own handler firewall", () => {
966
+ core.setStrict(false);
967
+ expect(h.raiseError).toBe(false);
968
+ core.setStrict(true);
969
+ expect(h.raiseError).toBe(true);
970
+ });
971
+
972
+ it("is awaited, so its events stay in the caller's async context and order", () => {
973
+ expect(h.awaitHandlers).toBe(true);
974
+ });
975
+ });
976
+
977
+ describe("token counts", () => {
978
+ it("prefers usage_metadata, with its detail", () => {
979
+ expect(
980
+ usageOf({
981
+ generations: [[{ message: { usage_metadata: { input_tokens: 3, output_tokens: 4, total_tokens: 7, input_token_details: { cache_read: 1 } } } }]],
982
+ }),
983
+ ).toEqual({ input_tokens: 3, output_tokens: 4, total_tokens: 7, input_token_details: { cache_read: 1 } });
984
+ });
985
+
986
+ it("falls back to llmOutput in both spellings", () => {
987
+ expect(usageOf({ generations: [[{ text: "" }]], llmOutput: { tokenUsage: { promptTokens: 9, completionTokens: 8 } } })).toEqual({
988
+ input_tokens: 9,
989
+ output_tokens: 8,
990
+ total_tokens: 17,
991
+ });
992
+ expect(usageOf({ generations: [], llmOutput: { token_usage: { prompt_tokens: 1, completion_tokens: 2, total_tokens: 3 } } })).toEqual({
993
+ input_tokens: 1,
994
+ output_tokens: 2,
995
+ total_tokens: 3,
996
+ });
997
+ expect(usageOf({ generations: [] })).toBeUndefined();
998
+ });
999
+ });