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,930 @@
1
+ /**
2
+ * The async worker state machine for Evaluator v2.
3
+ *
4
+ * Claim -> fetch the transcript -> run each definition's condition -> submit a
5
+ * plan -> run the planned evaluations under a heartbeat -> submit each result.
6
+ *
7
+ * ## What is different from the Python worker, and why
8
+ *
9
+ * Python runs synchronous evaluations in a sized thread pool, because a
10
+ * blocking customer function would otherwise stall its event loop. JavaScript
11
+ * has no such option: a synchronous evaluation that does not return blocks the
12
+ * one thread there is, and no timeout can fire while it does. So the contract
13
+ * here is explicit — **an evaluation must yield.** An `async` function that
14
+ * awaits, or a sandboxed managed evaluation (which runs in its own Worker and
15
+ * IS killable), can always be bounded. A synchronous busy-loop cannot be, by
16
+ * anyone, and `DEFAULT_EVAL_TIMEOUT_SECONDS` will not save a worker from one.
17
+ *
18
+ * The bound that does hold everywhere: every evaluation is raced against a
19
+ * deadline, and a run that loses the race is reported `timed_out` and its
20
+ * result submitted, so the assignment does not sit unresolved. The evaluation
21
+ * itself may still be running — a promise cannot be cancelled — which is
22
+ * counted as `evaluations_orphaned` and logged with the eval key, so a hung one
23
+ * is findable.
24
+ */
25
+
26
+ import { hostname } from "node:os";
27
+ import { randomUUID } from "node:crypto";
28
+
29
+ import { logException, logger } from "../logger.js";
30
+ import { VERSION } from "../version.js";
31
+ import { EvalResult, Evaluator, ConditionResult } from "./authoring.js";
32
+ import type { EvalDefinition } from "./authoring.js";
33
+ import { EvaluatorAPIError, EvaluatorClient } from "./client.js";
34
+ import {
35
+ DEFAULT_POLL_INTERVAL_SECONDS,
36
+ ExecutionMode,
37
+ MAX_CLAIM_CAPACITY,
38
+ MAX_ERROR_MESSAGE_BYTES,
39
+ MAX_WORKER_ID_BYTES,
40
+ TerminalRunStatus,
41
+ } from "./protocol.js";
42
+ import type {
43
+ Assignment,
44
+ AssignmentDefinition,
45
+ EvalSelection,
46
+ ResultItem,
47
+ SessionTranscript,
48
+ SkippedEval,
49
+ } from "./protocol.js";
50
+ import {
51
+ EvaluationTimeout,
52
+ UnsafeEvaluatorSource,
53
+ compileCondition,
54
+ compileEvaluator,
55
+ sourceChecksum,
56
+ } from "./source.js";
57
+
58
+ /**
59
+ * Reserved out of the lease for the plan request (and network jitter) so the
60
+ * pre-plan condition phase always leaves time to submit the plan before the
61
+ * lease expires.
62
+ */
63
+ const CONDITION_PHASE_SAFETY_MARGIN_SECONDS = 5;
64
+
65
+ /**
66
+ * Fallback wall-clock bound for an evaluation whose definition declares no
67
+ * timeout. A LOCAL (customer-authored) eval has no sandbox backstop, so without
68
+ * this a hang — a wedged `await`, an unbounded judge HTTP call — would hold its
69
+ * worker slot and the assignment lease forever. Matches the storage contract's
70
+ * 5-minute per-eval default.
71
+ */
72
+ export const DEFAULT_EVAL_TIMEOUT_SECONDS = 300;
73
+
74
+ function utcNow(): string {
75
+ return `${new Date().toISOString().slice(0, -1)}000Z`;
76
+ }
77
+
78
+ function positiveIntEnv(name: string, fallback: number): number {
79
+ const raw = process.env[name];
80
+ if (raw === undefined) return fallback;
81
+ const value = Number(raw);
82
+ if (!Number.isInteger(value)) throw new Error(`${name} must be an integer`);
83
+ if (value <= 0) throw new Error(`${name} must be greater than zero`);
84
+ return value;
85
+ }
86
+
87
+ function booleanEnv(name: string, fallback = false): boolean {
88
+ const raw = process.env[name];
89
+ if (raw === undefined) return fallback;
90
+ const normalized = raw.trim().toLowerCase();
91
+ if (["1", "true", "yes", "on"].includes(normalized)) return true;
92
+ if (["0", "false", "no", "off"].includes(normalized)) return false;
93
+ throw new Error(`${name} must be a boolean`);
94
+ }
95
+
96
+ export interface WorkerConfig {
97
+ serverUrl: string;
98
+ credential: string;
99
+ workerId: string;
100
+ maxConcurrency: number;
101
+ requestTimeoutSeconds: number;
102
+ drainTimeoutSeconds: number;
103
+ allowInsecureHttp: boolean;
104
+ }
105
+
106
+ export function workerConfigFromEnv(): WorkerConfig {
107
+ const serverUrl = (process.env.FAILPROOFAI_EVALUATOR_URL ?? "").trim();
108
+ const credential = (process.env.FAILPROOFAI_EVALUATOR_TOKEN ?? "").trim();
109
+ if (!serverUrl) throw new Error("FAILPROOFAI_EVALUATOR_URL is required");
110
+ if (!credential) throw new Error("FAILPROOFAI_EVALUATOR_TOKEN is required");
111
+
112
+ let workerId = (process.env.FAILPROOFAI_EVALUATOR_WORKER_ID ?? "").trim();
113
+ if (!workerId) workerId = `${hostname()}-${process.pid}`;
114
+ if (Buffer.byteLength(workerId, "utf8") > MAX_WORKER_ID_BYTES) {
115
+ throw new Error(`FAILPROOFAI_EVALUATOR_WORKER_ID exceeds ${MAX_WORKER_ID_BYTES} bytes`);
116
+ }
117
+ for (const char of workerId) {
118
+ const code = char.codePointAt(0)!;
119
+ if (code < 32 || code === 127) {
120
+ throw new Error("FAILPROOFAI_EVALUATOR_WORKER_ID must not contain control characters");
121
+ }
122
+ }
123
+
124
+ const config: WorkerConfig = {
125
+ serverUrl,
126
+ credential,
127
+ workerId,
128
+ maxConcurrency: positiveIntEnv("FAILPROOFAI_EVALUATOR_CONCURRENCY", 1),
129
+ requestTimeoutSeconds: positiveIntEnv("FAILPROOFAI_EVALUATOR_REQUEST_TIMEOUT_SECONDS", 30),
130
+ drainTimeoutSeconds: positiveIntEnv("FAILPROOFAI_EVALUATOR_DRAIN_TIMEOUT_SECONDS", 60),
131
+ allowInsecureHttp: booleanEnv("FAILPROOFAI_EVALUATOR_ALLOW_INSECURE_HTTP"),
132
+ };
133
+ if (config.maxConcurrency > MAX_CLAIM_CAPACITY) {
134
+ throw new Error(`FAILPROOFAI_EVALUATOR_CONCURRENCY exceeds ${MAX_CLAIM_CAPACITY}`);
135
+ }
136
+ return config;
137
+ }
138
+
139
+ /** A deadline race that reports which side won, so the caller can count it. */
140
+ async function withDeadline<T>(
141
+ work: Promise<T>,
142
+ timeoutMs: number,
143
+ ): Promise<{ timedOut: false; value: T } | { timedOut: true }> {
144
+ let timer: ReturnType<typeof setTimeout> | undefined;
145
+ const expiry = new Promise<{ timedOut: true }>((resolve) => {
146
+ timer = setTimeout(() => {
147
+ resolve({ timedOut: true });
148
+ }, timeoutMs);
149
+ timer.unref?.();
150
+ });
151
+ try {
152
+ const outcome = await Promise.race([
153
+ work.then((value) => ({ timedOut: false as const, value })),
154
+ expiry,
155
+ ]);
156
+ return outcome;
157
+ } finally {
158
+ if (timer !== undefined) clearTimeout(timer);
159
+ }
160
+ }
161
+
162
+ async function sleep(ms: number, signal?: { aborted: boolean }): Promise<void> {
163
+ if (signal?.aborted) return;
164
+ await new Promise<void>((resolve) => {
165
+ const timer = setTimeout(resolve, ms);
166
+ timer.unref?.();
167
+ });
168
+ }
169
+
170
+ /**
171
+ * Compile server-authored source LAZILY, at invocation time.
172
+ *
173
+ * Compilation can reject unsafe or malformed source. Building the definition
174
+ * with this thunk instead of a pre-compiled function routes that failure
175
+ * through the same per-run `try/catch` that turns any evaluation error into a
176
+ * bounded FAILED result — so a poison definition dead-letters cleanly as one
177
+ * failed run instead of throwing out of assignment setup, crashing the task,
178
+ * and forcing the whole assignment to be reclaimed and retried until its
179
+ * attempt budget is exhausted.
180
+ */
181
+ function deferredManagedEval(
182
+ source: string,
183
+ timeoutSeconds: number | null,
184
+ evalKey: string,
185
+ compiler: Evaluator["managedCompiler"],
186
+ ): (session: SessionTranscript) => Promise<EvalResult> | EvalResult {
187
+ return (session: SessionTranscript) => {
188
+ const compile = compiler ?? ((s, o) => compileEvaluator(s, o));
189
+ return compile(source, { timeoutSeconds, evalKey })(session);
190
+ };
191
+ }
192
+
193
+ export class WorkerRuntime {
194
+ readonly evaluator: Evaluator;
195
+ readonly config: WorkerConfig;
196
+ readonly client: EvaluatorClient;
197
+
198
+ private stopping = false;
199
+ private stopWaiters: Array<() => void> = [];
200
+ private readonly activeAssignments = new Set<Promise<void>>();
201
+ private heartbeatInterval = 30;
202
+ private pollInterval: number = DEFAULT_POLL_INTERVAL_SECONDS;
203
+ private claimLimit: number;
204
+ private leaseDuration = 120;
205
+ private disabledDefinitions = new Set<string>();
206
+ private registered = false;
207
+ private lastServerContact: number | null = null;
208
+ private readonly metricCounts = new Map<string, number>();
209
+ private readonly slots: { inUse: number; waiters: Array<() => void> };
210
+
211
+ constructor(evaluator: Evaluator, config: WorkerConfig, options: { client?: EvaluatorClient } = {}) {
212
+ this.evaluator = evaluator;
213
+ this.config = config;
214
+ this.claimLimit = config.maxConcurrency;
215
+ this.client =
216
+ options.client ??
217
+ new EvaluatorClient({
218
+ baseUrl: config.serverUrl,
219
+ credential: config.credential,
220
+ timeoutSeconds: config.requestTimeoutSeconds,
221
+ allowInsecureHttp: config.allowInsecureHttp,
222
+ });
223
+ this.slots = { inUse: 0, waiters: [] };
224
+ }
225
+
226
+ async register(): Promise<void> {
227
+ let response;
228
+ try {
229
+ response = await this.call(() =>
230
+ this.client.register({
231
+ workerId: this.config.workerId,
232
+ sdkVersion: VERSION,
233
+ catalogRevision: this.evaluator.catalogRevision,
234
+ maxConcurrency: this.config.maxConcurrency,
235
+ definitions: this.evaluator.catalog(),
236
+ }),
237
+ );
238
+ } catch (error) {
239
+ this.increment("registration_failure");
240
+ throw error;
241
+ }
242
+ this.heartbeatInterval = response.heartbeatIntervalSeconds;
243
+ this.pollInterval = response.pollIntervalSeconds;
244
+ this.leaseDuration = response.leaseDurationSeconds;
245
+ this.claimLimit = Math.min(this.config.maxConcurrency, response.claimLimit);
246
+ if (
247
+ this.heartbeatInterval <= 0 ||
248
+ this.pollInterval <= 0 ||
249
+ this.leaseDuration <= this.heartbeatInterval ||
250
+ this.claimLimit <= 0
251
+ ) {
252
+ this.increment("registration_failure");
253
+ throw new Error("server returned invalid evaluator timing or claim limits");
254
+ }
255
+ this.disabledDefinitions = new Set(response.disabledDefinitions);
256
+ this.registered = true;
257
+ this.increment("registration_success");
258
+ }
259
+
260
+ async runForever(): Promise<void> {
261
+ await this.register();
262
+ let retryDelay = 1;
263
+ try {
264
+ while (!this.stopping) {
265
+ const capacity = this.claimLimit - this.activeAssignments.size;
266
+ if (capacity <= 0) {
267
+ await this.waitForProgress();
268
+ continue;
269
+ }
270
+ let response;
271
+ try {
272
+ response = await this.call(() =>
273
+ this.client.claim({
274
+ workerId: this.config.workerId,
275
+ catalogRevision: this.evaluator.catalogRevision,
276
+ capacity,
277
+ }),
278
+ );
279
+ } catch (error) {
280
+ if (!(error instanceof EvaluatorAPIError)) throw error;
281
+ this.increment("claim_failures");
282
+ logger.warn(`evaluator claim failed (code=${error.code}, retryable=${error.retryable})`);
283
+ if (!error.retryable) throw error;
284
+ // A transport failure with no status means the server is unreachable,
285
+ // not busy — back off by the whole lease rather than hammering it.
286
+ const delay = error.status === null ? this.leaseDuration : retryDelay;
287
+ await this.waitOrStop(delay * 1000);
288
+ retryDelay = Math.min(retryDelay * 2, 30);
289
+ continue;
290
+ }
291
+ retryDelay = 1;
292
+ const assignments = validatedAssignments(response.assignments, capacity);
293
+ for (const assignment of assignments) this.spawn(assignment);
294
+ this.increment("assignments_claimed", assignments.length);
295
+ if (assignments.length === 0) {
296
+ // Normal short poll: the server returns immediately, so when nothing
297
+ // is queued we wait the advertised interval instead of hot-looping.
298
+ // When work IS returned we loop straight back to drain any backlog.
299
+ await this.waitOrStop(this.pollInterval * 1000);
300
+ }
301
+ }
302
+ } finally {
303
+ await this.drain();
304
+ }
305
+ }
306
+
307
+ /** Claim once and finish the returned assignments; useful for jobs and tests. */
308
+ async runOnce(): Promise<number> {
309
+ const response = await this.call(() =>
310
+ this.client.claim({
311
+ workerId: this.config.workerId,
312
+ catalogRevision: this.evaluator.catalogRevision,
313
+ capacity: this.claimLimit,
314
+ }),
315
+ );
316
+ const assignments = validatedAssignments(response.assignments, this.claimLimit);
317
+ this.increment("assignments_claimed", assignments.length);
318
+ await Promise.all(assignments.map((assignment) => this.processAssignment(assignment)));
319
+ return assignments.length;
320
+ }
321
+
322
+ stop(): void {
323
+ this.stopping = true;
324
+ const waiters = this.stopWaiters;
325
+ this.stopWaiters = [];
326
+ for (const waiter of waiters) waiter();
327
+ }
328
+
329
+ async drain(): Promise<void> {
330
+ if (this.activeAssignments.size === 0) return;
331
+ const outcome = await withDeadline(
332
+ Promise.allSettled([...this.activeAssignments]).then(() => undefined),
333
+ this.config.drainTimeoutSeconds * 1000,
334
+ );
335
+ if (outcome.timedOut) {
336
+ logger.warn(
337
+ `drain timed out with ${this.activeAssignments.size} assignment(s) still running; ` +
338
+ "their results may not be submitted",
339
+ );
340
+ }
341
+ this.activeAssignments.clear();
342
+ }
343
+
344
+ private spawn(assignment: Assignment): void {
345
+ const task = this.processAssignment(assignment)
346
+ .catch((error: unknown) => {
347
+ logException("evaluator assignment failed", error);
348
+ })
349
+ .finally(() => {
350
+ this.activeAssignments.delete(task);
351
+ this.notifyProgress();
352
+ });
353
+ this.activeAssignments.add(task);
354
+ }
355
+
356
+ async processAssignment(assignment: Assignment): Promise<void> {
357
+ let session: SessionTranscript;
358
+ try {
359
+ session = await this.call(() => this.client.transcript(assignment, this.config.workerId));
360
+ } catch (error) {
361
+ if (error instanceof EvaluatorAPIError && error.code === "transcript_too_large") {
362
+ // No runs are planned yet, so there is nothing to submit a per-run
363
+ // result for, and the error is non-retryable — re-throwing would only
364
+ // wedge the poll loop and burn the assignment's whole retry budget
365
+ // against a transcript that can never shrink. The server terminalizes
366
+ // the assignment itself.
367
+ logger.warn(
368
+ `assignment ${assignment.assignmentId} transcript is too large to evaluate; skipping`,
369
+ );
370
+ this.increment("transcripts_too_large");
371
+ return;
372
+ }
373
+ throw error;
374
+ }
375
+ if (session.sessionRevisionId !== assignment.sessionRevisionId) {
376
+ throw new Error("transcript session revision does not match assignment");
377
+ }
378
+
379
+ const descriptors = await this.assignmentDefinitions(assignment);
380
+ // Every descriptor the assignment carries, keyed for reconstruction: on an
381
+ // idempotent replay the server re-serves the first attempt's run set, which
382
+ // may include a run this attempt's re-derived plan would have skipped.
383
+ const descriptorByKey = new Map<string, AssignmentDefinition>(
384
+ descriptors.map((item) => [`${item.evalKey}@${item.evalVersion}`, item]),
385
+ );
386
+ const localDefinitions = new Map<string, EvalDefinition>(
387
+ this.evaluator.definitions.map((item) => [`${item.evalKey}@${item.evalVersion}`, item]),
388
+ );
389
+
390
+ const selected: Array<[AssignmentDefinition, EvalDefinition | null]> = [];
391
+ const skipped: SkippedEval[] = [];
392
+ // The assignment lease is fixed at claim time and cannot be renewed until
393
+ // the plan is submitted (the server only extends a lease for a *planned*
394
+ // assignment with running runs). A slow condition phase can therefore burn
395
+ // the whole lease and get the plan fenced as `lease_lost`, so every
396
+ // condition is bounded by the lease it must leave time to plan within.
397
+ const conditionDeadline = this.conditionPhaseDeadline(assignment);
398
+
399
+ for (const descriptor of descriptors) {
400
+ const key = `${descriptor.evalKey}@${descriptor.evalVersion}`;
401
+ const local = localDefinitions.get(key) ?? null;
402
+ if (descriptor.executionMode === ExecutionMode.LOCAL && local === null) {
403
+ throw new Error("server requested a definition absent from this worker");
404
+ }
405
+ if (this.disabledDefinitions.has(descriptor.evalKey)) {
406
+ skipped.push(skippedOf(descriptor, "disabled_by_server"));
407
+ this.increment("conditions_skipped");
408
+ continue;
409
+ }
410
+
411
+ let applicable: boolean;
412
+ let reasonCode = "condition_false";
413
+ try {
414
+ // Whose condition decides applicability follows the EXECUTION MODE: a
415
+ // LOCAL definition's condition is client-authored; a sandboxed
416
+ // (server-authored) definition's is server-authored and MUST govern
417
+ // even when the worker also registered the same key/version locally.
418
+ // Keying `local` on key+version alone means a managed definition can
419
+ // collide with a local one; selecting the local condition there would
420
+ // let it override the server's rule and run the managed evaluator
421
+ // against the operator's intent.
422
+ let condition: ((s: SessionTranscript) => unknown) | null = null;
423
+ let managedConditionSource: string | null = null;
424
+ if (descriptor.executionMode === ExecutionMode.LOCAL) {
425
+ condition = local?.condition ?? null;
426
+ } else if (descriptor.conditionSource) {
427
+ managedConditionSource = descriptor.conditionSource;
428
+ }
429
+ if (condition === null && managedConditionSource === null) {
430
+ selected.push([descriptor, local]);
431
+ continue;
432
+ }
433
+ const budget = this.conditionBudget(conditionDeadline, descriptor.timeoutSeconds);
434
+ if (budget <= 0) {
435
+ // Not enough lease left to evaluate this condition and still submit
436
+ // the plan in time; skip it (and, as the loop proceeds, every later
437
+ // condition) rather than do work the server will fence as
438
+ // `lease_lost` and reclaim in a loop.
439
+ skipped.push(skippedOf(descriptor, "lease_exhausted"));
440
+ this.increment("conditions_skipped");
441
+ this.increment("conditions_lease_exhausted");
442
+ continue;
443
+ }
444
+ // Compiled INSIDE the try, and only once the lease budget is known: a
445
+ // managed condition the sandbox rejects must dead-letter as
446
+ // `condition_error`, not throw out of the plan loop and strand the
447
+ // whole assignment until its retry budget is exhausted.
448
+ if (managedConditionSource !== null) {
449
+ condition = compileCondition(managedConditionSource, { timeoutSeconds: budget });
450
+ }
451
+ const outcome = await withDeadline(
452
+ Promise.resolve(condition!(session)),
453
+ budget * 1000,
454
+ );
455
+ if (outcome.timedOut) throw new EvaluationTimeout("condition exceeded its budget");
456
+ const value = outcome.value;
457
+ if (value instanceof ConditionResult) {
458
+ applicable = value.applicable;
459
+ reasonCode = value.reasonCode;
460
+ } else if (typeof value === "boolean") {
461
+ applicable = value;
462
+ } else {
463
+ throw new TypeError("condition must return a boolean or a ConditionResult");
464
+ }
465
+ } catch (error) {
466
+ logger.warn(
467
+ `evaluator condition failed (assignment=${assignment.assignmentId}, ` +
468
+ `error=${error instanceof Error ? error.name : typeof error})`,
469
+ );
470
+ skipped.push(skippedOf(descriptor, "condition_error"));
471
+ this.increment("conditions_skipped");
472
+ continue;
473
+ }
474
+
475
+ if (applicable) {
476
+ selected.push([descriptor, local]);
477
+ this.increment("conditions_selected");
478
+ } else {
479
+ skipped.push(skippedOf(descriptor, reasonCode));
480
+ this.increment("conditions_skipped");
481
+ }
482
+ }
483
+
484
+ const plan = await this.call(() =>
485
+ this.client.plan(assignment.assignmentId, {
486
+ workerId: this.config.workerId,
487
+ leaseGeneration: assignment.leaseGeneration,
488
+ selected: selected.map(
489
+ ([item]): EvalSelection => ({ evalKey: item.evalKey, evalVersion: item.evalVersion }),
490
+ ),
491
+ skipped,
492
+ }),
493
+ );
494
+ if (plan.assignmentId !== assignment.assignmentId) {
495
+ throw new Error("server returned a plan for a different assignment");
496
+ }
497
+ // On an idempotent replay the server's status is authoritative: this
498
+ // attempt may have selected a different set than the first, so a mismatch
499
+ // against our own `selected` is expected, not an error.
500
+ if (!plan.idempotentReplay) {
501
+ const expected = selected.length > 0 ? "planned" : "skipped";
502
+ if (plan.assignmentStatus !== expected) {
503
+ throw new Error("server returned an inconsistent assignment status");
504
+ }
505
+ }
506
+
507
+ const pending = new Map<string, [AssignmentDefinition, EvalDefinition | null]>(
508
+ selected.map(([item, local]) => [`${item.evalKey}@${item.evalVersion}`, [item, local]]),
509
+ );
510
+ const runDefinitions: Array<[string, EvalDefinition]> = [];
511
+ const runIds = new Set<string>();
512
+ for (const run of plan.runs) {
513
+ if (runIds.has(run.evaluationRunId)) {
514
+ throw new Error("server returned a duplicate evaluation run id");
515
+ }
516
+ runIds.add(run.evaluationRunId);
517
+ const key = `${run.evalKey}@${run.evalVersion}`;
518
+ let entry = pending.get(key);
519
+ pending.delete(key);
520
+ if (entry === undefined) {
521
+ // On an idempotent replay the server's run set is AUTHORITATIVE — it
522
+ // re-serves the first attempt's runs even for a definition this
523
+ // attempt's condition phase would have skipped. Reconstruct from the
524
+ // assignment's descriptors rather than throwing and dead-lettering an
525
+ // assignment that could otherwise never converge.
526
+ const replay = plan.idempotentReplay ? descriptorByKey.get(key) : undefined;
527
+ if (replay === undefined) throw new Error("server returned an unrequested evaluation run");
528
+ entry = [replay, localDefinitions.get(key) ?? null];
529
+ }
530
+ const [descriptor, local] = entry;
531
+ if (run.executionMode !== descriptor.executionMode) {
532
+ throw new Error("server changed the evaluation execution mode");
533
+ }
534
+
535
+ let definition: EvalDefinition;
536
+ if (run.executionMode === ExecutionMode.LOCAL) {
537
+ if (local === null) throw new Error("local evaluation definition is unavailable");
538
+ definition = local;
539
+ } else {
540
+ if (!run.evaluatorSource || !run.sourceChecksum) {
541
+ throw new Error("server omitted managed evaluation source");
542
+ }
543
+ const expected = sourceChecksum(descriptor.conditionSource, run.evaluatorSource);
544
+ if (
545
+ expected !== run.sourceChecksum ||
546
+ (descriptor.sourceChecksum && descriptor.sourceChecksum !== run.sourceChecksum)
547
+ ) {
548
+ throw new Error("managed evaluation source checksum mismatch");
549
+ }
550
+ const timeoutSeconds = run.timeoutSeconds ?? descriptor.timeoutSeconds;
551
+ definition = {
552
+ evalKey: descriptor.evalKey,
553
+ displayName: descriptor.displayName,
554
+ evalVersion: descriptor.evalVersion,
555
+ resultKind: descriptor.resultKind,
556
+ labels: descriptor.labels,
557
+ function: deferredManagedEval(
558
+ run.evaluatorSource,
559
+ timeoutSeconds,
560
+ descriptor.evalKey,
561
+ this.evaluator.managedCompiler,
562
+ ),
563
+ condition: null,
564
+ onCancel: null,
565
+ timeoutSeconds,
566
+ };
567
+ }
568
+ runDefinitions.push([run.evaluationRunId, definition]);
569
+ }
570
+ if (pending.size > 0 && !plan.idempotentReplay) {
571
+ throw new Error("server omitted a selected evaluation run");
572
+ }
573
+
574
+ const states = new Map<string, { done: boolean; cancelled: boolean }>();
575
+ const tasks = runDefinitions.map(([runId, definition]) => {
576
+ const state = { done: false, cancelled: false };
577
+ states.set(runId, state);
578
+ return this.executeRun(assignment, runId, definition, session, state).finally(() => {
579
+ state.done = true;
580
+ });
581
+ });
582
+ const heartbeat = this.heartbeat(assignment, states);
583
+ try {
584
+ const outcomes = await Promise.allSettled(tasks);
585
+ for (const outcome of outcomes) {
586
+ if (outcome.status === "rejected") throw outcome.reason as Error;
587
+ }
588
+ } finally {
589
+ heartbeat.cancel();
590
+ await heartbeat.finished;
591
+ }
592
+ }
593
+
594
+ private async acquireSlot(): Promise<void> {
595
+ if (this.slots.inUse < this.config.maxConcurrency) {
596
+ this.slots.inUse += 1;
597
+ return;
598
+ }
599
+ await new Promise<void>((resolve) => this.slots.waiters.push(resolve));
600
+ this.slots.inUse += 1;
601
+ }
602
+
603
+ private releaseSlot(): void {
604
+ this.slots.inUse -= 1;
605
+ const waiter = this.slots.waiters.shift();
606
+ if (waiter) waiter();
607
+ }
608
+
609
+ private async executeRun(
610
+ assignment: Assignment,
611
+ runId: string,
612
+ definition: EvalDefinition,
613
+ session: SessionTranscript,
614
+ state: { done: boolean; cancelled: boolean },
615
+ ): Promise<void> {
616
+ await this.acquireSlot();
617
+ try {
618
+ await this.executeRunInSlot(assignment, runId, definition, session, state);
619
+ } finally {
620
+ this.releaseSlot();
621
+ }
622
+ }
623
+
624
+ private async executeRunInSlot(
625
+ assignment: Assignment,
626
+ runId: string,
627
+ definition: EvalDefinition,
628
+ session: SessionTranscript,
629
+ state: { done: boolean; cancelled: boolean },
630
+ ): Promise<void> {
631
+ const startedAt = utcNow();
632
+ const started = Date.now();
633
+ let items: readonly ResultItem[] = [];
634
+ let status: TerminalRunStatus;
635
+ let summary: string | null = null;
636
+ let errorCode: string | null = null;
637
+ let errorMessage: string | null = null;
638
+
639
+ try {
640
+ if (state.cancelled) throw new EvaluationCancelled();
641
+ // Always bound the evaluation. A definition with no declared timeout
642
+ // falls back to the default rather than awaiting unbounded — an unbounded
643
+ // local eval that hangs would wedge its worker slot and hold the lease
644
+ // forever.
645
+ const timeoutSeconds = definition.timeoutSeconds ?? DEFAULT_EVAL_TIMEOUT_SECONDS;
646
+ const outcome = await withDeadline(
647
+ Promise.resolve(definition.function(session)),
648
+ timeoutSeconds * 1000,
649
+ );
650
+ if (outcome.timedOut) throw new EvaluationTimeout("evaluation exceeded its timeout");
651
+ const result = outcome.value;
652
+ if (!(result instanceof EvalResult)) throw new TypeError("evaluation must return an EvalResult");
653
+ items = result.resultItems(definition.evalKey);
654
+ if (
655
+ !items.some(
656
+ (item) => item.resultKey === definition.evalKey && item.resultKind === definition.resultKind,
657
+ )
658
+ ) {
659
+ throw new Error("evaluation result does not contain its declared primary result");
660
+ }
661
+ status = TerminalRunStatus.SUCCEEDED;
662
+ summary = result.summary ?? null;
663
+ } catch (error) {
664
+ await this.cancelHook(definition, session);
665
+ if (error instanceof EvaluationCancelled || state.cancelled) {
666
+ status = TerminalRunStatus.CANCELLED;
667
+ errorCode = "lease_lost";
668
+ errorMessage = "the assignment lease was lost before this run finished";
669
+ } else if (error instanceof EvaluationTimeout) {
670
+ // A SANDBOXED evaluation that loses this race has already been
671
+ // terminated by the worker sandbox, so nothing is left running. A LOCAL
672
+ // one cannot be: a promise has no cancel, so the customer's function
673
+ // keeps going. Count it and name the eval so a hung one is findable.
674
+ this.increment("evaluations_orphaned");
675
+ logger.warn(
676
+ `evaluation ${JSON.stringify(definition.evalKey)} exceeded its timeout ` +
677
+ `(assignment=${assignment.assignmentId}). If it is a local evaluation it is still ` +
678
+ "running — a promise cannot be cancelled — and its worker slot is freed only when " +
679
+ "it settles.",
680
+ );
681
+ status = TerminalRunStatus.TIMED_OUT;
682
+ errorCode = "eval_timeout";
683
+ errorMessage = "evaluation exceeded its configured timeout";
684
+ } else if (error instanceof UnsafeEvaluatorSource) {
685
+ // Surface the REASON for a rejected server-authored definition. This is
686
+ // deliberately narrower than the generic branch below:
687
+ // `UnsafeEvaluatorSource` is raised by our own validator before any
688
+ // customer source runs, and its message is SDK-authored text about the
689
+ // source's shape — it embeds no transcript content, so it is safe to
690
+ // send back over the wire. Without it the author sees only "evaluation
691
+ // raised UnsafeEvaluatorSource" on every session, with no way to learn
692
+ // what was wrong.
693
+ status = TerminalRunStatus.FAILED;
694
+ errorCode = "eval_error";
695
+ const detail = error.message.trim();
696
+ errorMessage = truncateUtf8(
697
+ detail ? `evaluator source rejected: ${detail}` : "evaluator source rejected by the validator",
698
+ MAX_ERROR_MESSAGE_BYTES,
699
+ );
700
+ } else {
701
+ // Type name ONLY on the wire. A customer eval's error text can quote
702
+ // the transcript it was reading, and this field is persisted and shown
703
+ // in the dashboard. But log the FULL error LOCALLY: this runs on the
704
+ // customer's own pod over their own data, and without it an author
705
+ // whose eval throws sees only "evaluation raised TypeError" in the
706
+ // dashboard and nothing at all in their logs.
707
+ logException(
708
+ `evaluation ${JSON.stringify(definition.evalKey)} threw; reported to the server as a failed run`,
709
+ error,
710
+ );
711
+ status = TerminalRunStatus.FAILED;
712
+ errorCode = "eval_error";
713
+ errorMessage = `evaluation raised ${error instanceof Error ? error.name : typeof error}`;
714
+ }
715
+ }
716
+
717
+ await this.call(() =>
718
+ this.client.submitResult(runId, {
719
+ submissionId: randomUUID(),
720
+ workerId: this.config.workerId,
721
+ leaseGeneration: assignment.leaseGeneration,
722
+ status,
723
+ startedAt,
724
+ finishedAt: utcNow(),
725
+ durationMs: Math.max(0, Math.round(Date.now() - started)),
726
+ summary,
727
+ results: items,
728
+ errorCode,
729
+ errorMessage,
730
+ }),
731
+ );
732
+ this.increment(`runs_${status}`);
733
+ }
734
+
735
+ private async cancelHook(definition: EvalDefinition, session: SessionTranscript): Promise<void> {
736
+ if (definition.onCancel === null) return;
737
+ try {
738
+ await definition.onCancel(session);
739
+ } catch (error) {
740
+ logger.warn(
741
+ `evaluator cancellation hook failed (${error instanceof Error ? error.name : typeof error})`,
742
+ );
743
+ }
744
+ }
745
+
746
+ private heartbeat(
747
+ assignment: Assignment,
748
+ states: Map<string, { done: boolean; cancelled: boolean }>,
749
+ ): { cancel: () => void; finished: Promise<void> } {
750
+ let cancelled = false;
751
+ const finished = (async () => {
752
+ // Beat IMMEDIATELY, before the first sleep. The pre-plan condition phase
753
+ // may have consumed most of the claim-time lease, and the server only
754
+ // renews a planned assignment's lease on heartbeat — so sleeping a full
755
+ // interval here can let the lease expire after the runs have started,
756
+ // cancelling every one of them.
757
+ let first = true;
758
+ while (!cancelled) {
759
+ if (!first) await sleep(this.heartbeatInterval * 1000);
760
+ if (cancelled) return;
761
+ first = false;
762
+ const active = [...states.entries()]
763
+ .filter(([, state]) => !state.done)
764
+ .map(([runId]) => ({ evaluationRunId: runId, state: "running" }));
765
+ if (active.length === 0) return;
766
+ try {
767
+ const response = await this.call(() =>
768
+ this.client.heartbeat({
769
+ workerId: this.config.workerId,
770
+ leaseGeneration: assignment.leaseGeneration,
771
+ runs: active,
772
+ }),
773
+ );
774
+ const accepted = new Set(response.acceptedRunIds);
775
+ for (const [runId, state] of states) {
776
+ if (!state.done && !accepted.has(runId)) state.cancelled = true;
777
+ }
778
+ } catch (error) {
779
+ if (error instanceof EvaluatorAPIError && error.code === "lease_lost") {
780
+ this.increment("leases_lost");
781
+ for (const state of states.values()) state.cancelled = true;
782
+ return;
783
+ }
784
+ logger.warn(
785
+ `evaluator heartbeat failed (assignment=${assignment.assignmentId}, ` +
786
+ `${error instanceof EvaluatorAPIError ? `code=${error.code}` : `error=${error instanceof Error ? error.name : typeof error}`})`,
787
+ );
788
+ this.increment("heartbeat_failures");
789
+ }
790
+ }
791
+ })();
792
+ return {
793
+ cancel: () => {
794
+ cancelled = true;
795
+ },
796
+ finished,
797
+ };
798
+ }
799
+
800
+ /**
801
+ * The clock reading by which the pre-plan condition phase must end.
802
+ *
803
+ * The real `leaseExpiresAt` is used when it is in the future (production); a
804
+ * past or unparseable value (clock skew, or a replayed transcript in a test)
805
+ * falls back to the negotiated lease duration measured from now, so the bound
806
+ * never fires spuriously on a stale deadline.
807
+ */
808
+ private conditionPhaseDeadline(assignment: Assignment): number {
809
+ let remaining = this.leaseDuration;
810
+ const expires = Date.parse(assignment.leaseExpiresAt);
811
+ if (Number.isFinite(expires)) {
812
+ const parsed = (expires - Date.now()) / 1000;
813
+ if (parsed > 0) remaining = parsed;
814
+ }
815
+ return Date.now() + remaining * 1000;
816
+ }
817
+
818
+ /**
819
+ * Seconds a single condition may run: the lease left before the
820
+ * plan-submission margin, capped by the definition's own timeout.
821
+ */
822
+ private conditionBudget(deadline: number, timeoutSeconds: number | null): number {
823
+ let remaining = (deadline - Date.now()) / 1000 - CONDITION_PHASE_SAFETY_MARGIN_SECONDS;
824
+ if (timeoutSeconds !== null) remaining = Math.min(remaining, timeoutSeconds);
825
+ return remaining;
826
+ }
827
+
828
+ private async assignmentDefinitions(assignment: Assignment): Promise<AssignmentDefinition[]> {
829
+ if (assignment.definitionsUrl) {
830
+ const response = await this.call(() =>
831
+ this.client.definitions(assignment, this.config.workerId),
832
+ );
833
+ if (response.assignmentId !== assignment.assignmentId) {
834
+ throw new Error("server returned definitions for another assignment");
835
+ }
836
+ return [...response.definitions];
837
+ }
838
+ return this.evaluator.definitions.map((item) => ({
839
+ evalKey: item.evalKey,
840
+ displayName: item.displayName,
841
+ evalVersion: item.evalVersion,
842
+ resultKind: item.resultKind,
843
+ labels: item.labels,
844
+ executionMode: ExecutionMode.LOCAL,
845
+ conditionSource: null,
846
+ sourceChecksum: null,
847
+ timeoutSeconds: item.timeoutSeconds,
848
+ }));
849
+ }
850
+
851
+ private progressWaiters: Array<() => void> = [];
852
+
853
+ private notifyProgress(): void {
854
+ const waiters = this.progressWaiters;
855
+ this.progressWaiters = [];
856
+ for (const waiter of waiters) waiter();
857
+ }
858
+
859
+ private async waitForProgress(): Promise<void> {
860
+ if (this.activeAssignments.size === 0) return;
861
+ await new Promise<void>((resolve) => {
862
+ this.progressWaiters.push(resolve);
863
+ this.stopWaiters.push(resolve);
864
+ });
865
+ }
866
+
867
+ private async waitOrStop(ms: number): Promise<void> {
868
+ if (this.stopping) return;
869
+ await new Promise<void>((resolve) => {
870
+ const timer = setTimeout(resolve, ms);
871
+ timer.unref?.();
872
+ this.stopWaiters.push(() => {
873
+ clearTimeout(timer);
874
+ resolve();
875
+ });
876
+ });
877
+ }
878
+
879
+ private async call<T>(work: () => Promise<T>): Promise<T> {
880
+ const result = await work();
881
+ this.lastServerContact = Date.now();
882
+ return result;
883
+ }
884
+
885
+ private increment(name: string, amount = 1): void {
886
+ this.metricCounts.set(name, (this.metricCounts.get(name) ?? 0) + amount);
887
+ }
888
+
889
+ metrics(): Record<string, number> {
890
+ return Object.fromEntries(this.metricCounts);
891
+ }
892
+
893
+ isReady(): boolean {
894
+ if (this.stopping || !this.registered || this.lastServerContact === null) return false;
895
+ return (Date.now() - this.lastServerContact) / 1000 <= Math.max(this.leaseDuration, 60);
896
+ }
897
+ }
898
+
899
+ class EvaluationCancelled extends Error {
900
+ constructor() {
901
+ super("evaluation cancelled");
902
+ this.name = "EvaluationCancelled";
903
+ }
904
+ }
905
+
906
+ function skippedOf(definition: AssignmentDefinition, reasonCode: string): SkippedEval {
907
+ return { evalKey: definition.evalKey, evalVersion: definition.evalVersion, reasonCode };
908
+ }
909
+
910
+ function validatedAssignments(
911
+ assignments: readonly Assignment[],
912
+ capacity: number,
913
+ ): Assignment[] {
914
+ if (assignments.length > capacity) {
915
+ throw new Error("server returned more assignments than requested");
916
+ }
917
+ const ids = assignments.map((item) => item.assignmentId);
918
+ if (new Set(ids).size !== ids.length) throw new Error("server returned duplicate assignments");
919
+ return [...assignments];
920
+ }
921
+
922
+ /** Cut to `maximum` BYTES without splitting a multi-byte character. */
923
+ function truncateUtf8(value: string, maximum: number): string {
924
+ const encoded = Buffer.from(value, "utf8");
925
+ if (encoded.byteLength <= maximum) return value;
926
+ return new TextDecoder("utf-8", { fatal: false }).decode(encoded.subarray(0, maximum)).replace(
927
+ /�$/,
928
+ "",
929
+ );
930
+ }