failproofai 1.0.7-beta.1 → 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 (324) 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/node_modules_posthog-node_dist_entrypoints_index_node_mjs_09z9-p7._.js +1 -1
  62. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  63. package/.next/standalone/.next/server/chunks/src_hooks_18qtd42._.js +1 -1
  64. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04usis8._.js +2 -2
  65. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__056wjo4._.js +2 -2
  66. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0yxwl6j._.js → [root-of-the-server]__0l44ual._.js} +2 -2
  67. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n0xg95._.js +2 -2
  68. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0rwtwpm._.js +2 -2
  69. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s_yomn._.js +2 -2
  70. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11mayhe._.js +2 -2
  71. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1pprgri._.js +2 -2
  72. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1q4p5b8._.js +2 -2
  73. package/.next/standalone/.next/server/chunks/ssr/_042cgl1._.js +1 -1
  74. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  75. package/.next/standalone/.next/server/chunks/ssr/_0bqoto4._.js +1 -1
  76. package/.next/standalone/.next/server/chunks/ssr/{_214wgrp._.js → _1mel6y1._.js} +2 -2
  77. package/.next/standalone/.next/server/chunks/ssr/{_0bn2oo8._.js → _1v-jvrv._.js} +1 -1
  78. package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +1 -1
  79. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +2 -2
  80. package/.next/standalone/.next/server/chunks/ssr/app_actions_get-scheduled-audit_ts_0ei9sni._.js +1 -1
  81. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
  82. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  83. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
  84. package/.next/standalone/.next/server/chunks/ssr/app_settings_02tf1h4._.js +1 -1
  85. package/.next/standalone/.next/server/chunks/ssr/src_hooks_15t8kqj._.js +1 -1
  86. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1fm2w5z._.js +1 -1
  87. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1j0zy3v._.js +1 -1
  88. package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +1 -1
  89. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  90. package/.next/standalone/.next/server/pages/404.html +1 -1
  91. package/.next/standalone/.next/server/pages/500.html +1 -1
  92. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  93. package/.next/standalone/.next/server/server-reference-manifest.json +22 -22
  94. package/.next/standalone/.next/static/chunks/043j99m8ykg__.css +2 -0
  95. package/.next/standalone/.next/static/chunks/0fqd7m_u81mi5.js +1 -0
  96. package/.next/standalone/.next/static/chunks/129ag2bw93bdh.js +1 -0
  97. package/.next/standalone/.next/static/chunks/{29fql3nbnfc9q.js → 1qd741hzlmjbo.js} +1 -1
  98. package/.next/standalone/.next/static/chunks/{0vmd180qfntfb.js → 2_pltstd8-xgs.js} +1 -1
  99. package/.next/standalone/.next/static/chunks/{1u5zsejmgrir_.js → 2c8j9l6j_b1ci.js} +1 -1
  100. package/.next/standalone/.next/static/chunks/3-k569wzcli8q.js +1 -0
  101. package/.next/standalone/.next/static/chunks/{258668t68du6b.js → 3brze37td_wnc.js} +1 -1
  102. package/.next/standalone/.next/static/chunks/3otmypm6j_xfo.js +6 -0
  103. package/.next/standalone/.next/static/chunks/{12tvm75t5ffui.js → 3ugmd_7dyn0id.js} +1 -1
  104. package/.next/standalone/.next/static/chunks/3yxro_r2_o9ad.js +69 -0
  105. package/.next/standalone/PROBE-FOLLOWUP.md +186 -0
  106. package/.next/standalone/app/actions/get-jev-config.ts +38 -23
  107. package/.next/standalone/app/actions/update-jev-config.ts +1 -1
  108. package/.next/standalone/app/settings/jev-panel.tsx +33 -29
  109. package/.next/standalone/package.json +10 -10
  110. package/.next/standalone/sdk/python/skill/SKILL.md +60 -14
  111. package/.next/standalone/sdk/python/skill/agents/openai.yaml +2 -1
  112. package/.next/standalone/sdk/python/skill/references/evaluator.md +255 -0
  113. package/.next/standalone/sdk/python/skill/references/events.md +17 -8
  114. package/.next/standalone/sdk/python/skill/references/frameworks.md +3 -0
  115. package/.next/standalone/sdk/python/skill/references/install.md +3 -0
  116. package/.next/standalone/sdk/python/skill/references/integration.md +6 -2
  117. package/.next/standalone/sdk/python/skill/references/typescript.md +568 -0
  118. package/.next/standalone/sdk/typescript/CHANGELOG.md +119 -0
  119. package/.next/standalone/sdk/typescript/LICENSE +42 -0
  120. package/.next/standalone/sdk/typescript/README.md +552 -0
  121. package/.next/standalone/sdk/typescript/eslint.config.mjs +59 -0
  122. package/.next/standalone/sdk/typescript/examples/research-agent.ts +197 -0
  123. package/.next/standalone/sdk/typescript/integration/ai.test.ts +920 -0
  124. package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/agent.ts +337 -0
  125. package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/package-lock.json +281 -0
  126. package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/package.json +13 -0
  127. package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/surfaces.ts +605 -0
  128. package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/tsconfig.json +12 -0
  129. package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/tsconfig.surfaces.json +4 -0
  130. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/agent.ts +342 -0
  131. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/package-lock.json +168 -0
  132. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/package.json +13 -0
  133. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/surfaces.ts +628 -0
  134. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/tsconfig.json +12 -0
  135. package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/tsconfig.surfaces.json +4 -0
  136. package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/agent.ts +346 -0
  137. package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/package-lock.json +156 -0
  138. package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/package.json +13 -0
  139. package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/surfaces.ts +651 -0
  140. package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/tsconfig.json +12 -0
  141. package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/tsconfig.surfaces.json +4 -0
  142. package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/agent.ts +350 -0
  143. package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/package-lock.json +153 -0
  144. package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/package.json +13 -0
  145. package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/surfaces.ts +651 -0
  146. package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/tsconfig.json +12 -0
  147. package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/tsconfig.surfaces.json +4 -0
  148. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-0.3/agent.ts +623 -0
  149. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-0.3/package-lock.json +463 -0
  150. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-0.3/package.json +15 -0
  151. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-0.3/tsconfig.json +12 -0
  152. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/agent-v1.ts +99 -0
  153. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/agent.ts +623 -0
  154. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/package-lock.json +336 -0
  155. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/package.json +15 -0
  156. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/tsconfig.json +12 -0
  157. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/agent.ts +96 -0
  158. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/package-lock.json +579 -0
  159. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/package.json +15 -0
  160. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/tsconfig.json +12 -0
  161. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/vendor/lc-weather-provider/index.cjs +53 -0
  162. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/vendor/lc-weather-provider/index.mjs +55 -0
  163. package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/vendor/lc-weather-provider/package.json +18 -0
  164. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/agent.ts +659 -0
  165. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/package-lock.json +635 -0
  166. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/package.json +15 -0
  167. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/tsconfig.json +12 -0
  168. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/agent.ts +659 -0
  169. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/package-lock.json +553 -0
  170. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/package.json +15 -0
  171. package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/tsconfig.json +12 -0
  172. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/agent.ts +877 -0
  173. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/mcp-server.mjs +66 -0
  174. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/package-lock.json +6417 -0
  175. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/package.json +15 -0
  176. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/tsconfig.json +12 -0
  177. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/agent.ts +872 -0
  178. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/mcp-server.mjs +66 -0
  179. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/package-lock.json +2540 -0
  180. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/package.json +15 -0
  181. package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/tsconfig.json +12 -0
  182. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/actions.ts +18 -0
  183. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/ai/route.ts +42 -0
  184. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/edge/route.ts +29 -0
  185. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/langgraph/route.ts +21 -0
  186. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/llamaindex/route.ts +11 -0
  187. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/mastra/route.ts +19 -0
  188. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/status/route.ts +7 -0
  189. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/layout.tsx +9 -0
  190. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/page.tsx +15 -0
  191. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/instrumentation.ts +15 -0
  192. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/lib/ai.ts +61 -0
  193. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/lib/langgraph.ts +68 -0
  194. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/lib/llamaindex.ts +98 -0
  195. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/lib/mastra.ts +90 -0
  196. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/next.config.ts +52 -0
  197. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package-lock.json +4343 -0
  198. package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package.json +28 -0
  199. package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/agent.ts +51 -0
  200. package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/deno-npm.ts +76 -0
  201. package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/package-lock.json +484 -0
  202. package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/package.json +15 -0
  203. package/.next/standalone/sdk/typescript/integration/fixtures/types/agent.ts +79 -0
  204. package/.next/standalone/sdk/typescript/integration/fixtures/types/package-lock.json +740 -0
  205. package/.next/standalone/sdk/typescript/integration/fixtures/types/package.json +11 -0
  206. package/.next/standalone/sdk/typescript/integration/fixtures/vanilla/agent.ts +197 -0
  207. package/.next/standalone/sdk/typescript/integration/fixtures/vanilla/package-lock.json +70 -0
  208. package/.next/standalone/sdk/typescript/integration/fixtures/vanilla/package.json +12 -0
  209. package/.next/standalone/sdk/typescript/integration/fixtures/vanilla/tsconfig.json +12 -0
  210. package/.next/standalone/sdk/typescript/integration/global-setup.ts +29 -0
  211. package/.next/standalone/sdk/typescript/integration/harness.ts +451 -0
  212. package/.next/standalone/sdk/typescript/integration/langchain.test.ts +682 -0
  213. package/.next/standalone/sdk/typescript/integration/llamaindex.test.ts +709 -0
  214. package/.next/standalone/sdk/typescript/integration/mastra-coverage.test.ts +386 -0
  215. package/.next/standalone/sdk/typescript/integration/mastra.test.ts +311 -0
  216. package/.next/standalone/sdk/typescript/integration/nextjs.test.ts +341 -0
  217. package/.next/standalone/sdk/typescript/integration/runtime-parity.ts +180 -0
  218. package/.next/standalone/sdk/typescript/integration/runtimes.bun.test.ts +15 -0
  219. package/.next/standalone/sdk/typescript/integration/runtimes.core.test.ts +113 -0
  220. package/.next/standalone/sdk/typescript/integration/runtimes.deno.test.ts +19 -0
  221. package/.next/standalone/sdk/typescript/integration/types.test.ts +141 -0
  222. package/.next/standalone/sdk/typescript/integration/vanilla.test.ts +255 -0
  223. package/.next/standalone/sdk/typescript/package-lock.json +2640 -0
  224. package/.next/standalone/sdk/typescript/package.json +401 -0
  225. package/.next/standalone/sdk/typescript/scripts/finalize-build.mjs +123 -0
  226. package/.next/standalone/sdk/typescript/scripts/release.mjs +177 -0
  227. package/.next/standalone/sdk/typescript/src/clock.ts +58 -0
  228. package/.next/standalone/sdk/typescript/src/context.ts +214 -0
  229. package/.next/standalone/sdk/typescript/src/edge/adapter.ts +18 -0
  230. package/.next/standalone/sdk/typescript/src/edge/ai.ts +116 -0
  231. package/.next/standalone/sdk/typescript/src/edge/index.ts +238 -0
  232. package/.next/standalone/sdk/typescript/src/edge/langchain.ts +18 -0
  233. package/.next/standalone/sdk/typescript/src/edge/llamaindex.ts +12 -0
  234. package/.next/standalone/sdk/typescript/src/edge/mastra.ts +17 -0
  235. package/.next/standalone/sdk/typescript/src/edge/notice.ts +33 -0
  236. package/.next/standalone/sdk/typescript/src/environment.ts +75 -0
  237. package/.next/standalone/sdk/typescript/src/evaluator/authoring.ts +480 -0
  238. package/.next/standalone/sdk/typescript/src/evaluator/cli.ts +96 -0
  239. package/.next/standalone/sdk/typescript/src/evaluator/client.ts +421 -0
  240. package/.next/standalone/sdk/typescript/src/evaluator/expression.ts +1292 -0
  241. package/.next/standalone/sdk/typescript/src/evaluator/index.ts +144 -0
  242. package/.next/standalone/sdk/typescript/src/evaluator/protocol.ts +747 -0
  243. package/.next/standalone/sdk/typescript/src/evaluator/runtime.ts +930 -0
  244. package/.next/standalone/sdk/typescript/src/evaluator/sandbox-worker.ts +171 -0
  245. package/.next/standalone/sdk/typescript/src/evaluator/source-limits.ts +27 -0
  246. package/.next/standalone/sdk/typescript/src/evaluator/source.ts +509 -0
  247. package/.next/standalone/sdk/typescript/src/events.ts +879 -0
  248. package/.next/standalone/sdk/typescript/src/exit.ts +117 -0
  249. package/.next/standalone/sdk/typescript/src/index.ts +186 -0
  250. package/.next/standalone/sdk/typescript/src/integrations/ai.ts +1566 -0
  251. package/.next/standalone/sdk/typescript/src/integrations/compat.ts +322 -0
  252. package/.next/standalone/sdk/typescript/src/integrations/core.ts +1321 -0
  253. package/.next/standalone/sdk/typescript/src/integrations/index.ts +355 -0
  254. package/.next/standalone/sdk/typescript/src/integrations/langchain.ts +2340 -0
  255. package/.next/standalone/sdk/typescript/src/integrations/llamaindex.ts +2111 -0
  256. package/.next/standalone/sdk/typescript/src/integrations/mastra.ts +1802 -0
  257. package/.next/standalone/sdk/typescript/src/logger.ts +98 -0
  258. package/.next/standalone/sdk/typescript/src/next.ts +115 -0
  259. package/.next/standalone/sdk/typescript/src/node-require.ts +446 -0
  260. package/.next/standalone/sdk/typescript/src/redact.ts +305 -0
  261. package/.next/standalone/sdk/typescript/src/resolver.ts +120 -0
  262. package/.next/standalone/sdk/typescript/src/runtime.ts +29 -0
  263. package/.next/standalone/sdk/typescript/src/schema.ts +410 -0
  264. package/.next/standalone/sdk/typescript/src/scopes.ts +701 -0
  265. package/.next/standalone/sdk/typescript/src/shared.ts +33 -0
  266. package/.next/standalone/sdk/typescript/src/version.ts +5 -0
  267. package/.next/standalone/sdk/typescript/src/writer.ts +934 -0
  268. package/.next/standalone/sdk/typescript/test/adapters.test.ts +397 -0
  269. package/.next/standalone/sdk/typescript/test/ai.test.ts +1076 -0
  270. package/.next/standalone/sdk/typescript/test/copies.test.ts +204 -0
  271. package/.next/standalone/sdk/typescript/test/edge.test.ts +183 -0
  272. package/.next/standalone/sdk/typescript/test/evaluator-client.test.ts +234 -0
  273. package/.next/standalone/sdk/typescript/test/evaluator-protocol.test.ts +225 -0
  274. package/.next/standalone/sdk/typescript/test/events.test.ts +193 -0
  275. package/.next/standalone/sdk/typescript/test/expression.test.ts +181 -0
  276. package/.next/standalone/sdk/typescript/test/global-setup.ts +26 -0
  277. package/.next/standalone/sdk/typescript/test/helpers.ts +130 -0
  278. package/.next/standalone/sdk/typescript/test/integrations.test.ts +369 -0
  279. package/.next/standalone/sdk/typescript/test/langchain-copies.test.ts +204 -0
  280. package/.next/standalone/sdk/typescript/test/langchain.test.ts +999 -0
  281. package/.next/standalone/sdk/typescript/test/llamaindex.test.ts +1760 -0
  282. package/.next/standalone/sdk/typescript/test/mastra-coverage.test.ts +501 -0
  283. package/.next/standalone/sdk/typescript/test/mastra-lifecycle.test.ts +479 -0
  284. package/.next/standalone/sdk/typescript/test/mastra.test.ts +285 -0
  285. package/.next/standalone/sdk/typescript/test/next.test.ts +109 -0
  286. package/.next/standalone/sdk/typescript/test/packaging.test.ts +312 -0
  287. package/.next/standalone/sdk/typescript/test/redaction.test.ts +171 -0
  288. package/.next/standalone/sdk/typescript/test/runtimes.test.ts +101 -0
  289. package/.next/standalone/sdk/typescript/test/sandbox.test.ts +189 -0
  290. package/.next/standalone/sdk/typescript/test/scopes.test.ts +271 -0
  291. package/.next/standalone/sdk/typescript/test/setup.ts +19 -0
  292. package/.next/standalone/sdk/typescript/test/skill-snippets.test.ts +73 -0
  293. package/.next/standalone/sdk/typescript/test/spool-contract.test.ts +124 -0
  294. package/.next/standalone/sdk/typescript/test/tracker-bounds.test.ts +191 -0
  295. package/.next/standalone/sdk/typescript/test/wire-format.test.ts +214 -0
  296. package/.next/standalone/sdk/typescript/test/writer.test.ts +407 -0
  297. package/.next/standalone/sdk/typescript/tsconfig.build.json +15 -0
  298. package/.next/standalone/sdk/typescript/tsconfig.cjs.json +19 -0
  299. package/.next/standalone/sdk/typescript/tsconfig.json +28 -0
  300. package/.next/standalone/sdk/typescript/vitest.config.ts +33 -0
  301. package/.next/standalone/sdk/typescript/vitest.integration.config.ts +23 -0
  302. package/.next/standalone/server.js +1 -1
  303. package/README.md +2 -2
  304. package/dist/cli.mjs +208 -27
  305. package/dist/worker.mjs +120 -14
  306. package/package.json +10 -10
  307. package/scripts/build-policy-pack.mjs +14 -0
  308. package/src/audit/features.ts +3 -2
  309. package/src/hooks/builtin-policies.ts +156 -5
  310. package/src/hooks/jev-cli.ts +57 -1
  311. package/src/hooks/manager.ts +1 -1
  312. package/src/hooks/pack-cli.ts +150 -18
  313. package/src/hooks/pack-store.ts +1 -1
  314. package/src/hooks/policy-catalog.ts +148 -9
  315. package/src/hooks/types.ts +1 -1
  316. package/.next/standalone/.next/static/chunks/0cd-_8-c-m1ea.js +0 -6
  317. package/.next/standalone/.next/static/chunks/0qrbdkv9qmvli.js +0 -69
  318. package/.next/standalone/.next/static/chunks/0uldbut9y2-e8.js +0 -1
  319. package/.next/standalone/.next/static/chunks/285spx855h_3r.css +0 -2
  320. package/.next/standalone/.next/static/chunks/2vkvu9-opa_1z.js +0 -1
  321. package/.next/standalone/.next/static/chunks/37lhv7wa3ywt6.js +0 -1
  322. /package/.next/standalone/.next/static/{T8YAYM9h_64fKv705vug7 → gbEOjBgZAxF2UIUwZVHNu}/_buildManifest.js +0 -0
  323. /package/.next/standalone/.next/static/{T8YAYM9h_64fKv705vug7 → gbEOjBgZAxF2UIUwZVHNu}/_clientMiddlewareManifest.js +0 -0
  324. /package/.next/standalone/.next/static/{T8YAYM9h_64fKv705vug7 → gbEOjBgZAxF2UIUwZVHNu}/_ssgManifest.js +0 -0
@@ -0,0 +1,189 @@
1
+ import { describe, expect, it } from "vitest";
2
+
3
+ import { EvalResult, Score } from "../src/evaluator/authoring.js";
4
+ import { sessionTranscriptFromWire } from "../src/evaluator/protocol.js";
5
+ import {
6
+ EvaluationSandboxUnavailable,
7
+ EvaluationTimeout,
8
+ UnsafeEvaluatorSource,
9
+ compileCondition,
10
+ compileEvaluator,
11
+ sourceChecksum,
12
+ } from "../src/evaluator/source.js";
13
+ import { transcriptWire } from "./helpers.js";
14
+
15
+ /**
16
+ * The `worker_threads` sandbox, exercised for real.
17
+ *
18
+ * It is not the correctness boundary — `expression.ts` is — but it is the only
19
+ * thing that bounds CPU, heap and wall clock, and the only thing that can KILL
20
+ * a running evaluation. Every one of these cases is a way a permitted
21
+ * expression could otherwise take the worker down with it.
22
+ */
23
+
24
+ const session = sessionTranscriptFromWire(
25
+ transcriptWire([
26
+ { type: "tool_use", payload: { tool_name: "search" } },
27
+ { type: "tool_result", payload: { error: "timeout" } },
28
+ { type: "tool_result", payload: { output: "ok" } },
29
+ ]),
30
+ );
31
+
32
+ describe("running a managed evaluation", () => {
33
+ it("returns a rebuilt EvalResult from the worker", async () => {
34
+ const evaluate = compileEvaluator(
35
+ "EvalResult({ score: Score(1 - session.eventsOfType('tool_result')" +
36
+ ".filter(e => e.payload.error != null).length / session.count('tool_result')), " +
37
+ "reasoning: `saw ${session.eventCount} events` })",
38
+ { evalKey: "tool_success_rate" },
39
+ );
40
+ const result = await evaluate(session);
41
+ expect(result).toBeInstanceOf(EvalResult);
42
+ expect(result.score).toBeInstanceOf(Score);
43
+ expect(result.score!.value).toBe(0.5);
44
+ expect(result.reasoning).toBe("saw 3 events");
45
+ // The rebuilt result is a real one, so the authoring bounds apply to it.
46
+ expect(result.resultItems("tool_success_rate")).toHaveLength(1);
47
+ });
48
+
49
+ it("runs a managed condition in the same sandbox", async () => {
50
+ expect(await compileCondition("session.count('tool_use') > 0")(session)).toBe(true);
51
+ const structured = await compileCondition("ConditionResult(false, 'no_tools')")(session);
52
+ expect(structured).toMatchObject({ applicable: false, reasonCode: "no_tools" });
53
+ });
54
+
55
+ it("carries a metric and an assertion across the boundary", async () => {
56
+ const evaluate = compileEvaluator(
57
+ "EvalResult({ metrics: { tool_calls: Metric(session.count('tool_use'), { unit: 'count' }) }, " +
58
+ "assertions: { used_a_tool: Assertion(session.count('tool_use') > 0) } })",
59
+ { evalKey: "tool_calls" },
60
+ );
61
+ const result = await evaluate(session);
62
+ const items = result.resultItems("tool_calls");
63
+ expect(items.map((item) => [item.resultKey, item.resultKind, item.numericValue ?? item.boolValue])).toEqual([
64
+ ["tool_calls", "metric", 1],
65
+ ["used_a_tool", "assertion", true],
66
+ ]);
67
+ });
68
+ });
69
+
70
+ describe("failures come back as data, not as a crash", () => {
71
+ it("preserves the error's name across the worker boundary", async () => {
72
+ const evaluate = compileEvaluator("EvalResult({ score: Score(session.nope.deeper) })");
73
+ await expect(evaluate(session)).rejects.toThrow(TypeError);
74
+ });
75
+
76
+ it("reports a result that is not an EvalResult", async () => {
77
+ await expect(compileEvaluator("42")(session)).rejects.toThrow(/must return an EvalResult/);
78
+ });
79
+
80
+ it("reports a condition that is not a boolean or a ConditionResult", async () => {
81
+ await expect(compileCondition("42")(session)).rejects.toThrow(
82
+ /must return a boolean or a ConditionResult/,
83
+ );
84
+ });
85
+
86
+ it("rejects unsafe source BEFORE a worker is started", () => {
87
+ // Compilation is synchronous and happens in the parent, so a poison
88
+ // definition costs nothing and dead-letters as one failed run.
89
+ expect(() => compileEvaluator("(x => x).constructor")).toThrow(UnsafeEvaluatorSource);
90
+ });
91
+ });
92
+
93
+ describe("resource bounds", () => {
94
+ it("kills an evaluation that overruns its wall clock", async () => {
95
+ // Under the step ceiling this would run for a very long time; the worker is
96
+ // terminated either way, and both arrive as an EvaluationTimeout.
97
+ const evaluate = compileEvaluator(
98
+ "EvalResult({ score: Score(Array.from({ length: 1 }).length) })",
99
+ { timeoutSeconds: 0.001 },
100
+ );
101
+ await expect(evaluate(session)).rejects.toThrow(EvaluationTimeout);
102
+ }, 20_000);
103
+
104
+ it("bounds an unbounded recursion inside the worker", async () => {
105
+ const evaluate = compileEvaluator("(f => f(f))(f => f(f))", { timeoutSeconds: 10 });
106
+ await expect(evaluate(session)).rejects.toThrow(EvaluationTimeout);
107
+ }, 30_000);
108
+
109
+ it("refuses to evaluate at all when the sandbox cannot be started", async () => {
110
+ // Fails CLOSED. An evaluation that cannot be terminated is not one we are
111
+ // willing to start, so an unusable sandbox is a refusal — never a fallback
112
+ // to running tenant source in the worker's own thread.
113
+ const previous = process.env.FAILPROOFAI_SDK_SANDBOX_WORKER;
114
+ process.env.FAILPROOFAI_SDK_SANDBOX_WORKER = "/nonexistent/failproofai-sandbox-worker.js";
115
+ try {
116
+ const evaluate = compileEvaluator("EvalResult({ score: Score(1) })");
117
+ await expect(evaluate(session)).rejects.toThrow();
118
+ // And specifically NOT by quietly returning a result.
119
+ await expect(evaluate(session)).rejects.not.toBeInstanceOf(EvalResult);
120
+ } finally {
121
+ process.env.FAILPROOFAI_SDK_SANDBOX_WORKER = previous;
122
+ }
123
+ });
124
+
125
+ it("names the override when it cannot locate the worker at all", () => {
126
+ // `EvaluationSandboxUnavailable` carries the remedy, because the situation
127
+ // it describes — a bundled install whose published layout is gone — is one
128
+ // the operator can only fix if they are told which variable to set.
129
+ const error = new EvaluationSandboxUnavailable("x");
130
+ expect(error.name).toBe("EvaluationSandboxUnavailable");
131
+ });
132
+
133
+ it("clamps a server-supplied timeout to the ceiling", async () => {
134
+ // A large `timeout_seconds` must not be able to remove the bound. The
135
+ // evaluation itself is instant; what matters is that it still completes,
136
+ // i.e. the clamp did not turn a huge number into an invalid one.
137
+ const evaluate = compileEvaluator("EvalResult({ score: Score(1) })", {
138
+ timeoutSeconds: 86_400,
139
+ });
140
+ await expect(evaluate(session)).resolves.toBeInstanceOf(EvalResult);
141
+ });
142
+ });
143
+
144
+ describe("isolation", () => {
145
+ it("gives the worker no environment to read", async () => {
146
+ // The language cannot reach `process` at all, so this is defence in depth —
147
+ // it means a future gap could not be escalated into credential theft.
148
+ const previous = process.env.FAILPROOFAI_EVALUATOR_TOKEN;
149
+ process.env.FAILPROOFAI_EVALUATOR_TOKEN = "a-cross-tenant-credential";
150
+ try {
151
+ expect(() => compileEvaluator("process.env")).toThrow(UnsafeEvaluatorSource);
152
+ expect(() => compileEvaluator("Object.keys(process.env)")).toThrow(UnsafeEvaluatorSource);
153
+ } finally {
154
+ if (previous === undefined) delete process.env.FAILPROOFAI_EVALUATOR_TOKEN;
155
+ else process.env.FAILPROOFAI_EVALUATOR_TOKEN = previous;
156
+ }
157
+ });
158
+
159
+ it("does not let one evaluation see another's state", async () => {
160
+ const first = compileEvaluator("EvalResult({ score: Score(0.25) })");
161
+ const second = compileEvaluator("EvalResult({ score: Score(0.75) })");
162
+ const [a, b] = await Promise.all([first(session), second(session)]);
163
+ expect(a.score!.value).toBe(0.25);
164
+ expect(b.score!.value).toBe(0.75);
165
+ });
166
+
167
+ it("runs more evaluations than the concurrency cap without losing any", async () => {
168
+ // The semaphore bounds how many sandboxes exist at once; the extras queue
169
+ // rather than pile up memory, and every one still returns.
170
+ const results = await Promise.all(
171
+ Array.from({ length: 8 }, (_, index) =>
172
+ compileEvaluator(`EvalResult({ score: Score(${(index / 10).toFixed(1)}) })`)(session),
173
+ ),
174
+ );
175
+ expect(results.map((result) => result.score!.value)).toEqual([
176
+ 0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7,
177
+ ]);
178
+ }, 30_000);
179
+ });
180
+
181
+ describe("sourceChecksum", () => {
182
+ it("covers the condition and the evaluator together, separated unambiguously", () => {
183
+ // A separator that could appear in either source would let two different
184
+ // pairs hash the same, which is what the checksum exists to prevent.
185
+ expect(sourceChecksum("a", "b")).not.toBe(sourceChecksum("ab", ""));
186
+ expect(sourceChecksum(null, "b")).toBe(sourceChecksum("", "b"));
187
+ expect(sourceChecksum("a", "b")).toMatch(/^sha256:[0-9a-f]{64}$/);
188
+ });
189
+ });
@@ -0,0 +1,271 @@
1
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
2
+
3
+ import { current, propagate } from "../src/context.js";
4
+ import { agent, session, toolCall } from "../src/scopes.js";
5
+ import { flushed, useSpool } from "./helpers.js";
6
+ import type { Spool } from "./helpers.js";
7
+
8
+ let spool: Spool;
9
+
10
+ beforeEach(() => {
11
+ spool = useSpool();
12
+ });
13
+ afterEach(async () => {
14
+ await spool.cleanup();
15
+ });
16
+
17
+ const typesOf = (events: Array<Record<string, unknown>>): string[] =>
18
+ events.map((event) => String(event.type));
19
+
20
+ describe("session", () => {
21
+ it("binds identity and emits nothing on its own", async () => {
22
+ const id = await session(async (sessionId) => {
23
+ expect(current().sessionId).toBe(sessionId);
24
+ return sessionId;
25
+ });
26
+ expect(id).toMatch(/^[0-9a-f]{32}$/);
27
+ expect(await flushed(spool)).toEqual([]);
28
+ });
29
+
30
+ it("inherits an already-bound session rather than splitting the run in two", async () => {
31
+ await session({ sessionId: "outer" }, async () => {
32
+ await session(async (inner) => {
33
+ expect(inner).toBe("outer");
34
+ });
35
+ });
36
+ });
37
+
38
+ it("unbinds on the way out", async () => {
39
+ await session({ sessionId: "s" }, () => undefined);
40
+ expect(current().sessionId).toBeNull();
41
+ });
42
+ });
43
+
44
+ describe("agent", () => {
45
+ it("brackets the block with agent_start and agent_end", async () => {
46
+ await agent("planner", { goal: "g" }, () => undefined);
47
+ const events = await flushed(spool);
48
+ expect(typesOf(events)).toEqual(["agent_start", "agent_end"]);
49
+ expect(events[0]!.goal).toBe("g");
50
+ expect(events[1]!.outcome).toBe("success");
51
+ });
52
+
53
+ it("emits error BEFORE agent_end, and marks the outcome 'failed' not 'failure'", async () => {
54
+ await expect(
55
+ agent("planner", async () => {
56
+ throw new TypeError("boom");
57
+ }),
58
+ ).rejects.toThrow("boom");
59
+
60
+ const events = await flushed(spool);
61
+ expect(typesOf(events)).toEqual(["agent_start", "error", "agent_end"]);
62
+ expect(events[1]!.error_type).toBe("TypeError");
63
+ expect(events[1]!.message).toBe("boom");
64
+ expect(typeof events[1]!.traceback).toBe("string");
65
+ // The server only counts error|failed|timeout|rejected as a failure.
66
+ expect(events[2]!.outcome).toBe("failed");
67
+ });
68
+
69
+ it("names the error by its class when a subclass leaves `name` as 'Error'", async () => {
70
+ // openai's BadRequestError (and many SDKs' errors) never set `name`, so
71
+ // `error.name` reads "Error" and the class was lost from the Errors surface.
72
+ class BadRequestError extends Error {}
73
+ await expect(
74
+ agent("planner", async () => {
75
+ await toolCall("t", () => {
76
+ throw new BadRequestError("model does not exist");
77
+ });
78
+ }),
79
+ ).rejects.toThrow("model does not exist");
80
+ const events = await flushed(spool);
81
+ expect(events.find((e) => e.type === "tool_result")!.error).toBe("BadRequestError: model does not exist");
82
+ expect(events.find((e) => e.type === "error")!.error_type).toBe("BadRequestError");
83
+ });
84
+
85
+ it("treats an AbortError as cancellation: no error event, outcome 'cancelled'", async () => {
86
+ const abort = new Error("stopped");
87
+ abort.name = "AbortError";
88
+ await expect(
89
+ agent("planner", async () => {
90
+ throw abort;
91
+ }),
92
+ ).rejects.toThrow("stopped");
93
+
94
+ const events = await flushed(spool);
95
+ expect(typesOf(events)).toEqual(["agent_start", "agent_end"]);
96
+ expect(events[1]!.outcome).toBe("cancelled");
97
+ });
98
+
99
+ it("nests, with parent_id taken from the enclosing agent", async () => {
100
+ await agent("supervisor", async () => {
101
+ await agent("worker", () => undefined);
102
+ });
103
+ const starts = (await flushed(spool)).filter((event) => event.type === "agent_start");
104
+ expect(starts[0]!.parent_id).toBeUndefined();
105
+ expect(starts[1]!.agent_id).toBe("worker");
106
+ expect(starts[1]!.parent_id).toBe("supervisor");
107
+ });
108
+
109
+ it("does NOT inherit a parent across an explicit new session", async () => {
110
+ // The span tree is keyed by session, so a cross-session parent would render
111
+ // as a dangling reference or get grafted onto an unrelated agent.
112
+ await agent("server", { sessionId: "boot" }, async () => {
113
+ await agent("handler", { sessionId: "request-1" }, () => undefined);
114
+ });
115
+ const handler = (await flushed(spool)).find(
116
+ (event) => event.type === "agent_start" && event.agent_id === "handler",
117
+ )!;
118
+ expect(handler.session_id).toBe("request-1");
119
+ expect(handler.parent_id).toBeUndefined();
120
+ });
121
+
122
+ it("honours an explicit parentId of null as a forced root", async () => {
123
+ await agent("outer", async () => {
124
+ await agent("inner", { parentId: null }, () => undefined);
125
+ });
126
+ const inner = (await flushed(spool)).find(
127
+ (event) => event.type === "agent_start" && event.agent_id === "inner",
128
+ )!;
129
+ expect(inner.parent_id).toBeUndefined();
130
+ });
131
+
132
+ it("stays synchronous for a synchronous body", () => {
133
+ const value = agent("sync", () => 42);
134
+ expect(value).toBe(42);
135
+ });
136
+
137
+ it("leaves no frame behind when agent_start itself throws", () => {
138
+ expect(() => agent("bad", { type: "reserved" }, () => undefined)).toThrow(/Reserved field/);
139
+ expect(current().sessionId).toBeNull();
140
+ expect(current().depth).toBe(0);
141
+ });
142
+ });
143
+
144
+ describe("toolCall", () => {
145
+ it("records the body's resolved value as the output", async () => {
146
+ await session({ sessionId: "s" }, async () => {
147
+ const hits = await toolCall("search", { input: { q: "x" } }, async () => ["a", "b"]);
148
+ expect(hits).toEqual(["a", "b"]);
149
+ });
150
+ const result = (await flushed(spool)).find((event) => event.type === "tool_result")!;
151
+ expect(result.output).toEqual(["a", "b"]);
152
+ expect(result.tool_name).toBe("search");
153
+ });
154
+
155
+ it("prefers an explicitly assigned output over the return value", async () => {
156
+ await session({ sessionId: "s" }, async () => {
157
+ await toolCall("search", async (call) => {
158
+ call.output = { chosen: true };
159
+ return "ignored";
160
+ });
161
+ });
162
+ const result = (await flushed(spool)).find((event) => event.type === "tool_result")!;
163
+ expect(result.output).toEqual({ chosen: true });
164
+ });
165
+
166
+ it("records a failure on the leaf and emits NO error event", async () => {
167
+ await session({ sessionId: "s" }, async () => {
168
+ await expect(
169
+ toolCall("search", async () => {
170
+ throw new RangeError("nope");
171
+ }),
172
+ ).rejects.toThrow("nope");
173
+ });
174
+ const events = await flushed(spool);
175
+ expect(typesOf(events)).toEqual(["tool_use", "tool_result"]);
176
+ expect(events[1]!.error).toBe("RangeError: nope");
177
+ });
178
+
179
+ it("closes a cancelled tool call with no error string", async () => {
180
+ const abort = new Error("cancelled");
181
+ abort.name = "AbortError";
182
+ await session({ sessionId: "s" }, async () => {
183
+ await expect(
184
+ toolCall("search", async () => {
185
+ throw abort;
186
+ }),
187
+ ).rejects.toThrow();
188
+ });
189
+ const result = (await flushed(spool)).find((event) => event.type === "tool_result")!;
190
+ expect("error" in result).toBe(false);
191
+ });
192
+
193
+ it("resolves identity once, at entry, so a nested scope cannot move the result", async () => {
194
+ await agent("outer", async () => {
195
+ await toolCall("search", async () => {
196
+ await agent("inner", () => undefined);
197
+ });
198
+ });
199
+ const result = (await flushed(spool)).find((event) => event.type === "tool_result")!;
200
+ expect(result.agent_id).toBe("outer");
201
+ });
202
+ });
203
+
204
+ describe("using-style scopes", () => {
205
+ it("emits the same events as the callback form", async () => {
206
+ {
207
+ using span = agent.open("planner", { goal: "g" });
208
+ expect(span.agentId).toBe("planner");
209
+ using call = toolCall.open("search", { input: { q: "x" } });
210
+ call.call.output = "done";
211
+ }
212
+ const events = await flushed(spool);
213
+ expect(typesOf(events)).toEqual(["agent_start", "tool_use", "tool_result", "agent_end"]);
214
+ expect(events[2]!.output).toBe("done");
215
+ expect(events[3]!.outcome).toBe("success");
216
+ expect(current().sessionId).toBeNull();
217
+ });
218
+
219
+ it("records a failure the block caught, via fail()", async () => {
220
+ {
221
+ using span = agent.open("planner");
222
+ span.fail(new Error("handled"));
223
+ }
224
+ const events = await flushed(spool);
225
+ expect(events.at(-1)!.outcome).toBe("failed");
226
+ });
227
+ });
228
+
229
+ describe("propagate", () => {
230
+ it("carries identity into a callback invoked outside the scope", async () => {
231
+ let stored: (() => void) | null = null;
232
+ await session({ sessionId: "s1" }, async () => {
233
+ await agent("planner", () => {
234
+ stored = propagate(() => {
235
+ expect(current().sessionId).toBe("s1");
236
+ expect(current().agentId).toBe("planner");
237
+ });
238
+ });
239
+ });
240
+ expect(current().sessionId).toBeNull();
241
+ stored!();
242
+ });
243
+
244
+ it("binds the same identity on every invocation, not the previous call's leftovers", async () => {
245
+ const seen: Array<string | null> = [];
246
+ const wrapped = await session({ sessionId: "s1" }, () =>
247
+ propagate(() => {
248
+ seen.push(current().sessionId);
249
+ }),
250
+ );
251
+ wrapped();
252
+ wrapped();
253
+ expect(seen).toEqual(["s1", "s1"]);
254
+ });
255
+ });
256
+
257
+ describe("concurrency", () => {
258
+ it("keeps two concurrent runs on separate identities", async () => {
259
+ await Promise.all([
260
+ agent("a", { sessionId: "sa" }, async () => {
261
+ await new Promise((resolve) => setTimeout(resolve, 5));
262
+ expect(current().sessionId).toBe("sa");
263
+ }),
264
+ agent("b", { sessionId: "sb" }, async () => {
265
+ expect(current().sessionId).toBe("sb");
266
+ }),
267
+ ]);
268
+ const starts = (await flushed(spool)).filter((event) => event.type === "agent_start");
269
+ expect(new Set(starts.map((event) => event.session_id))).toEqual(new Set(["sa", "sb"]));
270
+ });
271
+ });
@@ -0,0 +1,19 @@
1
+ import { afterAll } from "vitest";
2
+
3
+ import { runtime } from "../src/runtime.js";
4
+
5
+ /**
6
+ * Close the process-wide writer when a test FILE finishes.
7
+ *
8
+ * Vitest gives each file a fresh module registry but one process, so every file
9
+ * that touches `runtime.ts` builds another writer with another flush timer and
10
+ * another `exit` listener. Left open they accumulate across the run, Node warns
11
+ * about the listener count, and the last file's assertions race timers the
12
+ * first file started.
13
+ *
14
+ * `close()` is the API the writer already exposes for exactly this.
15
+ */
16
+ afterAll(async () => {
17
+ await runtime.writer.flushNow();
18
+ runtime.writer.close();
19
+ });
@@ -0,0 +1,73 @@
1
+ import { readdirSync, readFileSync, statSync } from "node:fs";
2
+ import { join, relative } from "node:path";
3
+
4
+ import ts from "typescript";
5
+ import { describe, expect, it } from "vitest";
6
+
7
+ import * as failproofai from "../src/index.js";
8
+ import * as evaluator from "../src/evaluator/index.js";
9
+
10
+ /**
11
+ * The `failproofai-sdk` skill teaches this package too, and its TypeScript blocks
12
+ * are instructions an agent copies into someone's real agent loop — code under
13
+ * test, like the Python blocks `sdk/python/tests/test_skill_snippets.py` guards.
14
+ *
15
+ * Two checks, both cheap and both aimed at drift rather than style: every
16
+ * ```ts block parses, and every SDK name a block calls — `failproofai.x`,
17
+ * `failproofai.event.x`, a named import from `@failproofai/sdk/evaluator` —
18
+ * still exists. A rename in `src/` otherwise leaves the skill teaching a call
19
+ * that throws `is not a function` in the customer's process.
20
+ */
21
+
22
+ const SKILL = join(__dirname, "..", "..", "python", "skill");
23
+
24
+ function markdownFiles(dir: string): string[] {
25
+ return readdirSync(dir).flatMap((name) => {
26
+ const path = join(dir, name);
27
+ if (statSync(path).isDirectory()) return markdownFiles(path);
28
+ return name.endsWith(".md") ? [path] : [];
29
+ });
30
+ }
31
+
32
+ function tsBlocks(path: string): string[] {
33
+ const text = readFileSync(path, "utf8");
34
+ return [...text.matchAll(/```(?:ts|typescript)[^\n]*\n([\s\S]*?)```/g)].map((m) => m[1]!);
35
+ }
36
+
37
+ const FILES = markdownFiles(SKILL).filter((path) => tsBlocks(path).length > 0);
38
+ const BLOCKS = FILES.flatMap((path) =>
39
+ tsBlocks(path).map((code, index) => ({ id: `${relative(SKILL, path)} #${index}`, code })),
40
+ );
41
+
42
+ describe("the failproofai-sdk skill's TypeScript snippets", () => {
43
+ it("has snippets to check (a path typo would make every test below vacuous)", () => {
44
+ expect(BLOCKS.length).toBeGreaterThanOrEqual(8);
45
+ });
46
+
47
+ it.each(BLOCKS)("$id parses", ({ code }) => {
48
+ const out = ts.transpileModule(code, {
49
+ reportDiagnostics: true,
50
+ compilerOptions: { module: ts.ModuleKind.ESNext, target: ts.ScriptTarget.ES2022 },
51
+ });
52
+ const errors = (out.diagnostics ?? []).map((d) => ts.flattenDiagnosticMessageText(d.messageText, "\n"));
53
+ expect(errors).toEqual([]);
54
+ });
55
+
56
+ it.each(BLOCKS)("$id calls only names the SDK exports", ({ code }) => {
57
+ const missing: string[] = [];
58
+ for (const [, name] of code.matchAll(/\bfailproofai\.(?!event\.)(\w+)/g)) {
59
+ if (!(name! in failproofai)) missing.push(`failproofai.${name}`);
60
+ }
61
+ for (const [, name] of code.matchAll(/\bfailproofai\.event\.(\w+)/g)) {
62
+ if (typeof (failproofai.event as unknown as Record<string, unknown>)[name!] !== "function") {
63
+ missing.push(`failproofai.event.${name}`);
64
+ }
65
+ }
66
+ for (const [, names] of code.matchAll(/import\s*\{([^}]*)\}\s*from\s*"@failproofai\/sdk\/evaluator"/g)) {
67
+ for (const name of names!.split(",").map((n) => n.trim()).filter(Boolean)) {
68
+ if (!(name in evaluator)) missing.push(`@failproofai/sdk/evaluator: ${name}`);
69
+ }
70
+ }
71
+ expect(missing).toEqual([]);
72
+ });
73
+ });
@@ -0,0 +1,124 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { dirname, join, resolve } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+
6
+ import { afterEach, describe, expect, it } from "vitest";
7
+
8
+ import {
9
+ expandUser,
10
+ failproofaiCustomAgentsDir,
11
+ getBaseDir,
12
+ legacyAgenteyeDir,
13
+ setBaseDir,
14
+ } from "../src/resolver.js";
15
+
16
+ /**
17
+ * Four implementations resolve where this SDK's spool lives, and they must
18
+ * agree or the SDK writes where no daemon reads — with NO error on either side,
19
+ * which is the whole reason this file exists:
20
+ *
21
+ * * this package's `resolver.ts`
22
+ * * the Python SDK's `failproofai_sdk/_resolver.py`
23
+ * * the daemon's `crates/fpai-collect/src/config.rs`
24
+ * * the CLI's `src/hooks/fp-home.ts`
25
+ *
26
+ * These assertions read the OTHER THREE from disk rather than restating them.
27
+ * A test that spelled the path out a fifth time would pass while the daemon
28
+ * watched somewhere else.
29
+ */
30
+
31
+ const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../../..");
32
+
33
+ function read(relative: string): string {
34
+ return readFileSync(join(repoRoot, relative), "utf8");
35
+ }
36
+
37
+ afterEach(() => {
38
+ setBaseDir(null);
39
+ });
40
+
41
+ describe("agreement with the other implementations", () => {
42
+ it("matches the daemon's custom_agents_events_dir", () => {
43
+ const rust = read("crates/fpai-collect/src/config.rs");
44
+ // `home.join("custom-agents").join("events")`
45
+ expect(rust).toMatch(/\.join\("custom-agents"\)\s*\.join\("events"\)/);
46
+ expect(join(failproofaiCustomAgentsDir(), "events")).toBe(
47
+ join(homedir(), ".failproofai", "custom-agents", "events"),
48
+ );
49
+ });
50
+
51
+ it("matches the CLI's customAgentsDir", () => {
52
+ const hooks = read("src/hooks/fp-home.ts");
53
+ expect(hooks).toContain('atHome(home, "custom-agents")');
54
+ expect(hooks).toMatch(/process\.env\.FAILPROOFAI_HOME\s*\|\|\s*resolve\(homedir\(\), "\.failproofai"\)/);
55
+ });
56
+
57
+ it("matches the Python SDK's resolver", () => {
58
+ const python = read("sdk/python/failproofai_sdk/_resolver.py");
59
+ expect(python).toContain('base / "custom-agents"');
60
+ expect(python).toContain('os.environ.get("FAILPROOFAI_HOME")');
61
+ });
62
+
63
+ it("keeps the daemon watching the legacy root, so an older SDK is not stranded", () => {
64
+ const rust = read("crates/fpai-collect/src/config.rs");
65
+ expect(rust).toContain("agenteye_events_dir()");
66
+ expect(legacyAgenteyeDir()).toBe(join(homedir(), ".agenteye"));
67
+ });
68
+ });
69
+
70
+ describe("resolution order", () => {
71
+ it("prefers an explicit base directory over everything", () => {
72
+ setBaseDir("/tmp/somewhere-explicit");
73
+ expect(getBaseDir()).toBe("/tmp/somewhere-explicit");
74
+ });
75
+
76
+ it("moves with FAILPROOFAI_HOME but never leaves it", () => {
77
+ const previous = process.env.FAILPROOFAI_HOME;
78
+ process.env.FAILPROOFAI_HOME = "/opt/fp";
79
+ try {
80
+ // The `custom-agents` segment is appended unconditionally: the variable
81
+ // MOVES the umbrella, it cannot take the spool outside it.
82
+ expect(failproofaiCustomAgentsDir()).toBe(join("/opt/fp", "custom-agents"));
83
+ } finally {
84
+ if (previous === undefined) delete process.env.FAILPROOFAI_HOME;
85
+ else process.env.FAILPROOFAI_HOME = previous;
86
+ }
87
+ });
88
+
89
+ it("is NOT redirected by AGENTEYE_HOME", () => {
90
+ const previous = process.env.AGENTEYE_HOME;
91
+ process.env.AGENTEYE_HOME = "/tmp/agenteye-elsewhere";
92
+ try {
93
+ // A redirect with no confirmation and no error means batches land in a
94
+ // directory nothing reads, and an unread spool is indistinguishable from
95
+ // an idle one. The Python SDK removed this for the same reason.
96
+ expect(getBaseDir()).not.toContain("agenteye-elsewhere");
97
+ } finally {
98
+ if (previous === undefined) delete process.env.AGENTEYE_HOME;
99
+ else process.env.AGENTEYE_HOME = previous;
100
+ }
101
+ });
102
+ });
103
+
104
+ describe("tilde expansion", () => {
105
+ it("expands a leading ~, so the documented migration bridge does not create one", () => {
106
+ // `configure({ baseDir: "~/.agenteye" })` is the documented explicit bridge.
107
+ // Without expansion, the writer's recursive mkdir cheerfully creates a
108
+ // directory literally named `~` under the process's cwd and spools into it:
109
+ // nothing on the machine watches that path, so 100% of the telemetry is
110
+ // lost.
111
+ setBaseDir("~/.agenteye");
112
+ expect(getBaseDir()).toBe(join(homedir(), ".agenteye"));
113
+ expect(getBaseDir().startsWith("~")).toBe(false);
114
+ });
115
+
116
+ it("leaves a tilde that is not a home reference alone", () => {
117
+ expect(expandUser("/var/lib/~weird")).toBe("/var/lib/~weird");
118
+ });
119
+
120
+ it("resolves a relative base directory against the cwd", () => {
121
+ setBaseDir("relative/spool");
122
+ expect(getBaseDir()).toBe(resolve("relative/spool"));
123
+ });
124
+ });