failproofai 1.0.1 → 1.0.2-beta.0

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 (389) 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 +6 -6
  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 +2 -2
  7. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  8. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  11. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
  12. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  13. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  15. package/.next/standalone/.next/server/app/_not-found/page.js +2 -2
  16. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  17. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  18. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  19. package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
  20. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
  21. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +14 -14
  22. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  23. package/.next/standalone/.next/server/app/api/audit/invite/route.js +3 -2
  24. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  25. package/.next/standalone/.next/server/app/api/audit/run/route.js +5 -4
  26. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/auth/login-request/route.js +2 -2
  29. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +4 -3
  31. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/api/auth/logout/route.js +4 -4
  33. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/api/auth/status/route.js +4 -4
  35. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  37. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  38. package/.next/standalone/.next/server/app/audit/page.js +2 -2
  39. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  41. package/.next/standalone/.next/server/app/index.html +1 -1
  42. package/.next/standalone/.next/server/app/index.rsc +15 -15
  43. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +14 -14
  44. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
  45. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  46. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  47. package/.next/standalone/.next/server/app/page.js +2 -2
  48. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  49. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  50. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +66 -22
  51. package/.next/standalone/.next/server/app/policies/page.js +5 -4
  52. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  53. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  54. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  55. package/.next/standalone/.next/server/app/project/[name]/page.js +2 -2
  56. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  57. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  58. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  59. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  60. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +2 -2
  61. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  62. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  63. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  64. package/.next/standalone/.next/server/app/projects/page.js +2 -2
  65. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  66. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  67. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +4 -4
  68. package/.next/standalone/.next/server/app/settings/page.js +1 -1
  69. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  70. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  71. package/.next/standalone/.next/server/chunks/{[externals]__1qzqcio._.js → [externals]__0e32-7c._.js} +1 -1
  72. package/.next/standalone/.next/server/chunks/[externals]__1s462yl._.js +3 -0
  73. package/.next/standalone/.next/server/chunks/[root-of-the-server]__01eqny5._.js +3 -0
  74. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_0xu5z._.js +1 -1
  75. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1p8poxd._.js → [root-of-the-server]__0igxt32._.js} +2 -2
  76. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0neqlu-._.js +3 -0
  77. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +3 -0
  78. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0t9oqnn._.js +3 -0
  79. package/.next/standalone/.next/server/chunks/_0bs-v8p._.js +3 -0
  80. package/.next/standalone/.next/server/chunks/_0tovk6q._.js +3 -0
  81. package/.next/standalone/.next/server/chunks/_0trp3yc._.js +3 -0
  82. package/.next/standalone/.next/server/chunks/_185gyk9._.js +3 -0
  83. package/.next/standalone/.next/server/chunks/_1ek68ln._.js +5 -6
  84. package/.next/standalone/.next/server/chunks/lib_telemetry-id_ts_1k8gj9o._.js +3 -0
  85. package/.next/standalone/.next/server/chunks/{node_modules_posthog-node_dist_entrypoints_index_node_mjs_09d5c79._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_04op_ou._.js} +1 -1
  86. package/.next/standalone/.next/server/chunks/{node_modules_posthog-node_dist_entrypoints_index_node_mjs_1d2g73o._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_0dr20uz._.js} +1 -1
  87. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  88. package/.next/standalone/.next/server/chunks/src_hooks_0xbw3bu._.js +12 -0
  89. package/.next/standalone/.next/server/chunks/src_hooks_fp-home_ts_09kv0bn._.js +1 -1
  90. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__013jr2b._.js +4 -0
  91. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01wy8d-._.js +4 -0
  92. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02npjtd._.js +4 -0
  93. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0spkm68._.js → [root-of-the-server]__07gm3zl._.js} +21 -20
  94. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0da85px._.js +4 -0
  95. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ftmoxc._.js +4 -0
  96. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0oa1lav._.js +1 -1
  97. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0p-5p8u._.js +4 -0
  98. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s740oi._.js +6 -0
  99. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__07tbbf3._.js → [root-of-the-server]__0zig5sv._.js} +2 -2
  100. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__192nhvh._.js +5 -0
  101. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1p2otjt._.js +4 -0
  102. package/.next/standalone/.next/server/chunks/ssr/{_0lvyuv4._.js → _00e9tnf._.js} +2 -2
  103. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  104. package/.next/standalone/.next/server/chunks/ssr/{_0u5zauv._.js → _12l4a_k._.js} +1 -1
  105. package/.next/standalone/.next/server/chunks/ssr/_1u8-lu2._.js +1 -1
  106. package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +1 -1
  107. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +13 -13
  108. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  109. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +2 -2
  110. package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +1 -1
  111. package/.next/standalone/.next/server/chunks/ssr/src_hooks_08o7bqo._.js +10 -0
  112. package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +1 -1
  113. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-home_ts_0je3xkv._.js +1 -1
  114. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  115. package/.next/standalone/.next/server/middleware.js +1 -1
  116. package/.next/standalone/.next/server/pages/404.html +1 -1
  117. package/.next/standalone/.next/server/pages/500.html +1 -1
  118. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  119. package/.next/standalone/.next/server/server-reference-manifest.json +71 -27
  120. package/.next/standalone/.next/static/chunks/{37fcpc36x9gpe.js → 0eqky-7n7dgdm.js} +1 -1
  121. package/.next/standalone/.next/static/chunks/{1ide1wl2f7zi1.js → 0sa9v5mhc8861.js} +13 -13
  122. package/.next/standalone/.next/static/chunks/1mfzsja6ftim5.css +2 -0
  123. package/.next/standalone/.next/static/chunks/{3k7mxbp9hiom0.js → 1nuqytbta44af.js} +1 -1
  124. package/.next/standalone/.next/static/chunks/1sl2xmn9inx3y.js +6 -0
  125. package/.next/standalone/.next/static/chunks/{2_2lhuojq2xop.js → 2aawsjld9ied_.js} +1 -1
  126. package/.next/standalone/.next/static/chunks/2gn7ut4svofm2.js +1 -0
  127. package/.next/standalone/.next/static/chunks/{31s1smp-g7gks.js → 2hs7ycvsav7v2.js} +1 -1
  128. package/.next/standalone/.next/static/chunks/{0k5050ezjvv49.js → 2i2yt3hzjredm.js} +1 -1
  129. package/.next/standalone/.next/static/chunks/{3c808qrfcq0im.js → 35xg6retpe6rp.js} +1 -1
  130. package/.next/standalone/.next/static/chunks/{2zpp1we2jv6tb.js → 3y54nw0i7dsjl.js} +1 -1
  131. package/.next/standalone/SECURITY.md +5 -4
  132. package/.next/standalone/app/actions/get-hooks-config.ts +108 -17
  133. package/.next/standalone/app/actions/pack-actions.ts +153 -0
  134. package/.next/standalone/app/audit/_components/run-progress.tsx +1 -1
  135. package/.next/standalone/app/audit/_components/share-templates.ts +13 -13
  136. package/.next/standalone/app/policies/hooks-client.tsx +320 -14
  137. package/.next/standalone/components/navbar.tsx +2 -28
  138. package/.next/standalone/components/reach-developers.tsx +8 -1
  139. package/.next/standalone/docs-old/agenteye/python-sdk-skill.mdx +1 -1
  140. package/.next/standalone/docs-old/agenteye/python-sdk.mdx +59 -35
  141. package/.next/standalone/docs-old/i18n/README.ar.md +1 -0
  142. package/.next/standalone/docs-old/i18n/README.de.md +1 -0
  143. package/.next/standalone/docs-old/i18n/README.es.md +1 -0
  144. package/.next/standalone/docs-old/i18n/README.fr.md +1 -0
  145. package/.next/standalone/docs-old/i18n/README.he.md +1 -0
  146. package/.next/standalone/docs-old/i18n/README.hi.md +1 -0
  147. package/.next/standalone/docs-old/i18n/README.it.md +1 -0
  148. package/.next/standalone/docs-old/i18n/README.ja.md +1 -0
  149. package/.next/standalone/docs-old/i18n/README.ko.md +1 -0
  150. package/.next/standalone/docs-old/i18n/README.pt-br.md +1 -0
  151. package/.next/standalone/docs-old/i18n/README.ru.md +1 -0
  152. package/.next/standalone/docs-old/i18n/README.tr.md +1 -0
  153. package/.next/standalone/docs-old/i18n/README.vi.md +1 -0
  154. package/.next/standalone/docs-old/i18n/README.zh.md +1 -0
  155. package/.next/standalone/fp-cloud-cli/CHANGELOG.md +431 -0
  156. package/.next/standalone/fp-cloud-cli/LICENSE +42 -0
  157. package/.next/standalone/fp-cloud-cli/MANIFEST.in +10 -0
  158. package/.next/standalone/fp-cloud-cli/README.md +259 -0
  159. package/.next/standalone/fp-cloud-cli/fp_cli/__init__.py +10 -0
  160. package/.next/standalone/fp-cloud-cli/fp_cli/__main__.py +4 -0
  161. package/.next/standalone/fp-cloud-cli/fp_cli/_click_compat.py +64 -0
  162. package/.next/standalone/fp-cloud-cli/fp_cli/_context.py +332 -0
  163. package/.next/standalone/fp-cloud-cli/fp_cli/_version.py +1 -0
  164. package/.next/standalone/fp-cloud-cli/fp_cli/analytics.py +432 -0
  165. package/.next/standalone/fp-cloud-cli/fp_cli/analytics_config.py +77 -0
  166. package/.next/standalone/fp-cloud-cli/fp_cli/analytics_registry.py +83 -0
  167. package/.next/standalone/fp-cloud-cli/fp_cli/app.py +492 -0
  168. package/.next/standalone/fp-cloud-cli/fp_cli/auth.py +160 -0
  169. package/.next/standalone/fp-cloud-cli/fp_cli/client.py +1694 -0
  170. package/.next/standalone/fp-cloud-cli/fp_cli/commands/__init__.py +0 -0
  171. package/.next/standalone/fp-cloud-cli/fp_cli/commands/_write.py +214 -0
  172. package/.next/standalone/fp-cloud-cli/fp_cli/commands/agent_cmds.py +407 -0
  173. package/.next/standalone/fp-cloud-cli/fp_cli/commands/alerts_cmds.py +445 -0
  174. package/.next/standalone/fp-cloud-cli/fp_cli/commands/audits_cmds.py +1054 -0
  175. package/.next/standalone/fp-cloud-cli/fp_cli/commands/auth_cmds.py +512 -0
  176. package/.next/standalone/fp-cloud-cli/fp_cli/commands/errors_cmds.py +190 -0
  177. package/.next/standalone/fp-cloud-cli/fp_cli/commands/evals_cmds.py +161 -0
  178. package/.next/standalone/fp-cloud-cli/fp_cli/commands/events_cmds.py +159 -0
  179. package/.next/standalone/fp-cloud-cli/fp_cli/commands/fleet_cmds.py +416 -0
  180. package/.next/standalone/fp-cloud-cli/fp_cli/commands/guardrails_cmds.py +148 -0
  181. package/.next/standalone/fp-cloud-cli/fp_cli/commands/incidents_cmds.py +472 -0
  182. package/.next/standalone/fp-cloud-cli/fp_cli/commands/keys_cmds.py +407 -0
  183. package/.next/standalone/fp-cloud-cli/fp_cli/commands/list_cmds.py +63 -0
  184. package/.next/standalone/fp-cloud-cli/fp_cli/commands/orgs_cmds.py +319 -0
  185. package/.next/standalone/fp-cloud-cli/fp_cli/commands/policies_cmds.py +499 -0
  186. package/.next/standalone/fp-cloud-cli/fp_cli/commands/queries_cmds.py +378 -0
  187. package/.next/standalone/fp-cloud-cli/fp_cli/commands/sessions_cmds.py +151 -0
  188. package/.next/standalone/fp-cloud-cli/fp_cli/commands/settings_cmds.py +150 -0
  189. package/.next/standalone/fp-cloud-cli/fp_cli/commands/usage_cmds.py +35 -0
  190. package/.next/standalone/fp-cloud-cli/fp_cli/commands/users_cmds.py +404 -0
  191. package/.next/standalone/fp-cloud-cli/fp_cli/config.py +330 -0
  192. package/.next/standalone/fp-cloud-cli/fp_cli/dates.py +78 -0
  193. package/.next/standalone/fp-cloud-cli/fp_cli/enforcement.py +345 -0
  194. package/.next/standalone/fp-cloud-cli/fp_cli/errors.py +98 -0
  195. package/.next/standalone/fp-cloud-cli/fp_cli/models.py +891 -0
  196. package/.next/standalone/fp-cloud-cli/fp_cli/orgs.py +30 -0
  197. package/.next/standalone/fp-cloud-cli/fp_cli/output.py +6593 -0
  198. package/.next/standalone/fp-cloud-cli/fp_cli/permissions.py +208 -0
  199. package/.next/standalone/fp-cloud-cli/fp_cli/policy_check.py +290 -0
  200. package/.next/standalone/fp-cloud-cli/fp_cli/py.typed +0 -0
  201. package/.next/standalone/fp-cloud-cli/fp_cli/select.py +322 -0
  202. package/.next/standalone/fp-cloud-cli/fp_cli/theme.py +53 -0
  203. package/.next/standalone/fp-cloud-cli/pyproject.toml +106 -0
  204. package/.next/standalone/fp-cloud-cli/skill/SKILL.md +302 -0
  205. package/.next/standalone/fp-cloud-cli/skill/agents/openai.yaml +8 -0
  206. package/.next/standalone/fp-cloud-cli/skill/references/commands.md +254 -0
  207. package/.next/standalone/fp-cloud-cli/tests/__init__.py +0 -0
  208. package/.next/standalone/fp-cloud-cli/tests/conftest.py +92 -0
  209. package/.next/standalone/fp-cloud-cli/tests/test_alerting.py +644 -0
  210. package/.next/standalone/fp-cloud-cli/tests/test_analytics.py +385 -0
  211. package/.next/standalone/fp-cloud-cli/tests/test_audits.py +950 -0
  212. package/.next/standalone/fp-cloud-cli/tests/test_auth.py +98 -0
  213. package/.next/standalone/fp-cloud-cli/tests/test_auth_mode.py +272 -0
  214. package/.next/standalone/fp-cloud-cli/tests/test_click_compat.py +118 -0
  215. package/.next/standalone/fp-cloud-cli/tests/test_client.py +299 -0
  216. package/.next/standalone/fp-cloud-cli/tests/test_commands.py +814 -0
  217. package/.next/standalone/fp-cloud-cli/tests/test_config.py +99 -0
  218. package/.next/standalone/fp-cloud-cli/tests/test_dashboards_agent.py +340 -0
  219. package/.next/standalone/fp-cloud-cli/tests/test_dates.py +76 -0
  220. package/.next/standalone/fp-cloud-cli/tests/test_enforcement_logic.py +481 -0
  221. package/.next/standalone/fp-cloud-cli/tests/test_facets.py +170 -0
  222. package/.next/standalone/fp-cloud-cli/tests/test_failproofai_home.py +722 -0
  223. package/.next/standalone/fp-cloud-cli/tests/test_fp_home_contract.py +198 -0
  224. package/.next/standalone/fp-cloud-cli/tests/test_hardening.py +186 -0
  225. package/.next/standalone/fp-cloud-cli/tests/test_help_table_coverage.py +127 -0
  226. package/.next/standalone/fp-cloud-cli/tests/test_keys_queries.py +496 -0
  227. package/.next/standalone/fp-cloud-cli/tests/test_list.py +59 -0
  228. package/.next/standalone/fp-cloud-cli/tests/test_multivalue.py +183 -0
  229. package/.next/standalone/fp-cloud-cli/tests/test_no_customer_identifiers.py +168 -0
  230. package/.next/standalone/fp-cloud-cli/tests/test_operator.py +492 -0
  231. package/.next/standalone/fp-cloud-cli/tests/test_orgs.py +692 -0
  232. package/.next/standalone/fp-cloud-cli/tests/test_output.py +1732 -0
  233. package/.next/standalone/fp-cloud-cli/tests/test_policy_check.py +191 -0
  234. package/.next/standalone/fp-cloud-cli/tests/test_readme_matches_reality.py +125 -0
  235. package/.next/standalone/fp-cloud-cli/tests/test_review_fixes.py +161 -0
  236. package/.next/standalone/fp-cloud-cli/tests/test_telemetry_completeness.py +90 -0
  237. package/.next/standalone/fp-cloud-cli/tests/test_usage.py +115 -0
  238. package/.next/standalone/fp-cloud-cli/tests/test_v1_origin_diagnostic.py +70 -0
  239. package/.next/standalone/fp-cloud-cli/tests/test_v1_routing.py +214 -0
  240. package/.next/standalone/fp-cloud-cli/tests/test_whoami.py +104 -0
  241. package/.next/standalone/fp-cloud-cli/uv.lock +552 -0
  242. package/.next/standalone/package.json +29 -22
  243. package/.next/standalone/sdk/python/CHANGELOG.md +70 -0
  244. package/.next/standalone/sdk/python/LICENSE +42 -0
  245. package/.next/standalone/sdk/python/MANIFEST.in +21 -0
  246. package/.next/standalone/sdk/python/README.md +466 -0
  247. package/.next/standalone/sdk/python/docs/README.md +249 -0
  248. package/.next/standalone/sdk/python/docs/_shared/README.md +43 -0
  249. package/.next/standalone/sdk/python/docs/_shared/__init__.py +195 -0
  250. package/.next/standalone/sdk/python/docs/crewai/README.md +328 -0
  251. package/.next/standalone/sdk/python/docs/crewai/examples/quickstart.py +61 -0
  252. package/.next/standalone/sdk/python/docs/crewai/examples/research_crew.py +92 -0
  253. package/.next/standalone/sdk/python/docs/langgraph/README.md +481 -0
  254. package/.next/standalone/sdk/python/docs/langgraph/examples/quickstart.py +51 -0
  255. package/.next/standalone/sdk/python/docs/langgraph/examples/research_agent.py +86 -0
  256. package/.next/standalone/sdk/python/docs/langgraph/examples/supervisor_handoff.py +83 -0
  257. package/.next/standalone/sdk/python/docs/llama_index/README.md +332 -0
  258. package/.next/standalone/sdk/python/docs/llama_index/examples/quickstart.py +62 -0
  259. package/.next/standalone/sdk/python/docs/llama_index/examples/research_agent.py +93 -0
  260. package/.next/standalone/sdk/python/docs/manual/README.md +491 -0
  261. package/.next/standalone/sdk/python/docs/manual/examples/quickstart.py +57 -0
  262. package/.next/standalone/sdk/python/docs/manual/examples/research_agent.py +133 -0
  263. package/.next/standalone/sdk/python/docs/pydantic_ai/README.md +323 -0
  264. package/.next/standalone/sdk/python/docs/pydantic_ai/examples/quickstart.py +48 -0
  265. package/.next/standalone/sdk/python/docs/pydantic_ai/examples/research_agent.py +94 -0
  266. package/.next/standalone/sdk/python/failproofai_sdk/__init__.py +131 -0
  267. package/.next/standalone/sdk/python/failproofai_sdk/_context.py +218 -0
  268. package/.next/standalone/sdk/python/failproofai_sdk/_environment.py +78 -0
  269. package/.next/standalone/sdk/python/failproofai_sdk/_events.py +752 -0
  270. package/.next/standalone/sdk/python/failproofai_sdk/_resolver.py +118 -0
  271. package/.next/standalone/sdk/python/failproofai_sdk/_runtime.py +21 -0
  272. package/.next/standalone/sdk/python/failproofai_sdk/_schema.py +317 -0
  273. package/.next/standalone/sdk/python/failproofai_sdk/_scopes.py +422 -0
  274. package/.next/standalone/sdk/python/failproofai_sdk/_version.py +1 -0
  275. package/.next/standalone/sdk/python/failproofai_sdk/_writer.py +750 -0
  276. package/.next/standalone/sdk/python/failproofai_sdk/integrations/__init__.py +274 -0
  277. package/.next/standalone/sdk/python/failproofai_sdk/integrations/_compat.py +247 -0
  278. package/.next/standalone/sdk/python/failproofai_sdk/integrations/_core.py +1076 -0
  279. package/.next/standalone/sdk/python/failproofai_sdk/integrations/crewai.py +1669 -0
  280. package/.next/standalone/sdk/python/failproofai_sdk/integrations/langchain.py +2151 -0
  281. package/.next/standalone/sdk/python/failproofai_sdk/integrations/llama_index.py +1588 -0
  282. package/.next/standalone/sdk/python/failproofai_sdk/integrations/pydantic_ai.py +977 -0
  283. package/.next/standalone/sdk/python/failproofai_sdk/py.typed +0 -0
  284. package/.next/standalone/sdk/python/pyproject.toml +92 -0
  285. package/.next/standalone/sdk/python/skill/SKILL.md +399 -0
  286. package/.next/standalone/sdk/python/skill/agents/openai.yaml +8 -0
  287. package/.next/standalone/sdk/python/skill/references/events.md +234 -0
  288. package/.next/standalone/sdk/python/skill/references/frameworks.md +314 -0
  289. package/.next/standalone/sdk/python/skill/references/install.md +100 -0
  290. package/.next/standalone/sdk/python/skill/references/integration.md +352 -0
  291. package/.next/standalone/sdk/python/tests/__init__.py +0 -0
  292. package/.next/standalone/sdk/python/tests/conftest.py +169 -0
  293. package/.next/standalone/sdk/python/tests/integrations/__init__.py +6 -0
  294. package/.next/standalone/sdk/python/tests/integrations/test_crewai.py +1299 -0
  295. package/.next/standalone/sdk/python/tests/integrations/test_langchain.py +2338 -0
  296. package/.next/standalone/sdk/python/tests/integrations/test_llama_index.py +1576 -0
  297. package/.next/standalone/sdk/python/tests/integrations/test_pydantic_ai.py +1102 -0
  298. package/.next/standalone/sdk/python/tests/test_context.py +410 -0
  299. package/.next/standalone/sdk/python/tests/test_docs.py +411 -0
  300. package/.next/standalone/sdk/python/tests/test_durability.py +1352 -0
  301. package/.next/standalone/sdk/python/tests/test_encoding.py +571 -0
  302. package/.next/standalone/sdk/python/tests/test_integrations.py +1127 -0
  303. package/.next/standalone/sdk/python/tests/test_no_customer_identifiers.py +214 -0
  304. package/.next/standalone/sdk/python/tests/test_packaging.py +185 -0
  305. package/.next/standalone/sdk/python/tests/test_resolver_umbrella.py +178 -0
  306. package/.next/standalone/sdk/python/tests/test_scopes.py +487 -0
  307. package/.next/standalone/sdk/python/tests/test_sdk.py +923 -0
  308. package/.next/standalone/sdk/python/tests/test_server_contract.py +650 -0
  309. package/.next/standalone/sdk/python/tests/test_site_docs.py +371 -0
  310. package/.next/standalone/sdk/python/tests/test_skill_snippets.py +165 -0
  311. package/.next/standalone/sdk/python/tests/test_spool_contract.py +287 -0
  312. package/.next/standalone/sdk/python/tests/test_spool_creation.py +360 -0
  313. package/.next/standalone/sdk/python/tests/test_wire_format.py +279 -0
  314. package/.next/standalone/sdk/python/tests/test_zero_dependencies.py +378 -0
  315. package/.next/standalone/sdk/python/uv.lock +6005 -0
  316. package/.next/standalone/server.js +1 -1
  317. package/README.md +77 -21
  318. package/bin/failproofai.mjs +145 -11
  319. package/dist/cli.mjs +4482 -2205
  320. package/dist/index.js +5 -5
  321. package/dist/worker.mjs +2399 -1978
  322. package/package.json +29 -22
  323. package/policy-pack/SHA256SUMS +2 -0
  324. package/policy-pack/failproofai-pack.json +732 -0
  325. package/policy-pack/failproofai-pack.mjs +2017 -0
  326. package/scripts/build-policy-pack.mjs +121 -0
  327. package/scripts/changelog-section.py +77 -0
  328. package/scripts/prune-standalone.mjs +3 -0
  329. package/scripts/python-version.py +232 -0
  330. package/scripts/translate-docs/cli.ts +21 -0
  331. package/scripts/translate-docs/mintlify-nav.ts +85 -13
  332. package/scripts/translate-docs/translator.ts +66 -11
  333. package/src/audit/cache.ts +40 -3
  334. package/src/audit/cli.ts +1 -1
  335. package/src/audit/index.ts +1 -1
  336. package/src/audit/replay.ts +89 -3
  337. package/src/audit/report.ts +5 -5
  338. package/src/audit/schedule-cli.ts +49 -53
  339. package/src/hooks/builtin-policies.ts +217 -579
  340. package/src/hooks/cloud-enrollment-cli.ts +66 -27
  341. package/src/hooks/cloud-managed-policies.ts +6 -1
  342. package/src/hooks/configure-wizard.ts +1 -1
  343. package/src/hooks/custom-hooks-loader.ts +89 -6
  344. package/src/hooks/fp-home.ts +92 -4
  345. package/src/hooks/fp-reset.ts +26 -2
  346. package/src/hooks/handler.ts +181 -11
  347. package/src/hooks/harness-cli.ts +79 -25
  348. package/src/hooks/hook-activity-store.ts +13 -3
  349. package/src/hooks/install-prompt.ts +25 -3
  350. package/src/hooks/manager.ts +418 -172
  351. package/src/hooks/migrations.ts +2 -2
  352. package/src/hooks/pack-cli.ts +505 -0
  353. package/src/hooks/pack-failclosed.ts +189 -0
  354. package/src/hooks/pack-manifest.ts +344 -0
  355. package/src/hooks/pack-store.ts +930 -0
  356. package/src/hooks/policy-catalog.ts +535 -0
  357. package/src/hooks/policy-evaluator.ts +24 -16
  358. package/src/hooks/policy-presets.ts +4 -2
  359. package/src/hooks/policy-registry.ts +8 -2
  360. package/src/hooks/policy-types.ts +26 -0
  361. package/src/hooks/session-pause-cli.ts +33 -9
  362. package/src/hooks/tui.ts +570 -0
  363. package/src/hooks/types.ts +15 -1
  364. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_usx0j._.js +0 -3
  365. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_zk340._.js +0 -3
  366. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0agdw2a._.js +0 -3
  367. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d1u_na._.js +0 -3
  368. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0oy4kxb._.js +0 -3
  369. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0zf034w._.js +0 -3
  370. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tvn4wf._.js +0 -3
  371. package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +0 -3
  372. package/.next/standalone/.next/server/chunks/_1ger0a2._.js +0 -3
  373. package/.next/standalone/.next/server/chunks/_1zuiiy3._.js +0 -3
  374. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_1iiwm5e._.js +0 -3
  375. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0kc8_v5._.js +0 -4
  376. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0kgy9da._.js +0 -4
  377. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0mhqk5a._.js +0 -4
  378. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0pltpn8._.js +0 -4
  379. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qkcyf-._.js +0 -4
  380. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0w0x_ok._.js +0 -4
  381. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1_dfocn._.js +0 -4
  382. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1bfex62._.js +0 -5
  383. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1kzapg5._.js +0 -6
  384. package/.next/standalone/.next/static/chunks/36fw6yk1s6x_f.js +0 -1
  385. package/.next/standalone/.next/static/chunks/3tzq0260n17ae.js +0 -6
  386. package/.next/standalone/.next/static/chunks/3wq9x0c-7ld5d.css +0 -2
  387. /package/.next/standalone/.next/static/{ZklXxyA5ygsWSQz2u_zii → nwbyWT06Ud0XdXOrVJyvS}/_buildManifest.js +0 -0
  388. /package/.next/standalone/.next/static/{ZklXxyA5ygsWSQz2u_zii → nwbyWT06Ud0XdXOrVJyvS}/_clientMiddlewareManifest.js +0 -0
  389. /package/.next/standalone/.next/static/{ZklXxyA5ygsWSQz2u_zii → nwbyWT06Ud0XdXOrVJyvS}/_ssgManifest.js +0 -0
@@ -0,0 +1,487 @@
1
+ """Tests for session() / agent() / tool_call().
2
+
3
+ The exception table in `_scopes.agent` is the contract most likely to be broken
4
+ by a well-meaning refactor, so every row of it has a test *and* every test
5
+ asserts event ORDER, not just presence: the dashboard closes the agent span at
6
+ `agent_end`, so an `error` emitted after it is attributed to nothing.
7
+ """
8
+
9
+ import asyncio
10
+ from datetime import datetime, timezone
11
+
12
+ import pytest
13
+
14
+ import failproofai_sdk
15
+ import failproofai_sdk._context as _context
16
+ import failproofai_sdk._runtime as _runtime
17
+
18
+
19
+ def indexes(entries, event_type):
20
+ return [i for i, e in enumerate(entries) if e["type"] == event_type]
21
+
22
+
23
+ def only(entries, event_type):
24
+ matches = [e for e in entries if e["type"] == event_type]
25
+ assert len(matches) == 1, f"expected one {event_type}, got {len(matches)}"
26
+ return matches[0]
27
+
28
+
29
+ # ---------------------------------------------------------------------------
30
+ # session()
31
+ # ---------------------------------------------------------------------------
32
+
33
+ def test_session_emits_no_events(events):
34
+ with failproofai_sdk.session("s-1"):
35
+ pass
36
+ assert events.entries == []
37
+
38
+
39
+ def test_session_binds_agent_id_without_emitting(events):
40
+ with failproofai_sdk.session("s-1", agent_id="worker"):
41
+ _runtime.event.agent_start()
42
+ entry = only(events.entries, "agent_start")
43
+ assert entry["session_id"] == "s-1"
44
+ assert entry["agent_id"] == "worker"
45
+
46
+
47
+ # ---------------------------------------------------------------------------
48
+ # agent() — happy path
49
+ # ---------------------------------------------------------------------------
50
+
51
+ def test_agent_brackets_the_run(events):
52
+ with failproofai_sdk.agent("planner", session_id="s-1", goal="find it"):
53
+ pass
54
+ assert events.types() == ["agent_start", "agent_end"]
55
+ start, end = events.entries
56
+ assert start["agent_id"] == "planner"
57
+ assert start["goal"] == "find it"
58
+ assert "parent_id" not in start
59
+ assert end["outcome"] == "success"
60
+
61
+
62
+ def test_agent_generates_a_session_id(events):
63
+ with failproofai_sdk.agent("planner") as ident:
64
+ assert len(ident.session_id) == 32
65
+ assert events.entries[0]["session_id"] == ident.session_id
66
+
67
+
68
+ def test_agent_custom_outcome_and_summary(events):
69
+ with failproofai_sdk.agent("a", session_id="s", outcome="partial", summary="did half"):
70
+ pass
71
+ end = only(events.entries, "agent_end")
72
+ assert end["outcome"] == "partial"
73
+ assert end["summary"] == "did half"
74
+
75
+
76
+ def test_agent_extra_fields_land_on_agent_start(events):
77
+ with failproofai_sdk.agent("a", session_id="s", framework="langgraph", fw_node="retrieve"):
78
+ pass
79
+ start = only(events.entries, "agent_start")
80
+ assert start["framework"] == "langgraph"
81
+ assert start["fw_node"] == "retrieve"
82
+
83
+
84
+ def test_agent_default_id_is_main(events):
85
+ with failproofai_sdk.agent(session_id="s"):
86
+ pass
87
+ assert events.entries[0]["agent_id"] == "main"
88
+
89
+
90
+ # ---------------------------------------------------------------------------
91
+ # Nesting and parent_id
92
+ # ---------------------------------------------------------------------------
93
+
94
+ def test_parent_ids_follow_the_stack(events):
95
+ with failproofai_sdk.agent("a", session_id="s"):
96
+ with failproofai_sdk.agent("b"):
97
+ with failproofai_sdk.agent("c"):
98
+ assert failproofai_sdk.current().depth == 3
99
+ assert failproofai_sdk.current().parent_id == "b"
100
+
101
+ starts = [e for e in events.entries if e["type"] == "agent_start"]
102
+ assert [e["agent_id"] for e in starts] == ["a", "b", "c"]
103
+ assert "parent_id" not in starts[0]
104
+ assert starts[1]["parent_id"] == "a"
105
+ assert starts[2]["parent_id"] == "b"
106
+
107
+
108
+ def test_explicit_parent_none_forces_a_root_span(events):
109
+ with failproofai_sdk.agent("a", session_id="s"):
110
+ with failproofai_sdk.agent("b", parent_id=None):
111
+ pass
112
+ start_b = [e for e in events.entries if e["type"] == "agent_start"][1]
113
+ assert "parent_id" not in start_b
114
+
115
+
116
+ def test_explicit_parent_string_overrides(events):
117
+ with failproofai_sdk.agent("a", session_id="s"):
118
+ with failproofai_sdk.agent("b", parent_id="somewhere-else"):
119
+ pass
120
+ start_b = [e for e in events.entries if e["type"] == "agent_start"][1]
121
+ assert start_b["parent_id"] == "somewhere-else"
122
+
123
+
124
+ def test_nested_agent_inherits_the_session(events):
125
+ with failproofai_sdk.agent("a", session_id="s-outer"):
126
+ with failproofai_sdk.agent("b"):
127
+ pass
128
+ assert {e["session_id"] for e in events.entries} == {"s-outer"}
129
+
130
+
131
+ def test_stack_unwinds_after_an_exception_through_three_scopes(events):
132
+ class Boom(Exception):
133
+ pass
134
+
135
+ try:
136
+ with failproofai_sdk.agent("a", session_id="s"):
137
+ with failproofai_sdk.agent("b"):
138
+ with failproofai_sdk.agent("c"):
139
+ raise Boom("deep")
140
+ except Boom as exc:
141
+ assert str(exc) == "deep"
142
+ else:
143
+ pytest.fail("Boom was not raised")
144
+
145
+ assert failproofai_sdk.current().depth == 0
146
+ assert _context.snapshot() == (None, ())
147
+ # Each level reports the failure on its own span, innermost first.
148
+ assert events.types() == [
149
+ "agent_start", "agent_start", "agent_start",
150
+ "error", "agent_end",
151
+ "error", "agent_end",
152
+ "error", "agent_end",
153
+ ]
154
+ ends = [e for e in events.entries if e["type"] == "agent_end"]
155
+ assert [e["agent_id"] for e in ends] == ["c", "b", "a"]
156
+
157
+
158
+ def test_stack_unwinds_even_when_emission_fails(events, monkeypatch):
159
+ real_agent_end = _runtime.event.agent_end
160
+
161
+ def explode(**kwargs):
162
+ if kwargs.get("agent_id") == "b":
163
+ raise RuntimeError("writer is down")
164
+ return real_agent_end(**kwargs)
165
+
166
+ monkeypatch.setattr(_runtime.event, "agent_end", explode)
167
+
168
+ with failproofai_sdk.agent("a", session_id="s"):
169
+ with pytest.raises(RuntimeError, match="writer is down"):
170
+ with failproofai_sdk.agent("b"):
171
+ pass
172
+ assert failproofai_sdk.current().agent_id == "a"
173
+ assert failproofai_sdk.current().depth == 1
174
+
175
+
176
+ def test_failed_agent_start_does_not_leave_a_frame(events):
177
+ with pytest.raises(ValueError, match="Reserved field"):
178
+ with failproofai_sdk.agent("a", session_id="s", timestamp="nope"):
179
+ pass
180
+ assert _context.snapshot() == (None, ())
181
+
182
+
183
+ # ---------------------------------------------------------------------------
184
+ # The exception table — one test per row, asserting order
185
+ # ---------------------------------------------------------------------------
186
+
187
+ def test_no_exception_emits_only_agent_end(events):
188
+ with failproofai_sdk.agent("a", session_id="s"):
189
+ pass
190
+ assert events.types() == ["agent_start", "agent_end"]
191
+ assert only(events.entries, "agent_end")["outcome"] == "success"
192
+
193
+
194
+ def test_exception_emits_error_before_agent_end(events):
195
+ try:
196
+ with failproofai_sdk.agent("a", session_id="s"):
197
+ raise ValueError("nope")
198
+ except ValueError as exc:
199
+ assert str(exc) == "nope"
200
+ else:
201
+ pytest.fail("ValueError was not raised")
202
+
203
+ types = events.types()
204
+ assert types.index("error") < types.index("agent_end")
205
+ err = only(events.entries, "error")
206
+ assert err["error_type"] == "ValueError"
207
+ assert err["message"] == "nope"
208
+ assert "ValueError: nope" in err["traceback"]
209
+ end = only(events.entries, "agent_end")
210
+ # "failed", never "failure": only error|failed|timeout|rejected count as a
211
+ # failure server-side.
212
+ assert end["outcome"] == "failed"
213
+
214
+
215
+ def _assert_failed_base_exception(events, expected_type):
216
+ types = events.types()
217
+ assert types.index("error") < types.index("agent_end")
218
+ assert only(events.entries, "agent_end")["outcome"] == "failed"
219
+ assert only(events.entries, "error")["error_type"] == expected_type.__name__
220
+
221
+
222
+ def test_keyboard_interrupt_is_reported_as_failed(events):
223
+ try:
224
+ with failproofai_sdk.agent("a", session_id="s"):
225
+ raise KeyboardInterrupt()
226
+ except KeyboardInterrupt:
227
+ pass
228
+ else:
229
+ pytest.fail("KeyboardInterrupt was not raised")
230
+ _assert_failed_base_exception(events, KeyboardInterrupt)
231
+
232
+
233
+ def test_system_exit_is_reported_as_failed(events):
234
+ try:
235
+ with failproofai_sdk.agent("a", session_id="s"):
236
+ raise SystemExit()
237
+ except SystemExit:
238
+ pass
239
+ else:
240
+ pytest.fail("SystemExit was not raised")
241
+ _assert_failed_base_exception(events, SystemExit)
242
+
243
+
244
+ def _assert_cancelled_without_error(events):
245
+ assert events.types() == ["agent_start", "agent_end"]
246
+ assert only(events.entries, "agent_end")["outcome"] == "cancelled"
247
+
248
+
249
+ def test_cancelled_error_is_not_an_error(events):
250
+ try:
251
+ with failproofai_sdk.agent("a", session_id="s"):
252
+ raise asyncio.CancelledError()
253
+ except asyncio.CancelledError:
254
+ pass
255
+ else:
256
+ pytest.fail("CancelledError was not raised")
257
+ _assert_cancelled_without_error(events)
258
+
259
+
260
+ def test_generator_exit_is_not_an_error(events):
261
+ try:
262
+ with failproofai_sdk.agent("a", session_id="s"):
263
+ raise GeneratorExit()
264
+ except GeneratorExit:
265
+ pass
266
+ else:
267
+ pytest.fail("GeneratorExit was not raised")
268
+ _assert_cancelled_without_error(events)
269
+
270
+
271
+ def test_real_task_cancellation_is_reported_as_cancelled(events):
272
+ async def main():
273
+ started = asyncio.Event()
274
+
275
+ async def body():
276
+ async with failproofai_sdk.agent("a", session_id="s"):
277
+ started.set()
278
+ await asyncio.sleep(60)
279
+
280
+ task = asyncio.create_task(body())
281
+ await started.wait()
282
+ task.cancel()
283
+ with pytest.raises(asyncio.CancelledError):
284
+ cancelled_result = await task
285
+ pytest.fail(f"cancelled task returned {cancelled_result!r}")
286
+
287
+ asyncio.run(main())
288
+ assert events.types() == ["agent_start", "agent_end"]
289
+ assert only(events.entries, "agent_end")["outcome"] == "cancelled"
290
+
291
+
292
+ # ---------------------------------------------------------------------------
293
+ # tool_call()
294
+ # ---------------------------------------------------------------------------
295
+
296
+ def test_tool_call_pairs_and_carries_output(events):
297
+ with failproofai_sdk.agent("a", session_id="s"):
298
+ with failproofai_sdk.tool_call("web_search", input={"q": "x"}) as t:
299
+ t.output = {"hits": 3}
300
+ call_id = t.id
301
+
302
+ assert events.types() == ["agent_start", "tool_use", "tool_result", "agent_end"]
303
+ use = only(events.entries, "tool_use")
304
+ res = only(events.entries, "tool_result")
305
+ assert use["tool_call_id"] == res["tool_call_id"] == call_id
306
+ assert use["input"] == {"q": "x"}
307
+ assert res["output"] == {"hits": 3}
308
+ assert "error" not in res
309
+ assert isinstance(res["duration_ms"], int)
310
+
311
+
312
+ def test_tool_call_id_is_read_only():
313
+ box = failproofai_sdk._scopes.ToolCall("abc")
314
+ assert box.id == "abc"
315
+ with pytest.raises(AttributeError):
316
+ box.id = "other"
317
+ # __slots__: no stray attributes
318
+ with pytest.raises(AttributeError):
319
+ box.whatever = 1
320
+
321
+
322
+ def test_tool_call_accepts_an_explicit_id(events):
323
+ with failproofai_sdk.agent("a", session_id="s"):
324
+ with failproofai_sdk.tool_call("t", tool_call_id="run-42") as t:
325
+ assert t.id == "run-42"
326
+ assert only(events.entries, "tool_use")["tool_call_id"] == "run-42"
327
+
328
+
329
+ def test_tool_call_failure_emits_tool_result_error_and_no_error_event(events):
330
+ with failproofai_sdk.agent("a", session_id="s"):
331
+ try:
332
+ with failproofai_sdk.tool_call("t"):
333
+ raise TypeError("bad arg")
334
+ except TypeError as exc:
335
+ assert str(exc) == "bad arg"
336
+ else:
337
+ pytest.fail("TypeError was not raised")
338
+
339
+ # No `error` event from the tool: an exception the agent loop catches is
340
+ # not a run-level error.
341
+ assert events.types() == ["agent_start", "tool_use", "tool_result", "agent_end"]
342
+ assert only(events.entries, "tool_result")["error"] == "TypeError: bad arg"
343
+ assert only(events.entries, "agent_end")["outcome"] == "success"
344
+
345
+
346
+ def test_propagating_tool_failure_is_reported_exactly_once(events):
347
+ try:
348
+ with failproofai_sdk.agent("a", session_id="s"):
349
+ with failproofai_sdk.tool_call("t"):
350
+ raise TypeError("bad arg")
351
+ except TypeError as exc:
352
+ assert str(exc) == "bad arg"
353
+ else:
354
+ pytest.fail("TypeError was not raised")
355
+
356
+ assert events.types() == [
357
+ "agent_start", "tool_use", "tool_result", "error", "agent_end",
358
+ ]
359
+ assert len(indexes(events.entries, "error")) == 1
360
+ types = events.types()
361
+ assert types.index("error") < types.index("agent_end")
362
+
363
+
364
+ def test_tool_call_uses_the_enclosing_agent_id(events):
365
+ with failproofai_sdk.agent("outer", session_id="s"):
366
+ with failproofai_sdk.agent("inner"):
367
+ with failproofai_sdk.tool_call("t"):
368
+ pass
369
+ use = only(events.entries, "tool_use")
370
+ res = only(events.entries, "tool_result")
371
+ assert use["agent_id"] == res["agent_id"] == "inner"
372
+
373
+
374
+ def test_tool_call_without_a_session_raises_naming_the_fix(events):
375
+ with pytest.raises(TypeError, match="propagate"):
376
+ with failproofai_sdk.tool_call("t"):
377
+ pass
378
+
379
+
380
+ def test_awkward_payload_does_not_break_the_scope(events):
381
+ """A non-JSON-serialisable output must not stop `agent_end` landing.
382
+
383
+ Coercion happens in the writer (`json.dumps(default=str)`), so the scope
384
+ itself must pass the object through untouched and still close the span.
385
+ """
386
+ value = datetime(2026, 7, 29, 12, 0, 0, tzinfo=timezone.utc)
387
+ with failproofai_sdk.agent("a", session_id="s"):
388
+ with failproofai_sdk.tool_call("t") as call:
389
+ call.output = value
390
+
391
+ assert events.types() == ["agent_start", "tool_use", "tool_result", "agent_end"]
392
+ assert only(events.entries, "tool_result")["output"] is value
393
+
394
+
395
+ def test_awkward_payload_survives_the_real_writer(tmp_path):
396
+ """The end-to-end version: through the actual JSONL writer, on disk."""
397
+ import json
398
+
399
+ from failproofai_sdk._events import EventNamespace
400
+ from failproofai_sdk._writer import EventWriter
401
+
402
+ writer = EventWriter(flush_interval=3600)
403
+ namespace = EventNamespace(writer)
404
+ original = _runtime.event
405
+ _runtime.event = namespace
406
+ try:
407
+ with failproofai_sdk.agent("a", session_id="s"):
408
+ with failproofai_sdk.tool_call("t") as call:
409
+ call.output = datetime(2026, 7, 29, 12, 0, 0, tzinfo=timezone.utc)
410
+ writer.flush_now()
411
+ finally:
412
+ _runtime.event = original
413
+
414
+ path = next((tmp_path / "events").glob("*.jsonl"))
415
+ parsed = [json.loads(line) for line in path.read_text().splitlines()]
416
+ assert [e["type"] for e in parsed] == [
417
+ "agent_start", "tool_use", "tool_result", "agent_end",
418
+ ]
419
+ assert parsed[2]["output"] == "2026-07-29 12:00:00+00:00"
420
+
421
+
422
+ # ---------------------------------------------------------------------------
423
+ # `async with` parity — the same body, both syntaxes, byte-identical dicts
424
+ # ---------------------------------------------------------------------------
425
+
426
+ def _scrub(entries):
427
+ """Drop the only fields that legitimately differ between two runs."""
428
+ return [{k: v for k, v in e.items() if k not in ("timestamp", "duration_ms")} for e in entries]
429
+
430
+
431
+ def _sync_body():
432
+ with failproofai_sdk.agent("planner", session_id="s-parity", goal="g", fw_node="n"):
433
+ with failproofai_sdk.agent("worker"):
434
+ with failproofai_sdk.tool_call("search", tool_call_id="tc-1", input={"q": "x"}) as t:
435
+ t.output = ["a", "b"]
436
+
437
+
438
+ async def _async_body():
439
+ async with failproofai_sdk.agent("planner", session_id="s-parity", goal="g", fw_node="n"):
440
+ async with failproofai_sdk.agent("worker"):
441
+ async with failproofai_sdk.tool_call("search", tool_call_id="tc-1", input={"q": "x"}) as t:
442
+ t.output = ["a", "b"]
443
+
444
+
445
+ def _sync_failing():
446
+ with pytest.raises(ValueError):
447
+ with failproofai_sdk.agent("planner", session_id="s-parity"):
448
+ with failproofai_sdk.tool_call("search", tool_call_id="tc-1"):
449
+ raise ValueError("nope")
450
+
451
+
452
+ async def _async_failing():
453
+ with pytest.raises(ValueError):
454
+ async with failproofai_sdk.agent("planner", session_id="s-parity"):
455
+ async with failproofai_sdk.tool_call("search", tool_call_id="tc-1"):
456
+ raise ValueError("nope")
457
+
458
+
459
+ @pytest.mark.parametrize(
460
+ "sync_body,async_body",
461
+ [(_sync_body, _async_body), (_sync_failing, _async_failing)],
462
+ ids=["happy", "failing"],
463
+ )
464
+ def test_async_with_is_identical_to_with(events, sync_body, async_body):
465
+ sync_body()
466
+ sync_entries = _scrub(events.entries)
467
+ events.entries.clear()
468
+
469
+ asyncio.run(async_body())
470
+ async_entries = _scrub(events.entries)
471
+
472
+ # `traceback` embeds the frame that raised, which differs by construction.
473
+ for entry in sync_entries + async_entries:
474
+ entry.pop("traceback", None)
475
+
476
+ assert sync_entries == async_entries
477
+ assert sync_entries # not vacuously equal
478
+
479
+
480
+ def test_async_session_binds_and_unbinds(events):
481
+ async def main():
482
+ async with failproofai_sdk.session("s-async") as sid:
483
+ assert sid == "s-async"
484
+ assert failproofai_sdk.current().session_id == "s-async"
485
+
486
+ asyncio.run(main())
487
+ assert failproofai_sdk.current().session_id is None