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.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +6 -6
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page.js +2 -2
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js +2 -2
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/api/audit/invite/route.js +3 -2
- package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route.js +5 -4
- package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js +2 -2
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +4 -3
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/logout/route.js +4 -4
- package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route.js +4 -4
- package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/audit/page.js +2 -2
- package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js +2 -2
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +66 -22
- package/.next/standalone/.next/server/app/policies/page.js +5 -4
- package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page.js +2 -2
- package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js +2 -2
- package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +4 -4
- package/.next/standalone/.next/server/app/settings/page.js +1 -1
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/chunks/{[externals]__1qzqcio._.js → [externals]__0e32-7c._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[externals]__1s462yl._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__01eqny5._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_0xu5z._.js +1 -1
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1p8poxd._.js → [root-of-the-server]__0igxt32._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0neqlu-._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0t9oqnn._.js +3 -0
- package/.next/standalone/.next/server/chunks/_0bs-v8p._.js +3 -0
- package/.next/standalone/.next/server/chunks/_0tovk6q._.js +3 -0
- package/.next/standalone/.next/server/chunks/_0trp3yc._.js +3 -0
- package/.next/standalone/.next/server/chunks/_185gyk9._.js +3 -0
- package/.next/standalone/.next/server/chunks/_1ek68ln._.js +5 -6
- package/.next/standalone/.next/server/chunks/lib_telemetry-id_ts_1k8gj9o._.js +3 -0
- 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
- 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
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
- package/.next/standalone/.next/server/chunks/src_hooks_0xbw3bu._.js +12 -0
- package/.next/standalone/.next/server/chunks/src_hooks_fp-home_ts_09kv0bn._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__013jr2b._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01wy8d-._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02npjtd._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0spkm68._.js → [root-of-the-server]__07gm3zl._.js} +21 -20
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0da85px._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ftmoxc._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0oa1lav._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0p-5p8u._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s740oi._.js +6 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__07tbbf3._.js → [root-of-the-server]__0zig5sv._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__192nhvh._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1p2otjt._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/{_0lvyuv4._.js → _00e9tnf._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_0u5zauv._.js → _12l4a_k._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1u8-lu2._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +13 -13
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_08o7bqo._.js +10 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-home_ts_0je3xkv._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/middleware.js +1 -1
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +71 -27
- package/.next/standalone/.next/static/chunks/{37fcpc36x9gpe.js → 0eqky-7n7dgdm.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1ide1wl2f7zi1.js → 0sa9v5mhc8861.js} +13 -13
- package/.next/standalone/.next/static/chunks/1mfzsja6ftim5.css +2 -0
- package/.next/standalone/.next/static/chunks/{3k7mxbp9hiom0.js → 1nuqytbta44af.js} +1 -1
- package/.next/standalone/.next/static/chunks/1sl2xmn9inx3y.js +6 -0
- package/.next/standalone/.next/static/chunks/{2_2lhuojq2xop.js → 2aawsjld9ied_.js} +1 -1
- package/.next/standalone/.next/static/chunks/2gn7ut4svofm2.js +1 -0
- package/.next/standalone/.next/static/chunks/{31s1smp-g7gks.js → 2hs7ycvsav7v2.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0k5050ezjvv49.js → 2i2yt3hzjredm.js} +1 -1
- package/.next/standalone/.next/static/chunks/{3c808qrfcq0im.js → 35xg6retpe6rp.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2zpp1we2jv6tb.js → 3y54nw0i7dsjl.js} +1 -1
- package/.next/standalone/SECURITY.md +5 -4
- package/.next/standalone/app/actions/get-hooks-config.ts +108 -17
- package/.next/standalone/app/actions/pack-actions.ts +153 -0
- package/.next/standalone/app/audit/_components/run-progress.tsx +1 -1
- package/.next/standalone/app/audit/_components/share-templates.ts +13 -13
- package/.next/standalone/app/policies/hooks-client.tsx +320 -14
- package/.next/standalone/components/navbar.tsx +2 -28
- package/.next/standalone/components/reach-developers.tsx +8 -1
- package/.next/standalone/docs-old/agenteye/python-sdk-skill.mdx +1 -1
- package/.next/standalone/docs-old/agenteye/python-sdk.mdx +59 -35
- package/.next/standalone/docs-old/i18n/README.ar.md +1 -0
- package/.next/standalone/docs-old/i18n/README.de.md +1 -0
- package/.next/standalone/docs-old/i18n/README.es.md +1 -0
- package/.next/standalone/docs-old/i18n/README.fr.md +1 -0
- package/.next/standalone/docs-old/i18n/README.he.md +1 -0
- package/.next/standalone/docs-old/i18n/README.hi.md +1 -0
- package/.next/standalone/docs-old/i18n/README.it.md +1 -0
- package/.next/standalone/docs-old/i18n/README.ja.md +1 -0
- package/.next/standalone/docs-old/i18n/README.ko.md +1 -0
- package/.next/standalone/docs-old/i18n/README.pt-br.md +1 -0
- package/.next/standalone/docs-old/i18n/README.ru.md +1 -0
- package/.next/standalone/docs-old/i18n/README.tr.md +1 -0
- package/.next/standalone/docs-old/i18n/README.vi.md +1 -0
- package/.next/standalone/docs-old/i18n/README.zh.md +1 -0
- package/.next/standalone/fp-cloud-cli/CHANGELOG.md +431 -0
- package/.next/standalone/fp-cloud-cli/LICENSE +42 -0
- package/.next/standalone/fp-cloud-cli/MANIFEST.in +10 -0
- package/.next/standalone/fp-cloud-cli/README.md +259 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/__init__.py +10 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/__main__.py +4 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/_click_compat.py +64 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/_context.py +332 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/_version.py +1 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/analytics.py +432 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/analytics_config.py +77 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/analytics_registry.py +83 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/app.py +492 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/auth.py +160 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/client.py +1694 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/__init__.py +0 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/_write.py +214 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/agent_cmds.py +407 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/alerts_cmds.py +445 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/audits_cmds.py +1054 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/auth_cmds.py +512 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/errors_cmds.py +190 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/evals_cmds.py +161 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/events_cmds.py +159 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/fleet_cmds.py +416 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/guardrails_cmds.py +148 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/incidents_cmds.py +472 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/keys_cmds.py +407 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/list_cmds.py +63 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/orgs_cmds.py +319 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/policies_cmds.py +499 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/queries_cmds.py +378 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/sessions_cmds.py +151 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/settings_cmds.py +150 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/usage_cmds.py +35 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/commands/users_cmds.py +404 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/config.py +330 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/dates.py +78 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/enforcement.py +345 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/errors.py +98 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/models.py +891 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/orgs.py +30 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/output.py +6593 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/permissions.py +208 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/policy_check.py +290 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/py.typed +0 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/select.py +322 -0
- package/.next/standalone/fp-cloud-cli/fp_cli/theme.py +53 -0
- package/.next/standalone/fp-cloud-cli/pyproject.toml +106 -0
- package/.next/standalone/fp-cloud-cli/skill/SKILL.md +302 -0
- package/.next/standalone/fp-cloud-cli/skill/agents/openai.yaml +8 -0
- package/.next/standalone/fp-cloud-cli/skill/references/commands.md +254 -0
- package/.next/standalone/fp-cloud-cli/tests/__init__.py +0 -0
- package/.next/standalone/fp-cloud-cli/tests/conftest.py +92 -0
- package/.next/standalone/fp-cloud-cli/tests/test_alerting.py +644 -0
- package/.next/standalone/fp-cloud-cli/tests/test_analytics.py +385 -0
- package/.next/standalone/fp-cloud-cli/tests/test_audits.py +950 -0
- package/.next/standalone/fp-cloud-cli/tests/test_auth.py +98 -0
- package/.next/standalone/fp-cloud-cli/tests/test_auth_mode.py +272 -0
- package/.next/standalone/fp-cloud-cli/tests/test_click_compat.py +118 -0
- package/.next/standalone/fp-cloud-cli/tests/test_client.py +299 -0
- package/.next/standalone/fp-cloud-cli/tests/test_commands.py +814 -0
- package/.next/standalone/fp-cloud-cli/tests/test_config.py +99 -0
- package/.next/standalone/fp-cloud-cli/tests/test_dashboards_agent.py +340 -0
- package/.next/standalone/fp-cloud-cli/tests/test_dates.py +76 -0
- package/.next/standalone/fp-cloud-cli/tests/test_enforcement_logic.py +481 -0
- package/.next/standalone/fp-cloud-cli/tests/test_facets.py +170 -0
- package/.next/standalone/fp-cloud-cli/tests/test_failproofai_home.py +722 -0
- package/.next/standalone/fp-cloud-cli/tests/test_fp_home_contract.py +198 -0
- package/.next/standalone/fp-cloud-cli/tests/test_hardening.py +186 -0
- package/.next/standalone/fp-cloud-cli/tests/test_help_table_coverage.py +127 -0
- package/.next/standalone/fp-cloud-cli/tests/test_keys_queries.py +496 -0
- package/.next/standalone/fp-cloud-cli/tests/test_list.py +59 -0
- package/.next/standalone/fp-cloud-cli/tests/test_multivalue.py +183 -0
- package/.next/standalone/fp-cloud-cli/tests/test_no_customer_identifiers.py +168 -0
- package/.next/standalone/fp-cloud-cli/tests/test_operator.py +492 -0
- package/.next/standalone/fp-cloud-cli/tests/test_orgs.py +692 -0
- package/.next/standalone/fp-cloud-cli/tests/test_output.py +1732 -0
- package/.next/standalone/fp-cloud-cli/tests/test_policy_check.py +191 -0
- package/.next/standalone/fp-cloud-cli/tests/test_readme_matches_reality.py +125 -0
- package/.next/standalone/fp-cloud-cli/tests/test_review_fixes.py +161 -0
- package/.next/standalone/fp-cloud-cli/tests/test_telemetry_completeness.py +90 -0
- package/.next/standalone/fp-cloud-cli/tests/test_usage.py +115 -0
- package/.next/standalone/fp-cloud-cli/tests/test_v1_origin_diagnostic.py +70 -0
- package/.next/standalone/fp-cloud-cli/tests/test_v1_routing.py +214 -0
- package/.next/standalone/fp-cloud-cli/tests/test_whoami.py +104 -0
- package/.next/standalone/fp-cloud-cli/uv.lock +552 -0
- package/.next/standalone/package.json +29 -22
- package/.next/standalone/sdk/python/CHANGELOG.md +70 -0
- package/.next/standalone/sdk/python/LICENSE +42 -0
- package/.next/standalone/sdk/python/MANIFEST.in +21 -0
- package/.next/standalone/sdk/python/README.md +466 -0
- package/.next/standalone/sdk/python/docs/README.md +249 -0
- package/.next/standalone/sdk/python/docs/_shared/README.md +43 -0
- package/.next/standalone/sdk/python/docs/_shared/__init__.py +195 -0
- package/.next/standalone/sdk/python/docs/crewai/README.md +328 -0
- package/.next/standalone/sdk/python/docs/crewai/examples/quickstart.py +61 -0
- package/.next/standalone/sdk/python/docs/crewai/examples/research_crew.py +92 -0
- package/.next/standalone/sdk/python/docs/langgraph/README.md +481 -0
- package/.next/standalone/sdk/python/docs/langgraph/examples/quickstart.py +51 -0
- package/.next/standalone/sdk/python/docs/langgraph/examples/research_agent.py +86 -0
- package/.next/standalone/sdk/python/docs/langgraph/examples/supervisor_handoff.py +83 -0
- package/.next/standalone/sdk/python/docs/llama_index/README.md +332 -0
- package/.next/standalone/sdk/python/docs/llama_index/examples/quickstart.py +62 -0
- package/.next/standalone/sdk/python/docs/llama_index/examples/research_agent.py +93 -0
- package/.next/standalone/sdk/python/docs/manual/README.md +491 -0
- package/.next/standalone/sdk/python/docs/manual/examples/quickstart.py +57 -0
- package/.next/standalone/sdk/python/docs/manual/examples/research_agent.py +133 -0
- package/.next/standalone/sdk/python/docs/pydantic_ai/README.md +323 -0
- package/.next/standalone/sdk/python/docs/pydantic_ai/examples/quickstart.py +48 -0
- package/.next/standalone/sdk/python/docs/pydantic_ai/examples/research_agent.py +94 -0
- package/.next/standalone/sdk/python/failproofai_sdk/__init__.py +131 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_context.py +218 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_environment.py +78 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_events.py +752 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_resolver.py +118 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_runtime.py +21 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_schema.py +317 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_scopes.py +422 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_version.py +1 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_writer.py +750 -0
- package/.next/standalone/sdk/python/failproofai_sdk/integrations/__init__.py +274 -0
- package/.next/standalone/sdk/python/failproofai_sdk/integrations/_compat.py +247 -0
- package/.next/standalone/sdk/python/failproofai_sdk/integrations/_core.py +1076 -0
- package/.next/standalone/sdk/python/failproofai_sdk/integrations/crewai.py +1669 -0
- package/.next/standalone/sdk/python/failproofai_sdk/integrations/langchain.py +2151 -0
- package/.next/standalone/sdk/python/failproofai_sdk/integrations/llama_index.py +1588 -0
- package/.next/standalone/sdk/python/failproofai_sdk/integrations/pydantic_ai.py +977 -0
- package/.next/standalone/sdk/python/failproofai_sdk/py.typed +0 -0
- package/.next/standalone/sdk/python/pyproject.toml +92 -0
- package/.next/standalone/sdk/python/skill/SKILL.md +399 -0
- package/.next/standalone/sdk/python/skill/agents/openai.yaml +8 -0
- package/.next/standalone/sdk/python/skill/references/events.md +234 -0
- package/.next/standalone/sdk/python/skill/references/frameworks.md +314 -0
- package/.next/standalone/sdk/python/skill/references/install.md +100 -0
- package/.next/standalone/sdk/python/skill/references/integration.md +352 -0
- package/.next/standalone/sdk/python/tests/__init__.py +0 -0
- package/.next/standalone/sdk/python/tests/conftest.py +169 -0
- package/.next/standalone/sdk/python/tests/integrations/__init__.py +6 -0
- package/.next/standalone/sdk/python/tests/integrations/test_crewai.py +1299 -0
- package/.next/standalone/sdk/python/tests/integrations/test_langchain.py +2338 -0
- package/.next/standalone/sdk/python/tests/integrations/test_llama_index.py +1576 -0
- package/.next/standalone/sdk/python/tests/integrations/test_pydantic_ai.py +1102 -0
- package/.next/standalone/sdk/python/tests/test_context.py +410 -0
- package/.next/standalone/sdk/python/tests/test_docs.py +411 -0
- package/.next/standalone/sdk/python/tests/test_durability.py +1352 -0
- package/.next/standalone/sdk/python/tests/test_encoding.py +571 -0
- package/.next/standalone/sdk/python/tests/test_integrations.py +1127 -0
- package/.next/standalone/sdk/python/tests/test_no_customer_identifiers.py +214 -0
- package/.next/standalone/sdk/python/tests/test_packaging.py +185 -0
- package/.next/standalone/sdk/python/tests/test_resolver_umbrella.py +178 -0
- package/.next/standalone/sdk/python/tests/test_scopes.py +487 -0
- package/.next/standalone/sdk/python/tests/test_sdk.py +923 -0
- package/.next/standalone/sdk/python/tests/test_server_contract.py +650 -0
- package/.next/standalone/sdk/python/tests/test_site_docs.py +371 -0
- package/.next/standalone/sdk/python/tests/test_skill_snippets.py +165 -0
- package/.next/standalone/sdk/python/tests/test_spool_contract.py +287 -0
- package/.next/standalone/sdk/python/tests/test_spool_creation.py +360 -0
- package/.next/standalone/sdk/python/tests/test_wire_format.py +279 -0
- package/.next/standalone/sdk/python/tests/test_zero_dependencies.py +378 -0
- package/.next/standalone/sdk/python/uv.lock +6005 -0
- package/.next/standalone/server.js +1 -1
- package/README.md +77 -21
- package/bin/failproofai.mjs +145 -11
- package/dist/cli.mjs +4482 -2205
- package/dist/index.js +5 -5
- package/dist/worker.mjs +2399 -1978
- package/package.json +29 -22
- package/policy-pack/SHA256SUMS +2 -0
- package/policy-pack/failproofai-pack.json +732 -0
- package/policy-pack/failproofai-pack.mjs +2017 -0
- package/scripts/build-policy-pack.mjs +121 -0
- package/scripts/changelog-section.py +77 -0
- package/scripts/prune-standalone.mjs +3 -0
- package/scripts/python-version.py +232 -0
- package/scripts/translate-docs/cli.ts +21 -0
- package/scripts/translate-docs/mintlify-nav.ts +85 -13
- package/scripts/translate-docs/translator.ts +66 -11
- package/src/audit/cache.ts +40 -3
- package/src/audit/cli.ts +1 -1
- package/src/audit/index.ts +1 -1
- package/src/audit/replay.ts +89 -3
- package/src/audit/report.ts +5 -5
- package/src/audit/schedule-cli.ts +49 -53
- package/src/hooks/builtin-policies.ts +217 -579
- package/src/hooks/cloud-enrollment-cli.ts +66 -27
- package/src/hooks/cloud-managed-policies.ts +6 -1
- package/src/hooks/configure-wizard.ts +1 -1
- package/src/hooks/custom-hooks-loader.ts +89 -6
- package/src/hooks/fp-home.ts +92 -4
- package/src/hooks/fp-reset.ts +26 -2
- package/src/hooks/handler.ts +181 -11
- package/src/hooks/harness-cli.ts +79 -25
- package/src/hooks/hook-activity-store.ts +13 -3
- package/src/hooks/install-prompt.ts +25 -3
- package/src/hooks/manager.ts +418 -172
- package/src/hooks/migrations.ts +2 -2
- package/src/hooks/pack-cli.ts +505 -0
- package/src/hooks/pack-failclosed.ts +189 -0
- package/src/hooks/pack-manifest.ts +344 -0
- package/src/hooks/pack-store.ts +930 -0
- package/src/hooks/policy-catalog.ts +535 -0
- package/src/hooks/policy-evaluator.ts +24 -16
- package/src/hooks/policy-presets.ts +4 -2
- package/src/hooks/policy-registry.ts +8 -2
- package/src/hooks/policy-types.ts +26 -0
- package/src/hooks/session-pause-cli.ts +33 -9
- package/src/hooks/tui.ts +570 -0
- package/src/hooks/types.ts +15 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_usx0j._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_zk340._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0agdw2a._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d1u_na._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0oy4kxb._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0zf034w._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tvn4wf._.js +0 -3
- package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +0 -3
- package/.next/standalone/.next/server/chunks/_1ger0a2._.js +0 -3
- package/.next/standalone/.next/server/chunks/_1zuiiy3._.js +0 -3
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_1iiwm5e._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0kc8_v5._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0kgy9da._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0mhqk5a._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0pltpn8._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qkcyf-._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0w0x_ok._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1_dfocn._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1bfex62._.js +0 -5
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1kzapg5._.js +0 -6
- package/.next/standalone/.next/static/chunks/36fw6yk1s6x_f.js +0 -1
- package/.next/standalone/.next/static/chunks/3tzq0260n17ae.js +0 -6
- package/.next/standalone/.next/static/chunks/3wq9x0c-7ld5d.css +0 -2
- /package/.next/standalone/.next/static/{ZklXxyA5ygsWSQz2u_zii → nwbyWT06Ud0XdXOrVJyvS}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{ZklXxyA5ygsWSQz2u_zii → nwbyWT06Ud0XdXOrVJyvS}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{ZklXxyA5ygsWSQz2u_zii → nwbyWT06Ud0XdXOrVJyvS}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# Event catalog
|
|
2
|
+
|
|
3
|
+
Every method lives on `failproofai_sdk.event`, is **keyword-only**, and returns `None`.
|
|
4
|
+
Nothing here blocks or does I/O — the call queues the event and returns.
|
|
5
|
+
|
|
6
|
+
`session_id` and `agent_id` are optional on all fifteen: omit them and they come
|
|
7
|
+
from the enclosing `failproofai_sdk.session()` / `failproofai_sdk.agent()` scope. Pass them and
|
|
8
|
+
your value wins. Omit `session_id` with nothing bound and you get a `TypeError`
|
|
9
|
+
naming the fix; `agent_id` falls back to `"main"` and never raises. See
|
|
10
|
+
`integration.md`.
|
|
11
|
+
|
|
12
|
+
Emit only what fits the agent. There is no requirement to use every type, and no
|
|
13
|
+
penalty for skipping one — except `agent_start`, without which the session does
|
|
14
|
+
not exist at all.
|
|
15
|
+
|
|
16
|
+
## The 15 events
|
|
17
|
+
|
|
18
|
+
Columns: **Required** is beyond `session_id` + `agent_id`, which every event
|
|
19
|
+
carries and which you rarely pass by hand.
|
|
20
|
+
*Optional fields are omitted from the record entirely when left unset* — they are
|
|
21
|
+
not written as `null`.
|
|
22
|
+
|
|
23
|
+
| Method | Required | Optional | Notes |
|
|
24
|
+
|---|---|---|---|
|
|
25
|
+
| `agent_start` | — | `goal`, `parent_id` | **Creates the session.** `parent_id` is the **`agent_id` of the parent agent** — not a session id, not a run id. Pass a session id here and you get no nesting, silently. |
|
|
26
|
+
| `agent_end` | — | `outcome`, `summary` | `outcome` must be `failed`/`error`/`timeout`/`rejected` to count as a failure. |
|
|
27
|
+
| `agent_pause` | `pause_id` | `reason`, `user_id` | Suspends the agent (waiting for a human, throttled, user-paused) **without ending it**. Starts the paused clock for this `pause_id`. |
|
|
28
|
+
| `agent_resume` | `pause_id` | `reason`, `user_id` | Emit **instead of a second `agent_start`** when a paused agent continues. `duration_ms` auto-computed — how long it was paused. |
|
|
29
|
+
| `tool_use` | `tool_name`, `tool_call_id` | `input` | Starts the duration clock for this `tool_call_id`. |
|
|
30
|
+
| `tool_result` | `tool_name`, `tool_call_id` | `output`, `error` | `duration_ms` auto-computed from the matching `tool_use`. |
|
|
31
|
+
| `model_request` | — | `model`, `messages`, `system`, `tools`, `request_id` | `request_id` is what pairs this with its response. |
|
|
32
|
+
| `model_response` | — | `model`, `stop_reason`, `input_tokens`, `output_tokens`, `content`, `role`, `request_id`, `error` | Token counts drive spend reporting. `error` marks a failed call — a 429 or a timeout — without a separate `error` event. |
|
|
33
|
+
| `error` | `error_type`, `message` | `traceback` | Always counts as an error, whatever else is set. |
|
|
34
|
+
| `hook_triggered` | `hook_name`, `hook_id` | `trigger_event`, `input` | Starts the clock for this `hook_id`. |
|
|
35
|
+
| `hook_completed` | `hook_name`, `hook_id` | `outcome`, `output`, `error` | `duration_ms` auto-computed. Same `outcome` rule as `agent_end`. |
|
|
36
|
+
| `human_wait` | `input_id` | `prompt`, `options`, `reason` | Starts the clock for this `input_id`. |
|
|
37
|
+
| `human_input` | `input_id` | `response` | `duration_ms` auto-computed — how long the human took. |
|
|
38
|
+
| `human_pause` | — | `reason`, `user_id` | |
|
|
39
|
+
| `human_interrupt` | — | `reason`, `user_id`, `at_step` | |
|
|
40
|
+
|
|
41
|
+
## Rules that apply to every event
|
|
42
|
+
|
|
43
|
+
**Payloads should be structured JSON where possible.** Serialization happens on
|
|
44
|
+
a background thread. Unsupported leaves such as `datetime`, `UUID`, `Decimal`,
|
|
45
|
+
`set`, `bytes`, or a Pydantic model are stringified automatically rather than
|
|
46
|
+
stopping the writer. If downstream analysis needs more than that string form,
|
|
47
|
+
serialize the value explicitly into a stable JSON object at the integration
|
|
48
|
+
boundary.
|
|
49
|
+
|
|
50
|
+
**Custom fields are free, and their *names* are unvalidated:**
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
failproofai_sdk.event.tool_use(
|
|
54
|
+
session_id=sid, agent_id="planner",
|
|
55
|
+
tool_name="web_search", tool_call_id="toolu_01",
|
|
56
|
+
input={"query": "..."},
|
|
57
|
+
tenant="acme", retry_count=2, # yours, kept verbatim
|
|
58
|
+
)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
A misspelled **optional** name is not an error — it is a new field. `inpt={...}`
|
|
62
|
+
is accepted, stored, and invisible; nothing will tell you. When something is
|
|
63
|
+
missing from a surface, suspect a typo before suspecting the platform.
|
|
64
|
+
|
|
65
|
+
A misspelled **required** name is a plain `TypeError` — `tool_name` and friends
|
|
66
|
+
are real parameters, so `tool_nmae="search"` fails loudly at the call site. Only
|
|
67
|
+
the optional names are silent.
|
|
68
|
+
|
|
69
|
+
**Five names are reserved and raise `ValueError`.** `timestamp`, `session_id`,
|
|
70
|
+
`agent_id`, `type`, `environment` — passing any as a custom field. (`session_id`
|
|
71
|
+
and `agent_id` are already named args, so Python raises `TypeError` first.)
|
|
72
|
+
|
|
73
|
+
**`duration_ms` is yours to pass on eleven of the fifteen.** It is computed for you
|
|
74
|
+
on `tool_result`, `hook_completed`, `human_input`, and `agent_resume`, and passing
|
|
75
|
+
it to *those four* raises `ValueError`. On the other eleven there is no guard:
|
|
76
|
+
`agent_end(..., duration_ms=5)` is accepted and stored as an ordinary custom field. Don't.
|
|
77
|
+
|
|
78
|
+
The one place you *should* pass it is **`model_response`**, where nothing computes
|
|
79
|
+
it for you. Time the call yourself and pass whole milliseconds as an **`int`** —
|
|
80
|
+
`round(seconds * 1000)`. A float raises `ValueError` at the call site, naming the
|
|
81
|
+
argument: the server reads this as an unsigned 32-bit integer and would store NULL
|
|
82
|
+
for anything else, so the SDK refuses it rather than letting the duration vanish.
|
|
83
|
+
The same guard covers `input_tokens` and `output_tokens`.
|
|
84
|
+
|
|
85
|
+
**Set `request_id` on both model events.** The same value on the `model_request`
|
|
86
|
+
and its `model_response` — a `uuid4().hex`, or the provider's own request id if it
|
|
87
|
+
gives you one, so your events line up with your provider logs. It links the pair
|
|
88
|
+
in the event detail view.
|
|
89
|
+
|
|
90
|
+
It does **not** yet drive the timeline rail or the model latency reports: those
|
|
91
|
+
still match concurrent LLM calls (a parallel fan-out, a sub-agent, a retry racing
|
|
92
|
+
its original) oldest-first, and will keep bracketing the wrong pairs. **Always
|
|
93
|
+
pass `duration_ms` on the `model_response` too** — that is what keeps the reported
|
|
94
|
+
duration right even when the bracketing is wrong.
|
|
95
|
+
|
|
96
|
+
**Correlation is a process-wide map keyed by your ids.** The SDK holds open
|
|
97
|
+
starts there until their matching end arrives. Consequences, in order of how much
|
|
98
|
+
they hurt:
|
|
99
|
+
|
|
100
|
+
- **Per-run counters are unsafe.** `call_1`, `call_2` — common in home-grown loops
|
|
101
|
+
— collide across overlapping runs. The failure is not the missing duration the
|
|
102
|
+
docs might lead you to expect; it is a *plausible wrong number attributed to the
|
|
103
|
+
wrong run*, which is worse. Reuse your framework's id (Anthropic and OpenAI
|
|
104
|
+
tool-call ids are globally unique), or a `uuid4`. `failproofai_sdk.tool_call()`
|
|
105
|
+
generates a `uuid4` for you.
|
|
106
|
+
- **`tool_call_id` and `hook_id` no longer collide with each other.** They live in
|
|
107
|
+
separate namespaces, so a `hook_completed(hook_id="x")` cannot pair with a
|
|
108
|
+
pending `tool_use(tool_call_id="x")`. The key is `<kind>:<session_id>:<id>`, so
|
|
109
|
+
each id only has to be unique *within one session, for one kind* — two sessions
|
|
110
|
+
reusing `call_1` measure independently. Reuse it twice in the SAME session and
|
|
111
|
+
the second `tool_use` overwrites the first pending entry, so the first
|
|
112
|
+
`tool_result` measures from the wrong start. (If you have read
|
|
113
|
+
older guidance saying one shared id space, that was true and is not any more —
|
|
114
|
+
the ids are namespaced by the SDK, so nothing on your side changes.)
|
|
115
|
+
- **`input_id` and `pause_id` are scoped per session/agent**, so
|
|
116
|
+
`human_wait`/`human_input` and `agent_pause`/`agent_resume` cannot collide
|
|
117
|
+
across runs at all.
|
|
118
|
+
- **The pair must happen in the same process.** A `tool_use` in one worker and a
|
|
119
|
+
`tool_result` in another produces two unpaired events and no duration. The same
|
|
120
|
+
goes for a human pause that resumes in a different process.
|
|
121
|
+
- **The map is capped at 10,000 and evicts oldest-first**, so a long-running
|
|
122
|
+
process that leaks orphaned starts can silently lose the duration on legitimate
|
|
123
|
+
later pairs.
|
|
124
|
+
|
|
125
|
+
**Timestamps are set by the SDK** at the moment you call the method — UTC,
|
|
126
|
+
microsecond precision, `Z`-suffixed (`2026-07-17T09:15:22.123456Z`). You cannot
|
|
127
|
+
override it (`timestamp` is reserved).
|
|
128
|
+
|
|
129
|
+
**There is no event id.** Events carry no unique identifier and no sequence
|
|
130
|
+
number. They are ordered by timestamp and correlated by your ids. This means
|
|
131
|
+
events are not deduplicable — if you emit the same event twice, that is two
|
|
132
|
+
events.
|
|
133
|
+
|
|
134
|
+
## What one line looks like
|
|
135
|
+
|
|
136
|
+
Each record is one line of JSON in an `event-*.jsonl` file. Key order is stable:
|
|
137
|
+
identity first, then the event's own required fields, then `environment`, then
|
|
138
|
+
whatever optional and custom fields you set.
|
|
139
|
+
|
|
140
|
+
```json
|
|
141
|
+
{"timestamp": "2026-07-17T09:15:22.123456Z", "session_id": "run-001", "agent_id": "planner", "type": "tool_use", "tool_name": "web_search", "tool_call_id": "toolu_01", "environment": "production", "input": {"query": "latest AI research"}}
|
|
142
|
+
{"timestamp": "2026-07-17T09:15:23.456789Z", "session_id": "run-001", "agent_id": "planner", "type": "tool_result", "tool_name": "web_search", "tool_call_id": "toolu_01", "environment": "production", "output": {"results": ["..."]}, "duration_ms": 1334}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**Parse it; don't grep it.** The whitespace above is what today's writer happens
|
|
146
|
+
to emit — it is not a contract. `grep '"type":"agent_start"'` finds nothing on a
|
|
147
|
+
perfectly healthy integration, and reads as "my events are missing". Use
|
|
148
|
+
`python -m json.tool --json-lines`, or `jq`.
|
|
149
|
+
|
|
150
|
+
`environment` is always present. It is `"dev"` unless you set it — see
|
|
151
|
+
`../SKILL.md` §3.
|
|
152
|
+
|
|
153
|
+
## A minimal complete run
|
|
154
|
+
|
|
155
|
+
The shape to aim for. `agent_start` and `agent_end` bracket everything; the pairs
|
|
156
|
+
nest inside.
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
import failproofai_sdk
|
|
160
|
+
|
|
161
|
+
failproofai_sdk.configure(environment="production")
|
|
162
|
+
|
|
163
|
+
sid = "run-001"
|
|
164
|
+
failproofai_sdk.event.agent_start(session_id=sid, agent_id="planner", goal="answer the user's question")
|
|
165
|
+
try:
|
|
166
|
+
failproofai_sdk.event.model_request(session_id=sid, agent_id="planner", model="claude-opus-4-8",
|
|
167
|
+
request_id="req-1",
|
|
168
|
+
messages=[{"role": "user", "content": "..."}])
|
|
169
|
+
failproofai_sdk.event.model_response(session_id=sid, agent_id="planner", model="claude-opus-4-8",
|
|
170
|
+
request_id="req-1", duration_ms=812,
|
|
171
|
+
stop_reason="tool_use", input_tokens=1200, output_tokens=95)
|
|
172
|
+
|
|
173
|
+
failproofai_sdk.event.tool_use(session_id=sid, agent_id="planner",
|
|
174
|
+
tool_name="web_search", tool_call_id="toolu_01",
|
|
175
|
+
input={"query": "..."})
|
|
176
|
+
failproofai_sdk.event.tool_result(session_id=sid, agent_id="planner",
|
|
177
|
+
tool_name="web_search", tool_call_id="toolu_01",
|
|
178
|
+
output={"results": ["..."]})
|
|
179
|
+
# BaseException, not Exception: `asyncio.CancelledError` inherits from
|
|
180
|
+
# BaseException, so `except Exception` lets a cancelled run through and the
|
|
181
|
+
# session ends with an `agent_start` and no `agent_end` at all.
|
|
182
|
+
except BaseException as e:
|
|
183
|
+
import traceback
|
|
184
|
+
failproofai_sdk.event.error(session_id=sid, agent_id="planner",
|
|
185
|
+
error_type=type(e).__name__, message=str(e),
|
|
186
|
+
traceback=traceback.format_exc())
|
|
187
|
+
failproofai_sdk.event.agent_end(session_id=sid, agent_id="planner", outcome="failed")
|
|
188
|
+
raise
|
|
189
|
+
else:
|
|
190
|
+
failproofai_sdk.event.agent_end(session_id=sid, agent_id="planner",
|
|
191
|
+
outcome="success", summary="answered from 1 search")
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Note `outcome="failed"` in the `except` — not `"failure"`, which silently reads as
|
|
195
|
+
a non-failure.
|
|
196
|
+
|
|
197
|
+
Threading `sid` through by hand like this is fine for one function and miserable
|
|
198
|
+
across a real codebase — which is why you do not have to. The same run, with the
|
|
199
|
+
scopes doing the identity and the bracketing:
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
with failproofai_sdk.agent("planner", session_id="run-001", goal="answer the user's question"):
|
|
203
|
+
failproofai_sdk.event.model_request(model="claude-opus-4-8", request_id="req-1", messages=[...])
|
|
204
|
+
failproofai_sdk.event.model_response(model="claude-opus-4-8", request_id="req-1", duration_ms=812,
|
|
205
|
+
stop_reason="tool_use", input_tokens=1200, output_tokens=95)
|
|
206
|
+
with failproofai_sdk.tool_call("web_search", input={"query": "..."}) as t:
|
|
207
|
+
t.output = {"results": ["..."]}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
`agent_start`/`agent_end`, the `error` event, `outcome="failed"` and the tool
|
|
211
|
+
timing all come for free, including on the exception path. See `integration.md`;
|
|
212
|
+
on a supported framework, `frameworks.md` gets you the same events with no call
|
|
213
|
+
sites at all.
|
|
214
|
+
|
|
215
|
+
## Pausing and resuming — not ending
|
|
216
|
+
|
|
217
|
+
When a run suspends — waiting for a human, rate-limited, user-paused — do **not**
|
|
218
|
+
emit `agent_end` and then a fresh `agent_start` on the way back: that reads as two
|
|
219
|
+
separate agents, and the wait counts as active work. Bracket the gap with
|
|
220
|
+
`agent_pause` / `agent_resume` instead, reusing one `pause_id`:
|
|
221
|
+
|
|
222
|
+
```python
|
|
223
|
+
import uuid
|
|
224
|
+
pause_id = str(uuid.uuid4())
|
|
225
|
+
failproofai_sdk.event.agent_pause(session_id=sid, agent_id="planner",
|
|
226
|
+
pause_id=pause_id, reason="waiting_for_user")
|
|
227
|
+
# … the run is parked; a human is deciding …
|
|
228
|
+
failproofai_sdk.event.agent_resume(session_id=sid, agent_id="planner", pause_id=pause_id)
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
The agent span stays open across the pause (it is not ended); `agent_resume`
|
|
232
|
+
carries the paused `duration_ms` when both halves run in the same process, and
|
|
233
|
+
paused time is reported separately from active work. Persist `pause_id` if the
|
|
234
|
+
resume happens in a different process so it reuses the same value.
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
# Framework integrations
|
|
2
|
+
|
|
3
|
+
If the agent runs on LangChain/LangGraph, CrewAI, LlamaIndex or Pydantic AI, you
|
|
4
|
+
do not write the instrumentation — you turn it on. The adapters ship inside the
|
|
5
|
+
SDK wheel and are imported only when you ask for them.
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
import failproofai_sdk
|
|
9
|
+
from langgraph.graph import StateGraph # import your framework FIRST
|
|
10
|
+
|
|
11
|
+
failproofai_sdk.configure(environment="production")
|
|
12
|
+
failproofai_sdk.instrument() # every supported framework already imported
|
|
13
|
+
|
|
14
|
+
graph.invoke({"messages": [...]}) # sessions, tools, models, errors all appear
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
No call site changes. `graph.invoke()`, `crew.kickoff()`, `await workflow.run()`
|
|
18
|
+
and `await agent.run()` are recorded exactly as they are written today.
|
|
19
|
+
|
|
20
|
+
## `instrument()` / `uninstrument()`
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
failproofai_sdk.instrument() # auto-detect
|
|
24
|
+
failproofai_sdk.instrument("crewai") # exactly one
|
|
25
|
+
failproofai_sdk.instrument("langchain", session_id=request_id, capture_content=False)
|
|
26
|
+
failproofai_sdk.uninstrument() # put everything back
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- **Auto-detect reads what is already imported, not what is installed.** This is
|
|
30
|
+
deliberate — a library that imports LangChain to find out whether you use it
|
|
31
|
+
costs you a second of startup for nothing. The consequence is an ordering rule:
|
|
32
|
+
`configure()` → import the framework → `instrument()` → run. Calling
|
|
33
|
+
`instrument()` too early instruments nothing and returns `()` — no exception,
|
|
34
|
+
but it does log a warning, so check stderr when a run records nothing.
|
|
35
|
+
- **It returns the names it newly instrumented**, as a tuple. Assert on it in
|
|
36
|
+
startup code if you want a loud failure: `assert failproofai_sdk.instrument()`.
|
|
37
|
+
- **Instrumenting something already active is a no-op** returning `()`. Calling
|
|
38
|
+
it from two code paths, or from a reloading dev server, cannot double-record.
|
|
39
|
+
- **An unknown name raises `ValueError` listing the valid ones.** A typo that
|
|
40
|
+
silently records nothing is the worst available outcome, so this one is loud.
|
|
41
|
+
Accepted spellings: `langchain` (aliases `langgraph`, `langchain_core`),
|
|
42
|
+
`crewai`, `llama_index` (`llamaindex`, `llama-index`), `pydantic_ai`
|
|
43
|
+
(`pydantic-ai`, `pydanticai`).
|
|
44
|
+
- **One adapter failing does not cost you the others.** With no argument, an
|
|
45
|
+
adapter whose install fails is logged and skipped and the rest still install.
|
|
46
|
+
- **Ask what is wired up** rather than guessing, when a run records nothing:
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from failproofai_sdk.integrations import available, active
|
|
50
|
+
|
|
51
|
+
available() # ('crewai', 'langchain', 'llama_index', 'pydantic_ai') — every adapter that ships
|
|
52
|
+
active() # ('langchain',) — what is instrumented in THIS process right now
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
An empty `active()` after you called `instrument()` is the ordering bug above:
|
|
56
|
+
the framework was not in `sys.modules` yet.
|
|
57
|
+
- **`uninstrument()` never raises**, restores the original objects it replaced,
|
|
58
|
+
and closes anything still open with `outcome="cancelled"` so teardown does not
|
|
59
|
+
leave a session reported as ongoing forever.
|
|
60
|
+
|
|
61
|
+
Options are keyword arguments to `instrument()`. The same dict reaches every
|
|
62
|
+
adapter, so an option meant for one is ignored by the others rather than raising:
|
|
63
|
+
|
|
64
|
+
| Option | Applies to | Effect |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
| `session_id=` | langchain, crewai, pydantic_ai | Pin every run to this session id. Use it when your service already has a per-request id. |
|
|
67
|
+
| `capture_content=False` | langchain, pydantic_ai | Drop prompts, messages and outputs; keep structure, durations and token counts. |
|
|
68
|
+
| `capture_messages=False` | llama_index | The same, for LlamaIndex. |
|
|
69
|
+
| `include_chains=("rag",)` | langchain | Record these intermediate chains by name. Default: none — see below. |
|
|
70
|
+
| `graph_callbacks=False` | langchain | Turn off LangGraph interrupt/resume wiring. Default on. |
|
|
71
|
+
| `steps=False` | llama_index | Stop emitting a hook pair per workflow step. Default on. |
|
|
72
|
+
| `embeddings=True` | llama_index | Record embedding calls. Default off — they are high volume and low signal. |
|
|
73
|
+
| `stale_after=600.0` | llama_index | Seconds before the background reaper closes a span the workflow never finished. |
|
|
74
|
+
| `reaper_interval=30.0` | llama_index | How often that reaper runs. |
|
|
75
|
+
|
|
76
|
+
## The rule the mappings follow
|
|
77
|
+
|
|
78
|
+
> A framework construct becomes an Failproof AI **agent** if and only if it owns an
|
|
79
|
+
> LLM decision loop and has its own goal. Everything else with a start and an end
|
|
80
|
+
> becomes the closest kind of leaf.
|
|
81
|
+
|
|
82
|
+
| Kind | Gets | Examples |
|
|
83
|
+
|---|---|---|
|
|
84
|
+
| owns a decision loop | `agent_start` / `agent_end` | the top-level graph, crew or workflow, and anything the framework itself calls an agent — a compiled subgraph, a CrewAI `Agent` role, a LlamaIndex `FunctionAgent` |
|
|
85
|
+
| something the agent *calls* | `tool_use` / `tool_result` | function tools, retrievers, memory and knowledge queries |
|
|
86
|
+
| machinery *around* the agent | `hook_triggered` / `hook_completed` (with `trigger_event`) | LangGraph nodes, LlamaIndex workflow steps, CrewAI flow methods, guardrails |
|
|
87
|
+
|
|
88
|
+
**A LangGraph node is a hook, not a nested agent**, and that is the one mapping
|
|
89
|
+
decision worth understanding, because it is the one you might be tempted to
|
|
90
|
+
"fix". `agent_id` is the primary facet across every session; it has to stay a
|
|
91
|
+
small, stable set of labels. Promote `retrieve`, `grade_documents` and
|
|
92
|
+
`should_continue` to agents and you drown the real agents in the filter, and the
|
|
93
|
+
session ends up labelled with whichever node happened to run first. Hook spans
|
|
94
|
+
draw identically on the timeline — same lanes, same durations — and you get a
|
|
95
|
+
per-node latency surface for free, with `hook_name` as its own facet.
|
|
96
|
+
|
|
97
|
+
## LangChain / LangGraph
|
|
98
|
+
|
|
99
|
+
Supported: `langchain-core >=1.4.7,<2`, `langgraph >=1.2,<2`.
|
|
100
|
+
|
|
101
|
+
Attaches through LangChain's own callback configuration, so **every** callback
|
|
102
|
+
manager the framework builds carries it — including ones created inside chains
|
|
103
|
+
you never touch.
|
|
104
|
+
|
|
105
|
+
| LangChain / LangGraph | Failproof AI |
|
|
106
|
+
|---|---|
|
|
107
|
+
| root run (the outermost chain/graph) | `agent_start` / `agent_end` |
|
|
108
|
+
| LangGraph node | `hook_triggered` / `hook_completed`, `trigger_event="graph_node"` |
|
|
109
|
+
| compiled subgraph | nested `agent_start` / `agent_end`, `agent_id="root/node"` |
|
|
110
|
+
| tool run | `tool_use` / `tool_result` |
|
|
111
|
+
| retriever run | `tool_use` / `tool_result`, output summarised |
|
|
112
|
+
| chat model / LLM run | `model_request` / `model_response`, paired on `request_id` |
|
|
113
|
+
| `interrupt()` | `human_wait` + `agent_pause` |
|
|
114
|
+
| `Command(resume=...)` | `agent_resume` + `human_input` |
|
|
115
|
+
| intermediate chains | **nothing**, unless you name them in `include_chains` |
|
|
116
|
+
|
|
117
|
+
**Python 3.10 async nodes must forward `RunnableConfig`.** LangGraph cannot
|
|
118
|
+
automatically propagate callback context from an async node into a child
|
|
119
|
+
`ainvoke()` on Python 3.10. Without this, the child model or tool appears as a
|
|
120
|
+
separate root run:
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
from langchain_core.runnables import RunnableConfig
|
|
124
|
+
|
|
125
|
+
async def plan(state, config: RunnableConfig):
|
|
126
|
+
reply = await model.ainvoke(state["messages"], config=config)
|
|
127
|
+
return {"messages": [reply]}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Python 3.11 and later propagate this context automatically.
|
|
131
|
+
|
|
132
|
+
`session_id` resolution, in order — the first that produces a value wins:
|
|
133
|
+
|
|
134
|
+
1. `instrument("langchain", session_id=...)`;
|
|
135
|
+
2. `config={"metadata": {"failproofai_sdk_session_id": sid}}` on the call — the
|
|
136
|
+
documented per-call key, and the one to use in a web service;
|
|
137
|
+
3. an enclosing `failproofai_sdk.session()` / `failproofai_sdk.agent()` scope;
|
|
138
|
+
4. `metadata["session_id" | "conversation_id" | "thread_id"]`;
|
|
139
|
+
5. the root run id.
|
|
140
|
+
|
|
141
|
+
It is never synthesised from scratch. A made-up id would split one run into many
|
|
142
|
+
sessions, which is a silent wrong answer rather than a loud one.
|
|
143
|
+
|
|
144
|
+
Three behaviours that surprise people:
|
|
145
|
+
|
|
146
|
+
- **A `GraphInterrupt` is control flow, not an error.** LangGraph raises it
|
|
147
|
+
through the same error callback as a genuine failure, so a naive integration
|
|
148
|
+
paints every human approval red and ends the run as `failed`. The adapter
|
|
149
|
+
treats the whole interrupt family as control flow and emits the HITL pairs
|
|
150
|
+
instead.
|
|
151
|
+
- **Streaming never produces per-token events.** Time-to-first-token and the
|
|
152
|
+
chunk count are folded into the closing `model_response` as `fw_ttft_ms` and
|
|
153
|
+
`fw_chunks`.
|
|
154
|
+
- **`agent_id` is the graph or chain name**, never a run UUID. Framework ids land
|
|
155
|
+
in `fw_run_id` / `fw_node` / `fw_thread_id`.
|
|
156
|
+
|
|
157
|
+
## CrewAI
|
|
158
|
+
|
|
159
|
+
Supported: `crewai >=1.13,<2` (the release where the span tree and normalised
|
|
160
|
+
token usage are both present). Registers a listener on CrewAI's event bus;
|
|
161
|
+
`crew.kickoff()` is unchanged.
|
|
162
|
+
|
|
163
|
+
| CrewAI | Failproof AI |
|
|
164
|
+
|---|---|
|
|
165
|
+
| crew kickoff | `agent_start` / `agent_end`, `agent_id` = crew name |
|
|
166
|
+
| agent execution | nested `agent_start` / `agent_end`, `agent_id` = the agent's **role** |
|
|
167
|
+
| task | no event of its own — folded into the agent execution that runs it |
|
|
168
|
+
| flow method | `hook_triggered` / `hook_completed`, `trigger_event="flow_method"` |
|
|
169
|
+
| guardrail | hook pair; a tripped guardrail closes with `outcome="rejected"` |
|
|
170
|
+
| tool usage | `tool_use` / `tool_result` |
|
|
171
|
+
| memory / knowledge query, save, retrieval | `tool_use` / `tool_result` (`memory.query`, `knowledge.search`, …) |
|
|
172
|
+
| LLM call | `model_request` / `model_response` |
|
|
173
|
+
| LLM stream chunks | folded into the closing `model_response` |
|
|
174
|
+
|
|
175
|
+
`agent_id` is the crew name at the top and the **agent role** underneath —
|
|
176
|
+
`"researcher"`, `"editor"`. CrewAI's `agent.id` is a UUID and goes to
|
|
177
|
+
`fw_agent_id`, never to `agent_id`. CrewAI runs its own internal flow inside
|
|
178
|
+
every agent execution; that one is a pass-through and does not become a span.
|
|
179
|
+
|
|
180
|
+
## LlamaIndex
|
|
181
|
+
|
|
182
|
+
Supported: `llama-index-core >=0.14.23,<0.15`. Registers on the root dispatcher,
|
|
183
|
+
so one call covers every workflow and agent in the process.
|
|
184
|
+
|
|
185
|
+
| LlamaIndex | Failproof AI |
|
|
186
|
+
|---|---|
|
|
187
|
+
| `Workflow.run` root span | session + `agent_start` / `agent_end` |
|
|
188
|
+
| nested `Workflow.run` span | nested `agent_start` / `agent_end` |
|
|
189
|
+
| workflow step | `hook_triggered` / `hook_completed`, `trigger_event="workflow_step"` |
|
|
190
|
+
| LLM chat start/end | `model_request` / `model_response`, paired on `request_id` |
|
|
191
|
+
| `FunctionTool.call` | `tool_use` / `tool_result` |
|
|
192
|
+
| retrieval start/end | `tool_use` / `tool_result`, output summarised |
|
|
193
|
+
| a tool that waits for an event | `human_wait` + `agent_pause`, then `agent_resume` + `human_input` |
|
|
194
|
+
| embeddings | nothing, unless `embeddings=True` |
|
|
195
|
+
|
|
196
|
+
`agent_id` is the `FunctionAgent.name` when there is one and the workflow class
|
|
197
|
+
name otherwise — never a span id.
|
|
198
|
+
|
|
199
|
+
**Token counts are best-effort here, and deliberately so.** LlamaIndex has no
|
|
200
|
+
standard usage field, so the raw usage dict always ships as `usage`, and the
|
|
201
|
+
top-level `input_tokens` / `output_tokens` are set **only** when a recognised key
|
|
202
|
+
is present. A model integration that names its counters something new gives you a
|
|
203
|
+
populated `usage` and blank token columns. That is the honest outcome; a
|
|
204
|
+
confident wrong number would be worse.
|
|
205
|
+
|
|
206
|
+
**Known gap:** human-in-the-loop is captured only when the wait happens inside a
|
|
207
|
+
tool — the pattern LlamaIndex documents. A plain workflow step that waits for an
|
|
208
|
+
event is resolved by the runtime before anything observable happens, so there is
|
|
209
|
+
no signal to key a pause on.
|
|
210
|
+
|
|
211
|
+
## Pydantic AI
|
|
212
|
+
|
|
213
|
+
Supported: `pydantic-ai-slim >=2.0,<3`. Every tutorial written for v1 is wrong
|
|
214
|
+
for this range: `Agent(instrument=...)` was removed in 2.0. The adapter installs
|
|
215
|
+
itself as a capability instead — no OpenTelemetry SDK required, and it cannot
|
|
216
|
+
double-count against your own tracing.
|
|
217
|
+
|
|
218
|
+
| Pydantic AI | Failproof AI |
|
|
219
|
+
|---|---|
|
|
220
|
+
| an agent run | `agent_start` / `agent_end` (plus `error` on failure) |
|
|
221
|
+
| a model request | `model_request` / `model_response` |
|
|
222
|
+
| a tool execution | `tool_use` / `tool_result` |
|
|
223
|
+
| graph nodes (`UserPromptNode`, `ModelRequestNode`, `CallToolsNode`) | **nothing** |
|
|
224
|
+
|
|
225
|
+
Graph nodes are Pydantic AI's own loop machinery rather than steps you wrote —
|
|
226
|
+
unlike a LangGraph node — and everything they do that is worth seeing is already
|
|
227
|
+
covered by the model and tool spans.
|
|
228
|
+
|
|
229
|
+
`session_id` is the run's `conversation_id`, so a conversation spanning several
|
|
230
|
+
runs is one session; an enclosing `failproofai_sdk.session()` / `failproofai_sdk.agent()` scope
|
|
231
|
+
always wins. `agent_id` is the `Agent`'s name.
|
|
232
|
+
|
|
233
|
+
**One ordering rule, because it bites:** the capability is attached when an
|
|
234
|
+
`Agent` is constructed, so **agents built before `instrument()` are not
|
|
235
|
+
instrumented**, and agents built while instrumented keep the capability object
|
|
236
|
+
after `uninstrument()` (it turns into a pass-through and stops recording).
|
|
237
|
+
Construct your agents after `instrument()`, or attach it yourself:
|
|
238
|
+
|
|
239
|
+
```python
|
|
240
|
+
from failproofai_sdk.integrations.pydantic_ai import FailproofAI
|
|
241
|
+
|
|
242
|
+
agent = Agent("openai:gpt-5", capabilities=[FailproofAI()])
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Mixing adapters with hand-written events
|
|
246
|
+
|
|
247
|
+
They compose, and this is the supported way to add detail an adapter cannot know
|
|
248
|
+
about:
|
|
249
|
+
|
|
250
|
+
```python
|
|
251
|
+
failproofai_sdk.instrument("langchain")
|
|
252
|
+
|
|
253
|
+
with failproofai_sdk.agent("planner", goal=question): # your bracket
|
|
254
|
+
graph.invoke(...) # adapter events land here
|
|
255
|
+
with failproofai_sdk.tool_call("billing_check") as t: # your own tool span
|
|
256
|
+
t.output = check(user)
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Adapter events join **that** session, with `parent_id="planner"`. An adapter
|
|
260
|
+
resolves identity from its own run id first, then that run's parent chain, then
|
|
261
|
+
whatever scope you have open — so a hand-written outer bracket and an adapter
|
|
262
|
+
produce one tree, not two.
|
|
263
|
+
|
|
264
|
+
## What every adapter guarantees
|
|
265
|
+
|
|
266
|
+
- **They never raise into your agent.** Every callback is wrapped: a failure logs
|
|
267
|
+
at WARNING with a traceback, and after three failures at the same call site
|
|
268
|
+
that site disables itself at ERROR. A broken adapter costs you a log line, not
|
|
269
|
+
your agent. Set `FAILPROOFAI_SDK_STRICT=1` to make it re-raise instead — do that in
|
|
270
|
+
tests and when debugging an adapter that records nothing.
|
|
271
|
+
- **Version ranges are checked at `instrument()` time.** Outside the supported
|
|
272
|
+
range: warn once, keep going. Named explicitly but not importable at all:
|
|
273
|
+
`ImportError` carrying the install command. `FAILPROOFAI_SDK_STRICT_INTEGRATIONS=1`
|
|
274
|
+
promotes every one of those warnings to an exception.
|
|
275
|
+
- **Framework-native ids are namespaced `fw_*`** — `fw_run_id`, `fw_node`,
|
|
276
|
+
`fw_task_id`, `fw_agent_id`, `fw_thread_id`. Flat, never nested. This is a
|
|
277
|
+
safety rule, not a style one: custom fields are merged last, so an un-namespaced
|
|
278
|
+
extra called `tool_name` or `duration_ms` would overwrite the real field.
|
|
279
|
+
- **Large payloads are truncated**, per field and per event, with a
|
|
280
|
+
`…[truncated]` marker. Prompts, retrieved documents and tool outputs are the
|
|
281
|
+
three largest strings in an agent process.
|
|
282
|
+
- **Every event carries `framework`, `framework_version` and
|
|
283
|
+
`integration_version`**, so you can tell adapter output from your own.
|
|
284
|
+
- **No per-token events, ever.** Streaming is folded into the closing
|
|
285
|
+
`model_response`.
|
|
286
|
+
- **Timestamps are stamped when the callback fires.** Nothing is backdated, so an
|
|
287
|
+
adapter cannot import a trace that already happened.
|
|
288
|
+
|
|
289
|
+
## Verifying an adapter
|
|
290
|
+
|
|
291
|
+
Everything in `../SKILL.md` §5 applies unchanged — the events go to the same
|
|
292
|
+
files. Four checks that are specific to adapter output:
|
|
293
|
+
|
|
294
|
+
1. **The first event of each session is the root `agent_start`.** Anything
|
|
295
|
+
emitted before it can leave the session labelled by the wrong actor.
|
|
296
|
+
2. **`agent_id` values are names, not UUIDs** — `"planner"`, `"researcher"`,
|
|
297
|
+
the graph name. A UUID here means something is being passed through that
|
|
298
|
+
should have gone to `fw_agent_id`.
|
|
299
|
+
3. **`model_request` and `model_response` share a `request_id`**, and every
|
|
300
|
+
`model_response` carries an integer `duration_ms`.
|
|
301
|
+
4. **Nothing is left open.** Every `tool_use` has a `tool_result`, every
|
|
302
|
+
`agent_start` an `agent_end`.
|
|
303
|
+
|
|
304
|
+
If an adapter records nothing at all, in this order: was the framework imported
|
|
305
|
+
**before** `instrument()` (auto-detect reads imported modules); did
|
|
306
|
+
`instrument()` return a non-empty tuple; and does the run produce anything with
|
|
307
|
+
`FAILPROOFAI_SDK_STRICT=1` set, which converts a swallowed adapter error into a raise.
|
|
308
|
+
|
|
309
|
+
## A framework that is not on this list
|
|
310
|
+
|
|
311
|
+
Use the shipped context managers at the framework's own boundaries —
|
|
312
|
+
`failproofai_sdk.agent()` around the run, `failproofai_sdk.tool_call()` in the tool hook. See
|
|
313
|
+
`integration.md`. Ask before writing a full callback adapter for an unsupported
|
|
314
|
+
framework: adding one to the SDK is usually the better answer.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Installing the SDK
|
|
2
|
+
|
|
3
|
+
```bash
|
|
4
|
+
pip install failproofai-sdk # or: uv add failproofai-sdk
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
The SDK has no dependencies, so that is all it installs. Optional extras pull in
|
|
8
|
+
the **framework**, never the adapter — all four adapters ship in the box:
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pip install 'failproofai-sdk[langchain]' # also: langgraph, crewai, pydantic-ai
|
|
12
|
+
pip install 'failproofai-sdk[llamaindex]' # note: no hyphen, unlike the dist name
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Most agents already have their framework installed and never need one of these.
|
|
16
|
+
|
|
17
|
+
Then `import failproofai_sdk`. There is no token, no private index, and no wheel to
|
|
18
|
+
download by hand — the distribution is on public PyPI. It has no dependencies, so
|
|
19
|
+
it cannot conflict with anything already in the agent's environment.
|
|
20
|
+
|
|
21
|
+
## The one thing that still goes wrong
|
|
22
|
+
|
|
23
|
+
**`pip install agenteye` does not install this SDK, and can uninstall it.**
|
|
24
|
+
|
|
25
|
+
`agenteye` was the SDK's distribution name inside the private monorepo, and it is
|
|
26
|
+
also the name an old CLI published under. That CLI has moved to `fp-cloud-cli` (command
|
|
27
|
+
`fp`), but its last release as `agenteye` — version `0.1.22` — is stranded on
|
|
28
|
+
public PyPI permanently. PyPI versions cannot be withdrawn and reused, and pip
|
|
29
|
+
resolves the highest version, so that build is what the name still resolves to.
|
|
30
|
+
|
|
31
|
+
| You run | You get | Symptom |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| `pip install agenteye`, nothing installed | the stranded CLI build | `import failproofai_sdk` → `ModuleNotFoundError`; that build ships `agenteye_cli` |
|
|
34
|
+
| `pip install agenteye`, SDK already present | the stranded CLI build **alongside** it | Confusing but survivable — different distribution names, so the SDK is not removed |
|
|
35
|
+
| `pip install agenteye` on a pre-rename SDK (`agenteye` ≤ `0.0.1b14`) | the stranded CLI build, **replacing the SDK** | The import that worked five minutes ago stops working: same distribution name, higher version, so pip treats it as an upgrade |
|
|
36
|
+
|
|
37
|
+
The last row is the dangerous one and it is why the rename happened. It fires
|
|
38
|
+
*after* a working integration, when someone wants the CLI to check that events
|
|
39
|
+
arrived and installs it into the agent's own environment. Nothing warns them.
|
|
40
|
+
|
|
41
|
+
If you want the CLI, it is a separate distribution and installing it cannot touch
|
|
42
|
+
`failproofai-sdk` — but give it its own environment anyway:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pipx install fp-cloud-cli # or: uv tool install fp-cloud-cli (the command is `fp`)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Migrating from the old `agenteye` distribution
|
|
49
|
+
|
|
50
|
+
Two changes, both mechanical:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip uninstall agenteye
|
|
54
|
+
pip install failproofai-sdk
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
```diff
|
|
58
|
+
-import agenteye
|
|
59
|
+
-agenteye.configure(base_dir=None, flush_interval=0.5)
|
|
60
|
+
-agenteye.event.agent_start(session_id="run-001", agent_id="planner")
|
|
61
|
+
+import failproofai_sdk
|
|
62
|
+
+failproofai_sdk.configure(base_dir=None, flush_interval=0.5)
|
|
63
|
+
+failproofai_sdk.event.agent_start(session_id="run-001", agent_id="planner")
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Every method name, argument, and emitted field is unchanged, and so is
|
|
67
|
+
`AGENTEYE_ENVIRONMENT` — a contract with a daemon that releases separately.
|
|
68
|
+
|
|
69
|
+
**Two things changed on disk.** The default spool root is now
|
|
70
|
+
`~/.failproofai/custom-agents`, not `~/.agenteye`; and **`AGENTEYE_HOME` no
|
|
71
|
+
longer moves the SDK's spool at all.** It used to sit above the default, so
|
|
72
|
+
exporting it for `agenteye-collector` — the component that genuinely reads it —
|
|
73
|
+
relocated this SDK as an unasked-for side effect. Resolution is now exactly
|
|
74
|
+
`configure(base_dir=...)`, else `~/.failproofai/custom-agents` (with
|
|
75
|
+
`$FAILPROOFAI_HOME` moving the umbrella, never the spool out of it).
|
|
76
|
+
|
|
77
|
+
`failproofaid` watches both roots, so if that is your daemon there is nothing to
|
|
78
|
+
do and already-spooled batches still get collected. If you run the older
|
|
79
|
+
`agenteye-collector`, point **it** at the SDK with
|
|
80
|
+
`AGENTEYE_HOME=~/.failproofai/custom-agents`, or pass `base_dir` explicitly.
|
|
81
|
+
(`AGENTEYE_SPOOL_TO_FAILPROOFAI` is retired: it also required the directory to
|
|
82
|
+
pre-exist, which nothing created, so it never took effect.)
|
|
83
|
+
|
|
84
|
+
## Confirm what you have
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
python -c "import failproofai_sdk; print(failproofai_sdk.__version__)"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
- A version string such as `0.0.1b1` → the SDK. Good.
|
|
91
|
+
- `ModuleNotFoundError: No module named 'failproofai_sdk'` → not installed. If
|
|
92
|
+
`pip show agenteye` returns something, you installed the wrong name; see above.
|
|
93
|
+
|
|
94
|
+
## Pinning
|
|
95
|
+
|
|
96
|
+
Pin `failproofai-sdk` in your dependency file like any other package. Never leave
|
|
97
|
+
an unpinned `agenteye` requirement anywhere a CI job will resolve it from PyPI —
|
|
98
|
+
it will pull the stranded CLI build on the next clean install. If you are
|
|
99
|
+
migrating, grep for `agenteye` in every `requirements*.txt`, `pyproject.toml`,
|
|
100
|
+
`Pipfile` and Dockerfile, not just the one you remember.
|