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,481 @@
|
|
|
1
|
+
# LangChain / LangGraph
|
|
2
|
+
|
|
3
|
+
One adapter serves both — LangGraph runs on `langchain-core`'s callback manager,
|
|
4
|
+
so instrumenting one instruments the other.
|
|
5
|
+
|
|
6
|
+
- [Install](#install)
|
|
7
|
+
- [The integration](#the-integration)
|
|
8
|
+
- [How it attaches](#how-it-attaches)
|
|
9
|
+
- [What gets recorded](#what-gets-recorded)
|
|
10
|
+
- [A complete example](#a-complete-example)
|
|
11
|
+
- [Naming your agents](#naming-your-agents)
|
|
12
|
+
- [Controlling the session](#controlling-the-session)
|
|
13
|
+
- [Options](#options)
|
|
14
|
+
- [What an event actually looks like](#what-an-event-actually-looks-like)
|
|
15
|
+
- [Human in the loop](#human-in-the-loop)
|
|
16
|
+
- [Pitfalls](#pitfalls)
|
|
17
|
+
- [Runnable examples](#runnable-examples)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Install
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pip install 'failproofai-sdk[langgraph]' # pins langgraph >=1.2,<2
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Using plain LangChain without LangGraph:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install 'failproofai-sdk[langchain]' # pins langchain-core >=1.4.7,<2
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
You almost certainly have the framework already. The extras exist to state the
|
|
34
|
+
supported range; the adapter itself ships in the base wheel.
|
|
35
|
+
|
|
36
|
+
**Supported:** `langchain-core` 1.4.7 → 2.0, `langgraph` 1.2 → 2.0. Outside
|
|
37
|
+
that range the adapter still installs and warns once, because a version we have
|
|
38
|
+
not tested is a better bet than no telemetry.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## The integration
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
import failproofai_sdk
|
|
46
|
+
|
|
47
|
+
failproofai_sdk.configure(environment="production")
|
|
48
|
+
failproofai_sdk.instrument()
|
|
49
|
+
|
|
50
|
+
with failproofai_sdk.session():
|
|
51
|
+
graph.invoke({"messages": [HumanMessage("...")]})
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Three lines, and nothing else in your codebase changes. No decorators on your
|
|
55
|
+
nodes, no callback passed to `.invoke()`, no ids threaded through your
|
|
56
|
+
functions.
|
|
57
|
+
|
|
58
|
+
`instrument()` with no argument auto-detects every supported framework already
|
|
59
|
+
imported. To be explicit:
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
failproofai_sdk.instrument("langchain") # "langgraph" is an alias
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## How it attaches
|
|
68
|
+
|
|
69
|
+
`instrument()` registers a tracer through
|
|
70
|
+
`langchain_core.tracers.context.register_configure_hook`. LangChain injects it
|
|
71
|
+
into **every callback manager it builds**, which means:
|
|
72
|
+
|
|
73
|
+
- every graph, node, tool, retriever and model call is captured;
|
|
74
|
+
- so is anything inside a library you did not write, as long as it goes through
|
|
75
|
+
LangChain;
|
|
76
|
+
- there is nothing to pass to `.invoke()` and no call site to change.
|
|
77
|
+
|
|
78
|
+
The tracer subclasses `BaseTracer`, so LangChain assembles the run tree and
|
|
79
|
+
hands over `Run` objects with inputs, outputs, metadata and timings already
|
|
80
|
+
collected — two override points instead of twenty hand-correlated callbacks.
|
|
81
|
+
|
|
82
|
+
<details>
|
|
83
|
+
<summary><b>Why we do not patch <code>BaseCallbackManager.__init__</code></b></summary>
|
|
84
|
+
|
|
85
|
+
Some other integrations do, and it double-records.
|
|
86
|
+
`BaseCallbackManager.merge()` builds a new manager with handlers already passed
|
|
87
|
+
in, so their `isinstance` dedup misses and the handler is added twice. MLflow
|
|
88
|
+
patches `merge` as well to work around it. The configure hook has no such hole.
|
|
89
|
+
|
|
90
|
+
This is also why you must **not** pass a Failproof handler in
|
|
91
|
+
`config={"callbacks": [...]}` yourself — see [Pitfalls](#pitfalls).
|
|
92
|
+
</details>
|
|
93
|
+
|
|
94
|
+
<details>
|
|
95
|
+
<summary><b>Why the handler runs inline</b></summary>
|
|
96
|
+
|
|
97
|
+
`run_inline = True` is not optional. `AsyncCallbackManager` dispatches sync
|
|
98
|
+
handlers through `run_in_executor` unless a handler opts out, and that hop can
|
|
99
|
+
**reorder callbacks** — which scrambles timestamp order and breaks every pairing.
|
|
100
|
+
Writing an event is a `deque.append`, so running inline on the event loop is
|
|
101
|
+
safe.
|
|
102
|
+
</details>
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## What gets recorded
|
|
107
|
+
|
|
108
|
+
| LangChain / LangGraph | Failproof event | When |
|
|
109
|
+
|---|---|---|
|
|
110
|
+
| root run | `agent_start` / `agent_end` | the outermost `.invoke()` / `.stream()` |
|
|
111
|
+
| LangGraph node | `hook_triggered` / `hook_completed` | each node entry and exit |
|
|
112
|
+
| compiled subgraph | nested `agent_start` / `agent_end` | a subgraph run, named `root/node` |
|
|
113
|
+
| tool run | `tool_use` / `tool_result` | each tool call, with args and output |
|
|
114
|
+
| retriever run | `tool_use` / `tool_result` | output summarised, not dumped |
|
|
115
|
+
| chat model / LLM run | `model_request` / `model_response` | each model call, with token usage |
|
|
116
|
+
| streamed tokens | *nothing* | folded into `fw_chunks`, `fw_ttft_ms` on the response |
|
|
117
|
+
| `interrupt()` | `human_wait` + `agent_pause` | the graph suspends for a person |
|
|
118
|
+
| `Command(resume=...)` | `agent_resume` + `human_input` | the graph continues |
|
|
119
|
+
| unhandled exception | `error` + `agent_end(outcome="failed")` | the run raises |
|
|
120
|
+
| intermediate chains | *nothing* | unless named in `include_chains` |
|
|
121
|
+
|
|
122
|
+
### Why a node is a hook and not a nested agent
|
|
123
|
+
|
|
124
|
+
`agent_id` is a `LowCardinality(String)` column and the primary facet on every
|
|
125
|
+
dashboard surface. Promoting `retrieve`, `grade_documents` and `should_continue`
|
|
126
|
+
to agents would:
|
|
127
|
+
|
|
128
|
+
- drown that facet with one entry per node, and
|
|
129
|
+
- label the whole session after whichever node happened to run first.
|
|
130
|
+
|
|
131
|
+
Hook spans render structurally identically in the timeline, and you get a
|
|
132
|
+
per-node latency page for free. Subgraphs *do* become nested agents, because a
|
|
133
|
+
compiled subgraph is a genuine unit of work.
|
|
134
|
+
|
|
135
|
+
### Why streamed tokens emit nothing
|
|
136
|
+
|
|
137
|
+
A 500-token response would otherwise be 500 stored rows against a five-lane
|
|
138
|
+
rail. The chunk count, time-to-first-token and a `fw_streamed` flag land on the
|
|
139
|
+
single `model_response` instead.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## A complete example
|
|
144
|
+
|
|
145
|
+
Copy-pasteable, no helpers:
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
import failproofai_sdk
|
|
149
|
+
from langchain_core.messages import HumanMessage
|
|
150
|
+
from langchain_core.tools import tool
|
|
151
|
+
from langchain_openai import ChatOpenAI
|
|
152
|
+
from langgraph.prebuilt import ToolNode, create_react_agent
|
|
153
|
+
|
|
154
|
+
failproofai_sdk.configure(environment="production")
|
|
155
|
+
failproofai_sdk.instrument()
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@tool
|
|
159
|
+
def price_of(item: str) -> float:
|
|
160
|
+
"""Return the unit price of an item in USD."""
|
|
161
|
+
return {"widget": 42.0, "gadget": 17.5}[item.lower().strip()]
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
@tool
|
|
165
|
+
def stock_of(item: str) -> int:
|
|
166
|
+
"""Return the units of an item currently in stock."""
|
|
167
|
+
return {"widget": 120, "gadget": 0}[item.lower().strip()]
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
# handle_tool_errors=True feeds a raised exception back to the model as a tool
|
|
171
|
+
# message instead of aborting the graph. The failure is recorded either way.
|
|
172
|
+
tools = ToolNode([price_of, stock_of], handle_tool_errors=True)
|
|
173
|
+
graph = create_react_agent(ChatOpenAI(model="gpt-4o-mini"), tools)
|
|
174
|
+
|
|
175
|
+
with failproofai_sdk.session():
|
|
176
|
+
with failproofai_sdk.agent("analyst", goal="price and stock report"):
|
|
177
|
+
result = graph.invoke({
|
|
178
|
+
"messages": [HumanMessage("Price and stock for widget and gadget?")]
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
print(result["messages"][-1].content)
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Running the fuller version of this
|
|
185
|
+
([`examples/research_agent.py`](examples/research_agent.py)) produces **36
|
|
186
|
+
events across 8 types**: the `analyst` span, the graph nested inside it, a hook
|
|
187
|
+
pair per node, a model pair per turn with token counts, and a tool pair per call
|
|
188
|
+
— including one that failed:
|
|
189
|
+
|
|
190
|
+
```
|
|
191
|
+
1 +0.000s agent_start analyst
|
|
192
|
+
2 +0.001s agent_start LangGraph · under analyst
|
|
193
|
+
3 +0.002s hook_triggered agent
|
|
194
|
+
4 +0.003s model_request gpt-5.6-terra
|
|
195
|
+
5 +3.690s model_response gpt-5.6-terra · 99 out-tok
|
|
196
|
+
...
|
|
197
|
+
28 +5.830s tool_use restock_eta
|
|
198
|
+
29 +5.834s tool_result restock_eta · error
|
|
199
|
+
...
|
|
200
|
+
36 +9.209s agent_end analyst · success
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Note event 29: a failed tool is a `tool_result` carrying `error`. The run still
|
|
204
|
+
ends `success`, because the agent recovered — the trace preserves both facts.
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## Naming your agents
|
|
209
|
+
|
|
210
|
+
By default the root span takes the graph's own name (`LangGraph`, or whatever
|
|
211
|
+
you passed to `.compile(name=...)`). Wrap it to get something meaningful:
|
|
212
|
+
|
|
213
|
+
```python
|
|
214
|
+
with failproofai_sdk.session():
|
|
215
|
+
with failproofai_sdk.agent("analyst", goal="price and stock report"):
|
|
216
|
+
graph.invoke(...)
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Everything inside now carries `parent_id="analyst"`, and the dashboard groups by
|
|
220
|
+
`analyst` rather than by a framework class name.
|
|
221
|
+
|
|
222
|
+
For multi-agent setups, nest the scopes — each worker becomes a child span:
|
|
223
|
+
|
|
224
|
+
```python
|
|
225
|
+
with failproofai_sdk.session():
|
|
226
|
+
with failproofai_sdk.agent("supervisor"):
|
|
227
|
+
with failproofai_sdk.agent("researcher"):
|
|
228
|
+
research_graph.invoke(...)
|
|
229
|
+
with failproofai_sdk.agent("writer"):
|
|
230
|
+
writer_graph.invoke(...)
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
See [`examples/supervisor_handoff.py`](examples/supervisor_handoff.py) — 38
|
|
234
|
+
events, 5 agents, correctly nested.
|
|
235
|
+
|
|
236
|
+
> **Keep `agent_id` low-cardinality.** It is a facet column. Use a role or node
|
|
237
|
+
> name (`analyst`, `researcher`), never a UUID or a per-run string. Put the real
|
|
238
|
+
> id in a payload field instead.
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Controlling the session
|
|
243
|
+
|
|
244
|
+
The session id is resolved in this order — first match wins:
|
|
245
|
+
|
|
246
|
+
1. `failproofai_sdk.instrument("langchain", session_id="...")` — pins every run
|
|
247
|
+
2. `config={"metadata": {"failproofai_sdk_session_id": "..."}}` — per call
|
|
248
|
+
3. the ambient `failproofai_sdk.session()` / `agent()` scope
|
|
249
|
+
4. `metadata["session_id"]`, `metadata["conversation_id"]`, `metadata["thread_id"]`
|
|
250
|
+
5. the root run id
|
|
251
|
+
|
|
252
|
+
It is **never synthesised from scratch**, because a made-up id splits one run
|
|
253
|
+
into many sessions — a silent wrong answer rather than a loud one.
|
|
254
|
+
|
|
255
|
+
Per-call override:
|
|
256
|
+
|
|
257
|
+
```python
|
|
258
|
+
graph.invoke(
|
|
259
|
+
{"messages": [...]},
|
|
260
|
+
config={"metadata": {"failproofai_sdk_session_id": f"chat-{user_id}"}},
|
|
261
|
+
)
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
> `thread_id` **is** available to callbacks on this stack, despite what you may
|
|
265
|
+
> have read. Reports that it is `None` are about `langchain-core` dropping
|
|
266
|
+
> `configurable` from `metadata`; LangGraph 1.2 re-adds it. It is still only the
|
|
267
|
+
> fourth resolution step, because a thread is a conversation, not necessarily a
|
|
268
|
+
> single run.
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## Options
|
|
273
|
+
|
|
274
|
+
```python
|
|
275
|
+
failproofai_sdk.instrument(
|
|
276
|
+
"langchain",
|
|
277
|
+
session_id=None, # pin every run to one session id
|
|
278
|
+
include_chains=set(), # allowlist intermediate chains as hook pairs
|
|
279
|
+
capture_content=True, # False drops prompts and completions from payloads
|
|
280
|
+
graph_callbacks=True, # first-class interrupt/resume (needs langgraph >= 1.2)
|
|
281
|
+
)
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
**`capture_content=False`** is the switch for regulated data. Structure,
|
|
285
|
+
timings, token counts, tool names and outcomes are all still recorded; the
|
|
286
|
+
message bodies and completions are not.
|
|
287
|
+
|
|
288
|
+
**`include_chains`** takes a set of runnable names. Use it sparingly — it exists
|
|
289
|
+
for a chain that is genuinely a step in your pipeline, not to surface
|
|
290
|
+
`RunnableSequence`.
|
|
291
|
+
|
|
292
|
+
It applies to **nested** runs only. A runnable you invoke at the top level is
|
|
293
|
+
the session's root, so it becomes the agent span rather than a hook pair, and
|
|
294
|
+
naming it here has no effect.
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## What an event actually looks like
|
|
299
|
+
|
|
300
|
+
A real `model_response`, captured from `examples/quickstart.py`:
|
|
301
|
+
|
|
302
|
+
```json
|
|
303
|
+
{
|
|
304
|
+
"timestamp": "2026-08-19T19:50:56.241974Z",
|
|
305
|
+
"session_id": "7e5de1571fa14424aa1a5bbd88cb420d",
|
|
306
|
+
"agent_id": "LangGraph",
|
|
307
|
+
"type": "model_response",
|
|
308
|
+
"environment": "production",
|
|
309
|
+
"model": "gpt-5.6-terra",
|
|
310
|
+
"stop_reason": "tool_calls",
|
|
311
|
+
"input_tokens": 139,
|
|
312
|
+
"output_tokens": 21,
|
|
313
|
+
"content": "",
|
|
314
|
+
"role": "assistant",
|
|
315
|
+
"request_id": "01a01b93-91a0-7c92-bf45-3857ee43d3ff",
|
|
316
|
+
"usage": { "input_tokens": 139, "output_tokens": 21, "total_tokens": 160 },
|
|
317
|
+
"duration_ms": 5202,
|
|
318
|
+
"framework": "langchain",
|
|
319
|
+
"framework_version": "1.5.6",
|
|
320
|
+
"integration_version": "0.0.1b1",
|
|
321
|
+
"fw_langgraph_version": "1.2.11",
|
|
322
|
+
"fw_run_id": "01a01b93-91a0-7c92-bf45-3857ee43d3ff",
|
|
323
|
+
"fw_node": "agent",
|
|
324
|
+
"fw_step": 1
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Everything prefixed `fw_` is framework-specific detail, namespaced so it can
|
|
329
|
+
never collide with — and silently overwrite — a first-class field like
|
|
330
|
+
`model` or `output_tokens`. `request_id` is what pairs this response with its
|
|
331
|
+
request; without it the dashboard falls back to FIFO pairing and concurrent
|
|
332
|
+
calls mis-pair.
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## Human in the loop
|
|
337
|
+
|
|
338
|
+
LangGraph's `interrupt()` produces **four** events, and neither pair is
|
|
339
|
+
redundant:
|
|
340
|
+
|
|
341
|
+
```python
|
|
342
|
+
from langgraph.types import interrupt, Command
|
|
343
|
+
|
|
344
|
+
def approve(state):
|
|
345
|
+
decision = interrupt({"prompt": "Ship it?", "options": ["yes", "no"]})
|
|
346
|
+
return {"approved": decision == "yes"}
|
|
347
|
+
|
|
348
|
+
with failproofai_sdk.session():
|
|
349
|
+
graph.invoke(state, config) # human_wait + agent_pause
|
|
350
|
+
# ... minutes pass ...
|
|
351
|
+
graph.invoke(Command(resume="yes"), config) # agent_resume + human_input
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
- `human_wait` → `human_input` carries the prompt, the options, the answer and
|
|
355
|
+
the pending-human count;
|
|
356
|
+
- `agent_pause` → `agent_resume` is the **only** thing that feeds paused time.
|
|
357
|
+
Without it the whole human wait is billed as active agent time.
|
|
358
|
+
|
|
359
|
+
The root agent span deliberately stays **open** across the gap, so the two
|
|
360
|
+
`.invoke()` calls are one session and one run.
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
## Pitfalls
|
|
365
|
+
|
|
366
|
+
### A raising tool aborts the whole graph
|
|
367
|
+
|
|
368
|
+
**Symptom:** your run dies on the first tool exception instead of recovering.
|
|
369
|
+
|
|
370
|
+
**Cause:** `create_react_agent` propagates it by default.
|
|
371
|
+
|
|
372
|
+
**Fix:** build the tool node explicitly.
|
|
373
|
+
|
|
374
|
+
```python
|
|
375
|
+
from langgraph.prebuilt import ToolNode, create_react_agent
|
|
376
|
+
|
|
377
|
+
tools = ToolNode([price_of, stock_of], handle_tool_errors=True)
|
|
378
|
+
graph = create_react_agent(model, tools)
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
The failure is recorded as `tool_result` with `error` either way — this only
|
|
382
|
+
decides whether the run survives it.
|
|
383
|
+
|
|
384
|
+
---
|
|
385
|
+
|
|
386
|
+
### A bare `llm.invoke()` shows up as an agent named after the model class
|
|
387
|
+
|
|
388
|
+
**Symptom:** an `agent_id` of `ChatOpenAI` in your trace.
|
|
389
|
+
|
|
390
|
+
**Cause:** a direct model call outside any graph has no parent run, so it opens
|
|
391
|
+
a root agent span **and** emits its own `model_request` / `model_response` pair
|
|
392
|
+
inside it. The dashboard parents leaves to an open agent and synthesises a
|
|
393
|
+
never-ending root span when there is none, so the span is deliberate.
|
|
394
|
+
|
|
395
|
+
**Fix:** name it.
|
|
396
|
+
|
|
397
|
+
```python
|
|
398
|
+
with failproofai_sdk.agent("summariser"):
|
|
399
|
+
summary = ChatOpenAI(model="gpt-4o-mini").invoke([HumanMessage(text)])
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
> Before v1.0.1-beta.2 this case emitted the agent span and **nothing else** —
|
|
403
|
+
> no model name, no token counts, no latency. If you are on an older build,
|
|
404
|
+
> upgrade.
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
### Interrupts look like errors and are not
|
|
409
|
+
|
|
410
|
+
**Symptom:** you expect a red error on every human approval.
|
|
411
|
+
|
|
412
|
+
**Cause:** LangGraph's runnable does `except BaseException: on_chain_error(e);
|
|
413
|
+
raise` with no special case for interrupts, so every HITL pause reaches the
|
|
414
|
+
tracer as an error callback.
|
|
415
|
+
|
|
416
|
+
**Fix:** none needed. Any `GraphBubbleUp` subclass — `GraphInterrupt`,
|
|
417
|
+
`NodeInterrupt`, `ParentCommand`, `GraphDrained` — is treated as control flow.
|
|
418
|
+
Without that, every approval would paint a red error plus
|
|
419
|
+
`agent_end(outcome="failed")`.
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
### Everything is recorded twice
|
|
424
|
+
|
|
425
|
+
**Symptom:** every event appears two times.
|
|
426
|
+
|
|
427
|
+
**Cause:** you passed a Failproof handler in `config={"callbacks": [...]}` *as
|
|
428
|
+
well as* calling `instrument()`.
|
|
429
|
+
|
|
430
|
+
**Fix:** remove it. The configure hook already covers every callback manager in
|
|
431
|
+
the process. There is never a reason to register a handler by hand.
|
|
432
|
+
|
|
433
|
+
---
|
|
434
|
+
|
|
435
|
+
### Nothing is recorded at all
|
|
436
|
+
|
|
437
|
+
Work through these in order:
|
|
438
|
+
|
|
439
|
+
1. Did `instrument()` actually run before the graph executed?
|
|
440
|
+
2. Is there a `with failproofai_sdk.session():` around the call? Without one,
|
|
441
|
+
every `.invoke()` becomes its own session — you will have events, but
|
|
442
|
+
scattered.
|
|
443
|
+
3. Set `FAILPROOFAI_SDK_STRICT=1` and run again. A silently degraded hook will
|
|
444
|
+
now raise instead of being swallowed.
|
|
445
|
+
4. Are you reading the spool directory to check? Do not — a running
|
|
446
|
+
`failproofaid` deletes each batch within milliseconds. Check the dashboard.
|
|
447
|
+
|
|
448
|
+
---
|
|
449
|
+
|
|
450
|
+
### Events from a worker thread raise `TypeError`
|
|
451
|
+
|
|
452
|
+
**Symptom:** `TypeError` naming `session_id` from inside a thread pool.
|
|
453
|
+
|
|
454
|
+
**Cause:** contextvars propagate into asyncio tasks automatically but **not**
|
|
455
|
+
into new threads — a thread starts with an empty context.
|
|
456
|
+
|
|
457
|
+
**Fix:**
|
|
458
|
+
|
|
459
|
+
```python
|
|
460
|
+
pool.submit(failproofai_sdk.propagate(work), x)
|
|
461
|
+
threading.Thread(target=failproofai_sdk.propagate(work)).start()
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
---
|
|
465
|
+
|
|
466
|
+
## Runnable examples
|
|
467
|
+
|
|
468
|
+
| file | what it shows | events |
|
|
469
|
+
|---|---|---|
|
|
470
|
+
| [`examples/quickstart.py`](examples/quickstart.py) | one tool, one turn — the smallest real trace | 14 |
|
|
471
|
+
| [`examples/research_agent.py`](examples/research_agent.py) | 3 tools, several turns, one tool that fails and recovers | 36 |
|
|
472
|
+
| [`examples/supervisor_handoff.py`](examples/supervisor_handoff.py) | a supervisor delegating to 2 workers, nested spans | 38 |
|
|
473
|
+
|
|
474
|
+
```bash
|
|
475
|
+
export OPENAI_API_KEY=sk-...
|
|
476
|
+
export FPAI_MODEL=gpt-4o-mini
|
|
477
|
+
python docs/langgraph/examples/quickstart.py
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
Each prints the event stream it produced. All three were run against a live
|
|
481
|
+
model before shipping.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""langgraph — the smallest thing that produces a trace.
|
|
2
|
+
|
|
3
|
+
pip install 'failproofai-sdk[langgraph]'
|
|
4
|
+
python docs/langgraph/examples/quickstart.py
|
|
5
|
+
|
|
6
|
+
`instrument()` installs a tracer on langchain's global callback manager, so
|
|
7
|
+
every graph, node, tool and model call in the process is recorded — including
|
|
8
|
+
ones inside libraries you did not write. Nothing below passes an id by hand.
|
|
9
|
+
"""
|
|
10
|
+
import sys
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
# Only so this file can import the shared trace printer from docs/_shared/.
|
|
14
|
+
# Delete these two lines and the `_shared` import below and the example still
|
|
15
|
+
# instruments correctly — it just stops printing its own trace at the end.
|
|
16
|
+
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
|
|
17
|
+
|
|
18
|
+
import failproofai_sdk
|
|
19
|
+
from _shared import banner, model, trace
|
|
20
|
+
from langchain_core.messages import HumanMessage
|
|
21
|
+
from langchain_core.tools import tool
|
|
22
|
+
from langchain_openai import ChatOpenAI
|
|
23
|
+
from langgraph.prebuilt import create_react_agent
|
|
24
|
+
|
|
25
|
+
failproofai_sdk.configure(environment="examples")
|
|
26
|
+
failproofai_sdk.instrument()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@tool
|
|
30
|
+
def word_count(text: str) -> int:
|
|
31
|
+
"""Count the words in a piece of text."""
|
|
32
|
+
return len(text.split())
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def main() -> None:
|
|
36
|
+
banner("langgraph quickstart", "one tool, one turn")
|
|
37
|
+
graph = create_react_agent(ChatOpenAI(model=model()), [word_count])
|
|
38
|
+
|
|
39
|
+
# A session groups everything below into one run. Without it each
|
|
40
|
+
# `.invoke()` becomes its own session, which is rarely what you want.
|
|
41
|
+
with failproofai_sdk.session() as sid:
|
|
42
|
+
result = graph.invoke(
|
|
43
|
+
{"messages": [HumanMessage("How many words in 'hello brave new world'?")]}
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
print(" answer:", result["messages"][-1].content.strip()[:120])
|
|
47
|
+
trace(sid, title="langgraph quickstart")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
if __name__ == "__main__":
|
|
51
|
+
main()
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""langgraph — a real multi-step run: three tools, several turns.
|
|
2
|
+
|
|
3
|
+
pip install 'failproofai-sdk[langgraph]'
|
|
4
|
+
python docs/langgraph/examples/research_agent.py
|
|
5
|
+
|
|
6
|
+
What this demonstrates that the quickstart does not:
|
|
7
|
+
|
|
8
|
+
* several model turns in one session, each paired `model_request`/`model_response`
|
|
9
|
+
with real token counts and latency;
|
|
10
|
+
* three distinct tools, each a `tool_use`/`tool_result` pair carrying arguments
|
|
11
|
+
and output;
|
|
12
|
+
* a tool that raises — recorded as `tool_result` with `error` set, and the run
|
|
13
|
+
keeps going, because a failed tool is data, not a crash;
|
|
14
|
+
* a named `agent()` scope, so the trace is labelled `analyst` rather than the
|
|
15
|
+
graph's generated id.
|
|
16
|
+
"""
|
|
17
|
+
import sys
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
# Only so this file can import the shared trace printer from docs/_shared/.
|
|
21
|
+
# Delete these two lines and the `_shared` import below and the example still
|
|
22
|
+
# instruments correctly — it just stops printing its own trace at the end.
|
|
23
|
+
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
|
|
24
|
+
|
|
25
|
+
import failproofai_sdk
|
|
26
|
+
from _shared import banner, model, trace
|
|
27
|
+
from langchain_core.messages import HumanMessage
|
|
28
|
+
from langchain_core.tools import tool
|
|
29
|
+
from langchain_openai import ChatOpenAI
|
|
30
|
+
from langgraph.prebuilt import ToolNode, create_react_agent
|
|
31
|
+
|
|
32
|
+
failproofai_sdk.configure(environment="examples")
|
|
33
|
+
failproofai_sdk.instrument()
|
|
34
|
+
|
|
35
|
+
_PRICES = {"widget": 42.0, "gadget": 17.5, "sprocket": 3.25}
|
|
36
|
+
_STOCK = {"widget": 120, "gadget": 0, "sprocket": 8}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@tool
|
|
40
|
+
def price_of(item: str) -> float:
|
|
41
|
+
"""Return the unit price of an item in USD."""
|
|
42
|
+
return _PRICES[item.lower().strip()]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@tool
|
|
46
|
+
def stock_of(item: str) -> int:
|
|
47
|
+
"""Return the units of an item currently in stock."""
|
|
48
|
+
return _STOCK[item.lower().strip()]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@tool
|
|
52
|
+
def restock_eta(item: str) -> str:
|
|
53
|
+
"""Return the restock ETA. Raises for items that are not tracked."""
|
|
54
|
+
# Deliberately unhandled: the trace should show a failed tool call and the
|
|
55
|
+
# agent recovering from it, which is the interesting case to observe.
|
|
56
|
+
raise LookupError(f"no restock schedule for {item!r}")
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def main() -> None:
|
|
60
|
+
banner("langgraph research agent", "3 tools · multi-turn · one failing call")
|
|
61
|
+
|
|
62
|
+
# `handle_tool_errors=True` feeds the exception back to the model as a tool
|
|
63
|
+
# message instead of raising out of `.invoke()`. The failproof trace records
|
|
64
|
+
# the failure either way — this just lets the run continue so you can watch
|
|
65
|
+
# the model recover from it.
|
|
66
|
+
tools = ToolNode([price_of, stock_of, restock_eta], handle_tool_errors=True)
|
|
67
|
+
graph = create_react_agent(ChatOpenAI(model=model()), tools)
|
|
68
|
+
|
|
69
|
+
question = (
|
|
70
|
+
"For 'widget' and 'gadget': give me the unit price and the stock level. "
|
|
71
|
+
"For anything out of stock, try to look up the restock ETA. "
|
|
72
|
+
"Finish with a two-line summary."
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
# `agent("analyst")` names the span. Without it the adapter falls back to the
|
|
76
|
+
# graph's own label, which is stable but not meaningful on a dashboard.
|
|
77
|
+
with failproofai_sdk.session() as sid:
|
|
78
|
+
with failproofai_sdk.agent("analyst", goal="price and stock report"):
|
|
79
|
+
result = graph.invoke({"messages": [HumanMessage(question)]})
|
|
80
|
+
|
|
81
|
+
print(" answer:", result["messages"][-1].content.strip()[:200], "\n")
|
|
82
|
+
trace(sid, title="langgraph research agent")
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
if __name__ == "__main__":
|
|
86
|
+
main()
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""langgraph — a supervisor delegating to two workers.
|
|
2
|
+
|
|
3
|
+
pip install 'failproofai-sdk[langgraph]'
|
|
4
|
+
python docs/langgraph/examples/supervisor_handoff.py
|
|
5
|
+
|
|
6
|
+
Multi-agent is where a flat event log stops being readable, so this is the
|
|
7
|
+
example to run if you want to see what the parent/child structure buys you.
|
|
8
|
+
|
|
9
|
+
Each worker runs inside its own `agent()` scope nested in the supervisor's, so
|
|
10
|
+
every event a worker emits carries `parent_id="supervisor"` and `depth=2`. The
|
|
11
|
+
dashboard renders that as a tree; a flat log cannot tell you which agent made
|
|
12
|
+
which model call.
|
|
13
|
+
"""
|
|
14
|
+
import sys
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
# Only so this file can import the shared trace printer from docs/_shared/.
|
|
18
|
+
# Delete these two lines and the `_shared` import below and the example still
|
|
19
|
+
# instruments correctly — it just stops printing its own trace at the end.
|
|
20
|
+
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
|
|
21
|
+
|
|
22
|
+
import failproofai_sdk
|
|
23
|
+
from _shared import banner, model, trace
|
|
24
|
+
from langchain_core.messages import HumanMessage
|
|
25
|
+
from langchain_core.tools import tool
|
|
26
|
+
from langchain_openai import ChatOpenAI
|
|
27
|
+
from langgraph.prebuilt import create_react_agent
|
|
28
|
+
|
|
29
|
+
failproofai_sdk.configure(environment="examples")
|
|
30
|
+
failproofai_sdk.instrument()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@tool
|
|
34
|
+
def fetch_incidents(service: str) -> str:
|
|
35
|
+
"""List recent incidents for a service."""
|
|
36
|
+
return {
|
|
37
|
+
"checkout": "2 incidents: 503 spike (12m), payment timeout (4m)",
|
|
38
|
+
"search": "1 incident: index lag (31m)",
|
|
39
|
+
}.get(service, "no incidents on record")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@tool
|
|
43
|
+
def oncall_for(service: str) -> str:
|
|
44
|
+
"""Return who is on call for a service."""
|
|
45
|
+
return {"checkout": "dana", "search": "kim"}.get(service, "unassigned")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def worker(name: str, tools: list, prompt: str) -> str:
|
|
49
|
+
"""One delegated unit of work, bracketed as its own child agent."""
|
|
50
|
+
graph = create_react_agent(ChatOpenAI(model=model()), tools)
|
|
51
|
+
with failproofai_sdk.agent(name, goal=prompt[:60]):
|
|
52
|
+
out = graph.invoke({"messages": [HumanMessage(prompt)]})
|
|
53
|
+
return out["messages"][-1].content
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def main() -> None:
|
|
57
|
+
banner("langgraph supervisor handoff", "1 supervisor → 2 workers · nested spans")
|
|
58
|
+
|
|
59
|
+
with failproofai_sdk.session() as sid:
|
|
60
|
+
with failproofai_sdk.agent("supervisor", goal="incident brief for checkout"):
|
|
61
|
+
incidents = worker(
|
|
62
|
+
"incident_worker",
|
|
63
|
+
[fetch_incidents],
|
|
64
|
+
"Use the tool to list recent incidents for the 'checkout' service.",
|
|
65
|
+
)
|
|
66
|
+
owner = worker(
|
|
67
|
+
"roster_worker",
|
|
68
|
+
[oncall_for],
|
|
69
|
+
"Use the tool to say who is on call for the 'checkout' service.",
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# The supervisor's own model turn, at depth 1 — the two worker turns
|
|
73
|
+
# above are at depth 2 and carry parent_id="supervisor".
|
|
74
|
+
summary = ChatOpenAI(model=model()).invoke(
|
|
75
|
+
[HumanMessage(f"In two lines, brief the on-call.\n{incidents}\n{owner}")]
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
print(" brief:", summary.content.strip()[:200], "\n")
|
|
79
|
+
trace(sid, title="langgraph supervisor handoff")
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
if __name__ == "__main__":
|
|
83
|
+
main()
|