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,491 @@
|
|
|
1
|
+
# Your own agent — no framework
|
|
2
|
+
|
|
3
|
+
For an agent you wrote yourself, or a framework Failproof has no adapter for.
|
|
4
|
+
There is nothing to instrument: you emit the events.
|
|
5
|
+
|
|
6
|
+
This is a first-class path, not a consolation prize. It is exactly what the four
|
|
7
|
+
adapters call underneath — they are translation tables over the same API.
|
|
8
|
+
|
|
9
|
+
- [Install](#install)
|
|
10
|
+
- [The three scopes](#the-three-scopes)
|
|
11
|
+
- [What a scope does on the way out](#what-a-scope-does-on-the-way-out)
|
|
12
|
+
- [The fifteen event methods](#the-fifteen-event-methods)
|
|
13
|
+
- [A complete example](#a-complete-example)
|
|
14
|
+
- [Threads and async](#threads-and-async)
|
|
15
|
+
- [Instrumenting an unsupported framework](#instrumenting-an-unsupported-framework)
|
|
16
|
+
- [Why there is no AutoGen adapter](#why-there-is-no-autogen-adapter)
|
|
17
|
+
- [Pitfalls](#pitfalls)
|
|
18
|
+
- [Runnable examples](#runnable-examples)
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install failproofai-sdk
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
No extras. Zero dependencies.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## The three scopes
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
import failproofai_sdk
|
|
36
|
+
|
|
37
|
+
failproofai_sdk.configure(environment="production")
|
|
38
|
+
|
|
39
|
+
with failproofai_sdk.session() as sid: # identity only — emits nothing
|
|
40
|
+
with failproofai_sdk.agent("planner"): # agent_start / agent_end
|
|
41
|
+
with failproofai_sdk.tool_call("search", input={"q": q}) as t:
|
|
42
|
+
t.output = search(q) # tool_use / tool_result
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
| scope | emits | purpose |
|
|
46
|
+
|---|---|---|
|
|
47
|
+
| `session()` | nothing | binds a session id — groups one run |
|
|
48
|
+
| `agent()` | `agent_start` / `agent_end` | brackets a unit of work |
|
|
49
|
+
| `tool_call()` | `tool_use` / `tool_result` | brackets one tool, measuring it |
|
|
50
|
+
|
|
51
|
+
**Everything inside them can omit `session_id=` and `agent_id=`.** The scopes
|
|
52
|
+
bind identity on contextvars and every `event.*` call reads it back. That is the
|
|
53
|
+
whole point — threading two ids through every function that might emit an event
|
|
54
|
+
is what turns instrumentation into a diff nobody wants to review.
|
|
55
|
+
|
|
56
|
+
All three work under `async with` as well as `with`:
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
async with failproofai_sdk.session():
|
|
60
|
+
async with failproofai_sdk.agent("planner"):
|
|
61
|
+
async with failproofai_sdk.tool_call("search", input={"q": q}) as t:
|
|
62
|
+
t.output = await search(q)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Nesting agents
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
with failproofai_sdk.session():
|
|
69
|
+
with failproofai_sdk.agent("supervisor"):
|
|
70
|
+
with failproofai_sdk.agent("researcher"): # parent_id = "supervisor"
|
|
71
|
+
...
|
|
72
|
+
with failproofai_sdk.agent("writer"): # parent_id = "supervisor"
|
|
73
|
+
...
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`parent_id` and `depth` are computed from the stack. You never pass them.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## What a scope does on the way out
|
|
81
|
+
|
|
82
|
+
`agent()` handles exceptions for you:
|
|
83
|
+
|
|
84
|
+
| what happened | events emitted | `outcome` |
|
|
85
|
+
|---|---|---|
|
|
86
|
+
| nothing raised | `agent_end` | `success` |
|
|
87
|
+
| `Exception` | `error`, then `agent_end` | `failed` |
|
|
88
|
+
| `KeyboardInterrupt` / `SystemExit` | `error`, then `agent_end` | `failed` |
|
|
89
|
+
| `CancelledError` / `GeneratorExit` | `agent_end` only | `cancelled` |
|
|
90
|
+
|
|
91
|
+
Two deliberate details:
|
|
92
|
+
|
|
93
|
+
- **`error` strictly before `agent_end`.** The dashboard closes the span at
|
|
94
|
+
`agent_end`, so anything emitted after it is attributed to nothing.
|
|
95
|
+
- **A cancellation is not a failure.** Otherwise every cancelled run pollutes
|
|
96
|
+
the errors surface. `asyncio.CancelledError` has been a `BaseException` since
|
|
97
|
+
Python 3.8, and it is caught and re-raised untouched.
|
|
98
|
+
|
|
99
|
+
The exception is **always** re-raised. A scope never swallows.
|
|
100
|
+
|
|
101
|
+
`tool_call()` does the same for tools: a raising body produces
|
|
102
|
+
`tool_result(error="TypeName: msg")` and **no** `error` event, because a tool
|
|
103
|
+
failure the agent loop catches is not a run-level error, and one that propagates
|
|
104
|
+
is reported exactly once by the enclosing `agent()`.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## The fifteen event methods
|
|
109
|
+
|
|
110
|
+
### agents
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
failproofai_sdk.event.agent_start(agent_id="planner", goal="find the cheapest flight")
|
|
114
|
+
failproofai_sdk.event.agent_end(agent_id="planner", outcome="success", summary="...")
|
|
115
|
+
failproofai_sdk.event.agent_pause(pause_id="p1", reason="awaiting approval")
|
|
116
|
+
failproofai_sdk.event.agent_resume(pause_id="p1")
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
`outcome` is `"failed"`, never `"failure"` — only `error|failed|timeout|rejected`
|
|
120
|
+
count as a failure server-side.
|
|
121
|
+
|
|
122
|
+
### models
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
failproofai_sdk.event.model_request(
|
|
126
|
+
model="gpt-4o-mini",
|
|
127
|
+
messages=[{"role": "user", "content": "..."}],
|
|
128
|
+
request_id="req-1", # optional; pairs the two events explicitly
|
|
129
|
+
)
|
|
130
|
+
failproofai_sdk.event.model_response(
|
|
131
|
+
model="gpt-4o-mini",
|
|
132
|
+
content="...",
|
|
133
|
+
input_tokens=139,
|
|
134
|
+
output_tokens=21,
|
|
135
|
+
request_id="req-1",
|
|
136
|
+
duration_ms=5202, # int, never float
|
|
137
|
+
)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Pass `request_id` if you make concurrent model calls — without it the dashboard
|
|
141
|
+
pairs requests and responses FIFO per agent, and concurrent calls mis-pair.
|
|
142
|
+
|
|
143
|
+
### tools
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
failproofai_sdk.event.tool_use(tool_name="search", tool_call_id="c1", input={"q": "..."})
|
|
147
|
+
failproofai_sdk.event.tool_result(tool_name="search", tool_call_id="c1", output="...", error=None)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
`tool_call_id` is what pairs them. Prefer the `tool_call()` scope, which
|
|
151
|
+
guarantees the pair even when the body raises.
|
|
152
|
+
|
|
153
|
+
### hooks
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
failproofai_sdk.event.hook_triggered(hook_name="retrieve", hook_id="h1", trigger_event="node")
|
|
157
|
+
failproofai_sdk.event.hook_completed(hook_name="retrieve", hook_id="h1", outcome="success")
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Use these for node, step or middleware boundaries — **not** nested `agent()`
|
|
161
|
+
calls. `agent_id` is a low-cardinality facet, and one entry per node drowns it.
|
|
162
|
+
|
|
163
|
+
### humans
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
failproofai_sdk.event.human_wait(input_id="i1", prompt="Approve?", options=["yes", "no"])
|
|
167
|
+
failproofai_sdk.event.human_input(input_id="i1", response="yes")
|
|
168
|
+
|
|
169
|
+
failproofai_sdk.event.human_pause(reason="operator paused the run", user_id="dana")
|
|
170
|
+
failproofai_sdk.event.human_interrupt(reason="operator stopped the run", at_step="step_3")
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
`human_wait`/`human_input` = *the agent asked a person*.
|
|
174
|
+
`human_pause`/`human_interrupt` = *a person acted on the agent* — a stop button,
|
|
175
|
+
an operator intervention. No framework signals the second pair, so it is always
|
|
176
|
+
yours.
|
|
177
|
+
|
|
178
|
+
Emit `agent_pause`/`agent_resume` around a human wait too: only that pair feeds
|
|
179
|
+
paused time, and without it the wait is billed as active agent time.
|
|
180
|
+
|
|
181
|
+
### failures
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
failproofai_sdk.event.error(
|
|
185
|
+
error_type="TimeoutError",
|
|
186
|
+
message="provider timed out after 30s",
|
|
187
|
+
traceback="...",
|
|
188
|
+
)
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Usually emitted for you by `agent()`. Call it directly for a failure that does
|
|
192
|
+
not raise — a validation rejection, a guardrail trip.
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## A complete example
|
|
197
|
+
|
|
198
|
+
A real tool-calling loop against the OpenAI API, with no agent framework at all:
|
|
199
|
+
|
|
200
|
+
```python
|
|
201
|
+
import json
|
|
202
|
+
|
|
203
|
+
import failproofai_sdk
|
|
204
|
+
from openai import OpenAI
|
|
205
|
+
|
|
206
|
+
failproofai_sdk.configure(environment="production")
|
|
207
|
+
|
|
208
|
+
client = OpenAI()
|
|
209
|
+
MODEL = "gpt-4o-mini"
|
|
210
|
+
|
|
211
|
+
PRICE = {"widget": 42.0, "gadget": 17.5}
|
|
212
|
+
STOCK = {"widget": 120, "gadget": 0}
|
|
213
|
+
|
|
214
|
+
TOOLS = [
|
|
215
|
+
{
|
|
216
|
+
"type": "function",
|
|
217
|
+
"function": {
|
|
218
|
+
"name": "price_of",
|
|
219
|
+
"description": "Unit price of an item.",
|
|
220
|
+
"parameters": {
|
|
221
|
+
"type": "object",
|
|
222
|
+
"properties": {"item": {"type": "string"}},
|
|
223
|
+
"required": ["item"],
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
]
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def run_tool(name: str, args: dict) -> str:
|
|
231
|
+
if name == "price_of":
|
|
232
|
+
return str(PRICE[args["item"].lower().strip()])
|
|
233
|
+
raise LookupError(f"unknown tool {name!r}")
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def turn(messages: list):
|
|
237
|
+
"""One LLM call, bracketed by the model pair."""
|
|
238
|
+
failproofai_sdk.event.model_request(model=MODEL, messages=messages)
|
|
239
|
+
reply = client.chat.completions.create(model=MODEL, messages=messages, tools=TOOLS)
|
|
240
|
+
usage = reply.usage
|
|
241
|
+
failproofai_sdk.event.model_response(
|
|
242
|
+
model=MODEL,
|
|
243
|
+
content=reply.choices[0].message.content or "",
|
|
244
|
+
input_tokens=usage.prompt_tokens,
|
|
245
|
+
output_tokens=usage.completion_tokens,
|
|
246
|
+
)
|
|
247
|
+
return reply.choices[0].message
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
messages = [
|
|
251
|
+
{"role": "system", "content": "Use the tools for every number. Be terse."},
|
|
252
|
+
{"role": "user", "content": "Price for widget and gadget?"},
|
|
253
|
+
]
|
|
254
|
+
|
|
255
|
+
with failproofai_sdk.session():
|
|
256
|
+
with failproofai_sdk.agent("inventory", goal="price report"):
|
|
257
|
+
for _ in range(4): # bounded: an unbounded agent loop is its own bug
|
|
258
|
+
message = turn(messages)
|
|
259
|
+
calls = message.tool_calls or []
|
|
260
|
+
if not calls:
|
|
261
|
+
print(message.content)
|
|
262
|
+
break
|
|
263
|
+
|
|
264
|
+
messages.append(message.model_dump(exclude_none=True))
|
|
265
|
+
for call in calls:
|
|
266
|
+
args = json.loads(call.function.arguments or "{}")
|
|
267
|
+
# tool_call() emits tool_use now and tool_result on exit,
|
|
268
|
+
# turning a raised exception into `error` on the result.
|
|
269
|
+
with failproofai_sdk.tool_call(
|
|
270
|
+
call.function.name, tool_call_id=call.id, input=args
|
|
271
|
+
) as handle:
|
|
272
|
+
handle.output = run_tool(call.function.name, args)
|
|
273
|
+
messages.append({
|
|
274
|
+
"role": "tool",
|
|
275
|
+
"tool_call_id": call.id,
|
|
276
|
+
"content": str(handle.output),
|
|
277
|
+
})
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Produces **14 events across 6 types** — the same shape an adapter would give
|
|
281
|
+
you:
|
|
282
|
+
|
|
283
|
+
```
|
|
284
|
+
1 +0.000s agent_start inventory
|
|
285
|
+
2 +0.000s model_request gpt-5.6-terra
|
|
286
|
+
3 +3.962s model_response gpt-5.6-terra · 96 out-tok
|
|
287
|
+
4 +3.962s tool_use price_of
|
|
288
|
+
5 +3.962s tool_result price_of · ok
|
|
289
|
+
...
|
|
290
|
+
12 +3.962s model_request gpt-5.6-terra
|
|
291
|
+
13 +8.459s model_response gpt-5.6-terra · 29 out-tok
|
|
292
|
+
14 +8.459s agent_end inventory · success
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## Threads and async
|
|
298
|
+
|
|
299
|
+
contextvars propagate into asyncio tasks **automatically**. They do **not**
|
|
300
|
+
propagate into new threads — a thread starts with an empty context.
|
|
301
|
+
|
|
302
|
+
```python
|
|
303
|
+
import failproofai_sdk
|
|
304
|
+
|
|
305
|
+
# asyncio: nothing to do
|
|
306
|
+
async with failproofai_sdk.session():
|
|
307
|
+
await asyncio.gather(worker(1), worker(2)) # both see the session
|
|
308
|
+
|
|
309
|
+
# threads: wrap the callable
|
|
310
|
+
pool.submit(failproofai_sdk.propagate(work), x)
|
|
311
|
+
pool.map(failproofai_sdk.propagate(work), items)
|
|
312
|
+
threading.Thread(target=failproofai_sdk.propagate(work)).start()
|
|
313
|
+
loop.run_in_executor(None, failproofai_sdk.propagate(work), x)
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
Without `propagate()`, the worker's events raise a `TypeError` naming the fix,
|
|
317
|
+
rather than silently landing on no session.
|
|
318
|
+
|
|
319
|
+
`propagate()` snapshots identity *values*, not the `Context` object — a
|
|
320
|
+
`Context` cannot be entered by two threads at once, so the obvious
|
|
321
|
+
`copy_context().run` form crashes on any reuse such as `pool.map`.
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## Instrumenting an unsupported framework
|
|
326
|
+
|
|
327
|
+
Most agent frameworks give you three seams. Map them and you have a complete
|
|
328
|
+
trace.
|
|
329
|
+
|
|
330
|
+
**1. Bracket the run** — wherever your framework starts and finishes a unit of
|
|
331
|
+
work:
|
|
332
|
+
|
|
333
|
+
```python
|
|
334
|
+
with failproofai_sdk.session():
|
|
335
|
+
with failproofai_sdk.agent(agent_name, goal=task):
|
|
336
|
+
result = framework.run(task)
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
**2. Bracket each tool** — in whatever the framework calls a tool wrapper or
|
|
340
|
+
middleware:
|
|
341
|
+
|
|
342
|
+
```python
|
|
343
|
+
with failproofai_sdk.tool_call(name, input=args) as call:
|
|
344
|
+
call.output = original(**args)
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
**3. Pair each model call** — around the provider call:
|
|
348
|
+
|
|
349
|
+
```python
|
|
350
|
+
failproofai_sdk.event.model_request(model=model, messages=messages)
|
|
351
|
+
reply = provider.complete(...)
|
|
352
|
+
failproofai_sdk.event.model_response(
|
|
353
|
+
model=model, content=text,
|
|
354
|
+
input_tokens=usage.prompt_tokens,
|
|
355
|
+
output_tokens=usage.completion_tokens,
|
|
356
|
+
)
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
If the framework has a node, step or middleware boundary worth seeing, add
|
|
360
|
+
`hook_triggered` / `hook_completed` around it. Do **not** promote it to a nested
|
|
361
|
+
`agent()`.
|
|
362
|
+
|
|
363
|
+
### If the framework has a global callback surface
|
|
364
|
+
|
|
365
|
+
If it does expose a process-wide registration point, four rules from the shipped
|
|
366
|
+
adapters are worth copying:
|
|
367
|
+
|
|
368
|
+
- **Never raise into the caller.** Wrap every callback so a bug in yours cannot
|
|
369
|
+
affect the instrumented call.
|
|
370
|
+
- **Do not hold a contextvar token between two callbacks.** When start and end
|
|
371
|
+
are separate calls, `ContextVar.reset(token)` raises across asyncio tasks and
|
|
372
|
+
threads alike. Keep a map from the framework's own run id to identity, and pass
|
|
373
|
+
`session_id=` / `agent_id=` explicitly.
|
|
374
|
+
- **Bound every map.** Orphaned starts are normal — a crashed run, an unconsumed
|
|
375
|
+
stream, a skipped end callback. Unbounded, that is a leak in a long-lived
|
|
376
|
+
server.
|
|
377
|
+
- **Restore exactly what you replaced.** Save the original attribute object; if
|
|
378
|
+
it is no longer yours at teardown, leave it alone rather than deleting somebody
|
|
379
|
+
else's patch.
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
## Why there is no AutoGen adapter
|
|
384
|
+
|
|
385
|
+
Two reasons, and both are decisions rather than backlog items.
|
|
386
|
+
|
|
387
|
+
**`autogen-core` is discontinued.** The `autogen-core` / `autogen-agentchat`
|
|
388
|
+
line has been unmaintained since 2025-09-30. An adapter against a dead callback
|
|
389
|
+
surface is a dependency that cannot be fixed when it drifts.
|
|
390
|
+
|
|
391
|
+
**AG2 has no global auto-instrument hook.** AG2 — the community fork — exposes
|
|
392
|
+
no process-wide registration point equivalent to LangChain's configure hook,
|
|
393
|
+
CrewAI's event bus, LlamaIndex's dispatcher or Pydantic AI's capability list.
|
|
394
|
+
Instrumenting it means wrapping each agent at each construction site, which is a
|
|
395
|
+
wrapper you paste into your own code — precisely the ergonomics the adapters
|
|
396
|
+
exist to remove.
|
|
397
|
+
|
|
398
|
+
If AutoGen matters to you, the three seams above record the same fifteen event
|
|
399
|
+
types at the same fidelity. It just costs you the call sites.
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
## Pitfalls
|
|
404
|
+
|
|
405
|
+
### Spans that never finish
|
|
406
|
+
|
|
407
|
+
**Symptom:** the dashboard shows a run still going, hours later.
|
|
408
|
+
|
|
409
|
+
**Cause:** an opening event with no closing one — a `model_request` with no
|
|
410
|
+
`model_response`, or a `tool_use` with no `tool_result`.
|
|
411
|
+
|
|
412
|
+
**Fix:** use the scopes, which guarantee the pair even when the body raises. If
|
|
413
|
+
you call `event.*` by hand, use `try` / `finally`.
|
|
414
|
+
|
|
415
|
+
---
|
|
416
|
+
|
|
417
|
+
### `ValueError: duration_ms is auto-computed`
|
|
418
|
+
|
|
419
|
+
**Symptom:** passing `duration_ms` to a closing event raises.
|
|
420
|
+
|
|
421
|
+
**Cause:** it is measured by the SDK from the matching opening event, so passing
|
|
422
|
+
it is rejected on `tool_result`, `hook_completed`, `agent_resume` and
|
|
423
|
+
`human_input`.
|
|
424
|
+
|
|
425
|
+
**Fix:** do not pass it. The exception is `model_response`, where it **is**
|
|
426
|
+
accepted, because only you know the real provider latency — and it must be an
|
|
427
|
+
`int` — a float raises `ValueError` at the call site, because the server would store NULL for it.
|
|
428
|
+
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
### `TypeError: ... missing session_id`
|
|
432
|
+
|
|
433
|
+
**Symptom:** a `TypeError` naming `session_id` from inside a worker.
|
|
434
|
+
|
|
435
|
+
**Cause:** you emitted from a thread that never inherited the context.
|
|
436
|
+
|
|
437
|
+
**Fix:** `failproofai_sdk.propagate()`. See [Threads and async](#threads-and-async).
|
|
438
|
+
|
|
439
|
+
This is deliberately a loud error rather than a silent drop: an event with no
|
|
440
|
+
session is skipped by ingest and answered `200`, which is the exact silent
|
|
441
|
+
failure the identity layer exists to prevent.
|
|
442
|
+
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
### Extra fields silently disappearing
|
|
446
|
+
|
|
447
|
+
**Symptom:** you passed `model="x"` as an extra field and it did not show up, or
|
|
448
|
+
it overwrote something.
|
|
449
|
+
|
|
450
|
+
**Cause:** extras are merged **last**, so an extra named like a declared field —
|
|
451
|
+
`tool_name`, `model`, `outcome`, `input_tokens` — would overwrite the real field
|
|
452
|
+
and change a promoted column.
|
|
453
|
+
|
|
454
|
+
**Fix:** namespace yours. The adapters use an `fw_` prefix:
|
|
455
|
+
|
|
456
|
+
```python
|
|
457
|
+
failproofai_sdk.event.tool_use(
|
|
458
|
+
tool_name="search", tool_call_id="c1",
|
|
459
|
+
my_region="eu-west-1", # fine
|
|
460
|
+
# model="x", # dropped, with a warning
|
|
461
|
+
)
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
---
|
|
465
|
+
|
|
466
|
+
### `agent_id` full of UUIDs
|
|
467
|
+
|
|
468
|
+
**Symptom:** the agent filter has thousands of entries.
|
|
469
|
+
|
|
470
|
+
**Cause:** `agent_id` is a low-cardinality facet column, and you put a run id in
|
|
471
|
+
it.
|
|
472
|
+
|
|
473
|
+
**Fix:** use a role or node name. Put the real id in a payload field.
|
|
474
|
+
|
|
475
|
+
---
|
|
476
|
+
|
|
477
|
+
## Runnable examples
|
|
478
|
+
|
|
479
|
+
| file | what it shows | events |
|
|
480
|
+
|---|---|---|
|
|
481
|
+
| [`examples/quickstart.py`](examples/quickstart.py) | the three scopes, ~40 lines | 6 |
|
|
482
|
+
| [`examples/research_agent.py`](examples/research_agent.py) | a real OpenAI tool-calling loop, hand-instrumented | 14 |
|
|
483
|
+
|
|
484
|
+
```bash
|
|
485
|
+
pip install failproofai-sdk openai
|
|
486
|
+
export OPENAI_API_KEY=sk-...
|
|
487
|
+
export FPAI_MODEL=gpt-4o-mini
|
|
488
|
+
python docs/manual/examples/quickstart.py
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
Both were run against a live model before shipping.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""no framework — the scopes and `event.*` directly.
|
|
2
|
+
|
|
3
|
+
pip install failproofai-sdk
|
|
4
|
+
python docs/manual/examples/quickstart.py
|
|
5
|
+
|
|
6
|
+
There is no adapter here and nothing to instrument. This is the path for an
|
|
7
|
+
agent you wrote yourself, or a framework failproof does not support yet.
|
|
8
|
+
|
|
9
|
+
Three scopes do the identity work:
|
|
10
|
+
|
|
11
|
+
session() binds a session id. emits nothing.
|
|
12
|
+
agent() brackets a span with agent_start / agent_end.
|
|
13
|
+
tool_call() brackets a tool with tool_use / tool_result.
|
|
14
|
+
|
|
15
|
+
Everything inside them can omit `session_id=` and `agent_id=` — the scopes bind
|
|
16
|
+
them on contextvars and every `event.*` call reads them back.
|
|
17
|
+
"""
|
|
18
|
+
import sys
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
|
|
21
|
+
# Only so this file can import the shared trace printer from docs/_shared/.
|
|
22
|
+
# Delete these two lines and the `_shared` import below and the example still
|
|
23
|
+
# instruments correctly — it just stops printing its own trace at the end.
|
|
24
|
+
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
|
|
25
|
+
|
|
26
|
+
import failproofai_sdk
|
|
27
|
+
from _shared import banner, model, trace
|
|
28
|
+
|
|
29
|
+
failproofai_sdk.configure(environment="examples")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def look_up(city: str) -> str:
|
|
33
|
+
return {"tokyo": "37M", "delhi": "33M"}.get(city.lower(), "unknown")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def main() -> None:
|
|
37
|
+
banner("manual quickstart", "no framework · scopes + event.*")
|
|
38
|
+
|
|
39
|
+
with failproofai_sdk.session() as sid:
|
|
40
|
+
with failproofai_sdk.agent("main", goal="answer one question"):
|
|
41
|
+
# tool_call() emits tool_use on entry and tool_result on exit,
|
|
42
|
+
# measuring duration and recording an exception as an error.
|
|
43
|
+
with failproofai_sdk.tool_call("population", input={"city": "tokyo"}) as call:
|
|
44
|
+
call.output = look_up("tokyo")
|
|
45
|
+
|
|
46
|
+
failproofai_sdk.event.model_request(model=model(), messages=[
|
|
47
|
+
{"role": "user", "content": "population of tokyo?"}
|
|
48
|
+
])
|
|
49
|
+
failproofai_sdk.event.model_response(
|
|
50
|
+
model=model(), output_tokens=3, duration_ms=210, content="37M"
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
trace(sid, title="manual quickstart")
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
if __name__ == "__main__":
|
|
57
|
+
main()
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"""no framework — a real agent loop, hand-instrumented.
|
|
2
|
+
|
|
3
|
+
pip install failproofai-sdk openai
|
|
4
|
+
python docs/manual/examples/research_agent.py
|
|
5
|
+
|
|
6
|
+
A working tool-calling loop against the openai api with no agent framework at
|
|
7
|
+
all, instrumented by hand. This is the reference for "my agent is bespoke".
|
|
8
|
+
|
|
9
|
+
Every event an adapter would emit for you appears here explicitly, so you can
|
|
10
|
+
see exactly what the adapters are doing on your behalf:
|
|
11
|
+
|
|
12
|
+
session() -> identity only, no event
|
|
13
|
+
agent() -> agent_start / agent_end
|
|
14
|
+
event.model_request/response -> one pair per llm turn, with usage
|
|
15
|
+
tool_call() -> tool_use / tool_result, duration measured
|
|
16
|
+
event.error -> anything you want on the errors surface
|
|
17
|
+
|
|
18
|
+
The one rule: emit the pairs. `model_request` without `model_response` is an
|
|
19
|
+
open span the dashboard renders as still-running forever.
|
|
20
|
+
"""
|
|
21
|
+
import json
|
|
22
|
+
import sys
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
|
|
25
|
+
# Only so this file can import the shared trace printer from docs/_shared/.
|
|
26
|
+
# Delete these two lines and the `_shared` import below and the example still
|
|
27
|
+
# instruments correctly — it just stops printing its own trace at the end.
|
|
28
|
+
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
|
|
29
|
+
|
|
30
|
+
import failproofai_sdk
|
|
31
|
+
from _shared import banner, model, trace
|
|
32
|
+
from openai import OpenAI
|
|
33
|
+
|
|
34
|
+
failproofai_sdk.configure(environment="examples")
|
|
35
|
+
|
|
36
|
+
client = OpenAI()
|
|
37
|
+
|
|
38
|
+
_PRICE = {"widget": 42.0, "gadget": 17.5}
|
|
39
|
+
_STOCK = {"widget": 120, "gadget": 0}
|
|
40
|
+
|
|
41
|
+
TOOLS = [
|
|
42
|
+
{
|
|
43
|
+
"type": "function",
|
|
44
|
+
"function": {
|
|
45
|
+
"name": "price_of",
|
|
46
|
+
"description": "Unit price of an item. Valid: widget, gadget.",
|
|
47
|
+
"parameters": {
|
|
48
|
+
"type": "object",
|
|
49
|
+
"properties": {"item": {"type": "string"}},
|
|
50
|
+
"required": ["item"],
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"type": "function",
|
|
56
|
+
"function": {
|
|
57
|
+
"name": "stock_of",
|
|
58
|
+
"description": "Units in stock. Valid: widget, gadget.",
|
|
59
|
+
"parameters": {
|
|
60
|
+
"type": "object",
|
|
61
|
+
"properties": {"item": {"type": "string"}},
|
|
62
|
+
"required": ["item"],
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def run_tool(name: str, args: dict) -> str:
|
|
70
|
+
if name == "price_of":
|
|
71
|
+
return str(_PRICE[args["item"].lower().strip()])
|
|
72
|
+
if name == "stock_of":
|
|
73
|
+
return str(_STOCK[args["item"].lower().strip()])
|
|
74
|
+
raise LookupError(f"unknown tool {name!r}")
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def turn(messages: list) -> object:
|
|
78
|
+
"""One llm call, bracketed by the model_request/model_response pair."""
|
|
79
|
+
failproofai_sdk.event.model_request(
|
|
80
|
+
model=model(),
|
|
81
|
+
messages=[{"role": m.get("role"), "content": str(m.get("content"))[:200]}
|
|
82
|
+
for m in messages],
|
|
83
|
+
)
|
|
84
|
+
reply = client.chat.completions.create(
|
|
85
|
+
model=model(), messages=messages, tools=TOOLS
|
|
86
|
+
)
|
|
87
|
+
usage = reply.usage
|
|
88
|
+
failproofai_sdk.event.model_response(
|
|
89
|
+
model=model(),
|
|
90
|
+
content=reply.choices[0].message.content or "",
|
|
91
|
+
input_tokens=getattr(usage, "prompt_tokens", None),
|
|
92
|
+
output_tokens=getattr(usage, "completion_tokens", None),
|
|
93
|
+
)
|
|
94
|
+
return reply.choices[0].message
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def main() -> None:
|
|
98
|
+
banner("manual research agent", "no framework · hand-instrumented loop")
|
|
99
|
+
|
|
100
|
+
messages = [
|
|
101
|
+
{"role": "system", "content": "Use the tools for every number. Be terse."},
|
|
102
|
+
{"role": "user", "content": "Price and stock for widget and gadget?"},
|
|
103
|
+
]
|
|
104
|
+
|
|
105
|
+
with failproofai_sdk.session() as sid:
|
|
106
|
+
with failproofai_sdk.agent("inventory", goal="price and stock report"):
|
|
107
|
+
for _ in range(4): # bounded: an unbounded agent loop is its own bug
|
|
108
|
+
message = turn(messages)
|
|
109
|
+
calls = message.tool_calls or []
|
|
110
|
+
if not calls:
|
|
111
|
+
print(" answer:", (message.content or "").strip()[:200], "\n")
|
|
112
|
+
break
|
|
113
|
+
|
|
114
|
+
messages.append(message.model_dump(exclude_none=True))
|
|
115
|
+
for call in calls:
|
|
116
|
+
args = json.loads(call.function.arguments or "{}")
|
|
117
|
+
# tool_call() emits tool_use now and tool_result on exit,
|
|
118
|
+
# turning a raised exception into `error` on the result.
|
|
119
|
+
with failproofai_sdk.tool_call(
|
|
120
|
+
call.function.name, tool_call_id=call.id, input=args
|
|
121
|
+
) as handle:
|
|
122
|
+
handle.output = run_tool(call.function.name, args)
|
|
123
|
+
messages.append({
|
|
124
|
+
"role": "tool",
|
|
125
|
+
"tool_call_id": call.id,
|
|
126
|
+
"content": str(handle.output),
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
trace(sid, title="manual research agent")
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
if __name__ == "__main__":
|
|
133
|
+
main()
|