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,249 @@
|
|
|
1
|
+
# failproofai-sdk — integration guide
|
|
2
|
+
|
|
3
|
+
Plug your agent into Failproof AI. One call, no call-site changes, no ids
|
|
4
|
+
threaded through your code.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
pip install 'failproofai-sdk[langgraph]'
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
```python
|
|
11
|
+
import failproofai_sdk
|
|
12
|
+
|
|
13
|
+
failproofai_sdk.instrument() # auto-detects the frameworks you imported
|
|
14
|
+
|
|
15
|
+
with failproofai_sdk.session():
|
|
16
|
+
graph.invoke(...) # recorded
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
That is the whole integration.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## pick your framework
|
|
24
|
+
|
|
25
|
+
| framework | guide | runnable code |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| LangChain / LangGraph | [langgraph/](langgraph/) | [langgraph/examples/](langgraph/examples/) |
|
|
28
|
+
| CrewAI | [crewai/](crewai/) | [crewai/examples/](crewai/examples/) |
|
|
29
|
+
| LlamaIndex | [llama_index/](llama_index/) | [llama_index/examples/](llama_index/examples/) |
|
|
30
|
+
| Pydantic AI | [pydantic_ai/](pydantic_ai/) | [pydantic_ai/examples/](pydantic_ai/examples/) |
|
|
31
|
+
| **no framework** (your own agent) | [manual/](manual/) | [manual/examples/](manual/examples/) |
|
|
32
|
+
|
|
33
|
+
Using something else — AutoGen, Haystack, Semantic Kernel, your own loop? Read
|
|
34
|
+
[manual/](manual/). It is the same fidelity, it just costs you the call sites,
|
|
35
|
+
and it explains why AutoGen has no adapter.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## what you get
|
|
40
|
+
|
|
41
|
+
Here is a real trace, printed by `langgraph/examples/quickstart.py`. This is
|
|
42
|
+
captured output, not an illustration:
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
━━ failproof_ai · langgraph quickstart
|
|
46
|
+
session faf3a02d64464e34809eae95fa244230
|
|
47
|
+
events 14 · agents 1 · types 8
|
|
48
|
+
|
|
49
|
+
№ offset event detail
|
|
50
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
51
|
+
1 +0.000s agent_start LangGraph
|
|
52
|
+
2 +0.001s hook_triggered agent
|
|
53
|
+
3 +0.002s model_request gpt-5.6-terra
|
|
54
|
+
4 +3.023s model_response gpt-5.6-terra · 21 out-tok
|
|
55
|
+
5 +3.024s hook_completed agent
|
|
56
|
+
6 +3.024s hook_triggered tools
|
|
57
|
+
7 +3.025s tool_use word_count
|
|
58
|
+
8 +3.025s tool_result word_count · ok
|
|
59
|
+
9 +3.025s hook_completed tools
|
|
60
|
+
10 +3.026s hook_triggered agent
|
|
61
|
+
11 +3.027s model_request gpt-5.6-terra
|
|
62
|
+
12 +5.717s model_response gpt-5.6-terra · 5 out-tok
|
|
63
|
+
13 +5.720s hook_completed agent
|
|
64
|
+
14 +5.721s agent_end LangGraph · success
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
One `graph.invoke()` from the outside. Fourteen events with timings, token
|
|
68
|
+
counts and the tool call, from the inside.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## the three calls
|
|
73
|
+
|
|
74
|
+
### 1. `configure()` — optional
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
failproofai_sdk.configure(
|
|
78
|
+
environment="production", # label on every event; default "dev"
|
|
79
|
+
flush_interval=0.5, # seconds between disk flushes
|
|
80
|
+
base_dir=None, # spool root; default ~/.failproofai/custom-agents
|
|
81
|
+
)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Defaults are usually right. Set `environment` so you can tell prod from staging
|
|
85
|
+
on the dashboard.
|
|
86
|
+
|
|
87
|
+
### 2. `instrument()` — the one that does the work
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
failproofai_sdk.instrument() # every framework already imported
|
|
91
|
+
failproofai_sdk.instrument("crewai") # exactly one
|
|
92
|
+
failproofai_sdk.uninstrument() # put everything back
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Auto-detection reads `sys.modules` — a framework you have installed but are not
|
|
96
|
+
using is never imported on your behalf.
|
|
97
|
+
|
|
98
|
+
### 3. `session()` — group one run
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
with failproofai_sdk.session():
|
|
102
|
+
...
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
A session is one run. Without it, each top-level call becomes its own session,
|
|
106
|
+
which is almost never what you want.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## the fifteen event types
|
|
111
|
+
|
|
112
|
+
| group | events | what they mean |
|
|
113
|
+
|---|---|---|
|
|
114
|
+
| agents | `agent_start` `agent_end` | a unit of work begins / ends |
|
|
115
|
+
| | `agent_pause` `agent_resume` | it is blocked / unblocked (feeds paused time) |
|
|
116
|
+
| models | `model_request` `model_response` | one LLM round trip, with tokens |
|
|
117
|
+
| tools | `tool_use` `tool_result` | one tool call, with args and output |
|
|
118
|
+
| hooks | `hook_triggered` `hook_completed` | a node / step / task boundary |
|
|
119
|
+
| humans | `human_wait` `human_input` | you asked a person / they answered |
|
|
120
|
+
| | `human_pause` `human_interrupt` | a person paused / stopped the agent |
|
|
121
|
+
| failures | `error` | something went wrong |
|
|
122
|
+
|
|
123
|
+
**Events come in pairs.** The closing event carries a `duration_ms` measured
|
|
124
|
+
from the matching opening one. An opening event with no close renders as a span
|
|
125
|
+
that never finishes.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## what each framework emits
|
|
130
|
+
|
|
131
|
+
Measured from the real runs in this directory, not declared.
|
|
132
|
+
|
|
133
|
+
| event | langgraph | crewai | llama_index | pydantic ai | your own |
|
|
134
|
+
|---|:--:|:--:|:--:|:--:|:--:|
|
|
135
|
+
| `agent_start` / `agent_end` | yes | yes | yes | yes | you |
|
|
136
|
+
| `model_request` / `model_response` | yes | yes | yes | yes | you |
|
|
137
|
+
| `tool_use` / `tool_result` | yes | yes | yes | yes | you |
|
|
138
|
+
| `hook_triggered` / `hook_completed` | node | task | step | — | you |
|
|
139
|
+
| `error` | yes | yes | yes | yes | automatic |
|
|
140
|
+
| `human_wait` / `human_input` | yes | yes | yes | — | you |
|
|
141
|
+
| `agent_pause` / `agent_resume` | yes | yes | yes | — | you |
|
|
142
|
+
| `human_pause` / `human_interrupt` | — | — | — | — | you |
|
|
143
|
+
|
|
144
|
+
A dash means the framework has no such concept, not that it is missing.
|
|
145
|
+
Pydantic AI has no node boundary and no built-in human pause, so there is
|
|
146
|
+
nothing to map. `human_pause` and `human_interrupt` describe a *person* acting
|
|
147
|
+
on the agent — a stop button — which no framework signals; emit those yourself.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## running the examples
|
|
152
|
+
|
|
153
|
+
Every example in this tree was executed against a live model before it shipped.
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
pip install 'failproofai-sdk[langgraph]'
|
|
157
|
+
export OPENAI_API_KEY=sk-...
|
|
158
|
+
export FPAI_MODEL=gpt-4o-mini # optional, this is the default
|
|
159
|
+
|
|
160
|
+
python docs/langgraph/examples/quickstart.py
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Each one prints the event stream it produced when it finishes. That printer
|
|
164
|
+
lives in [`_shared/`](_shared/) and is **cosmetics only** — the two bootstrap
|
|
165
|
+
lines at the top of each example exist just to import it. Delete them and the
|
|
166
|
+
example still instruments correctly.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## instrumentation cannot break your agent
|
|
171
|
+
|
|
172
|
+
Every callback goes through a wrapper whose only job is to re-raise. Your call
|
|
173
|
+
sits in exactly one `try`; everything the SDK does happens outside it.
|
|
174
|
+
|
|
175
|
+
- a hook that raises is logged once, with its traceback, and your call is
|
|
176
|
+
unaffected;
|
|
177
|
+
- a hook that raises three times at the same site is disabled for the rest of
|
|
178
|
+
the process, with one error line saying so.
|
|
179
|
+
|
|
180
|
+
That firewall is the right default in production and the wrong one when you are
|
|
181
|
+
debugging. To make failures loud instead:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
export FAILPROOFAI_SDK_STRICT=1
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Without it you can only ever prove "it did not crash", never "it swallowed the
|
|
188
|
+
right thing".
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## zero dependencies
|
|
193
|
+
|
|
194
|
+
`import failproofai_sdk` pulls in nothing outside the standard library. That is
|
|
195
|
+
enforced, not asserted: one test installs the built wheel with `--no-deps`,
|
|
196
|
+
another launches a fresh interpreter and proves no framework reaches
|
|
197
|
+
`sys.modules`.
|
|
198
|
+
|
|
199
|
+
The extras install the **framework**, not the adapter — the adapter code always
|
|
200
|
+
ships in the base wheel and is imported only when `instrument()` asks for it.
|
|
201
|
+
Most people already have the framework and never need an extra.
|
|
202
|
+
|
|
203
|
+
| extra | installs |
|
|
204
|
+
|---|---|
|
|
205
|
+
| `failproofai-sdk[langchain]` | `langchain-core>=1.4.7,<2` |
|
|
206
|
+
| `failproofai-sdk[langgraph]` | `langgraph>=1.2,<2` |
|
|
207
|
+
| `failproofai-sdk[crewai]` | `crewai>=1.13,<2` |
|
|
208
|
+
| `failproofai-sdk[llamaindex]` | `llama-index-core>=0.14.23,<0.15` |
|
|
209
|
+
| `failproofai-sdk[pydantic-ai]` | `pydantic-ai-slim>=2.0,<3` |
|
|
210
|
+
|
|
211
|
+
There is deliberately no `[all]` — an extra that installs four agent frameworks
|
|
212
|
+
at once is a resolver problem handed to somebody who wanted a telemetry library.
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## verifying it works
|
|
217
|
+
|
|
218
|
+
Look at the dashboard, or query the store.
|
|
219
|
+
|
|
220
|
+
**Do not read the spool directory to check.** When `failproofaid` is running it
|
|
221
|
+
collects and deletes each batch file within milliseconds of it appearing, so a
|
|
222
|
+
read races the collector and returns only what has not shipped yet — which looks
|
|
223
|
+
exactly like an adapter that emitted nothing but its closing events. This is a
|
|
224
|
+
real thing that happened while writing these docs.
|
|
225
|
+
|
|
226
|
+
To inspect events in-process instead, tap the writer:
|
|
227
|
+
|
|
228
|
+
```python
|
|
229
|
+
captured = []
|
|
230
|
+
_original = failproofai_sdk._writer.submit
|
|
231
|
+
failproofai_sdk._writer.submit = lambda e: (captured.append(e), _original(e))[1]
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Every example here does exactly that.
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## troubleshooting
|
|
239
|
+
|
|
240
|
+
| symptom | most likely cause |
|
|
241
|
+
|---|---|
|
|
242
|
+
| no events at all | `instrument()` never ran, or ran after you built the agent (Pydantic AI) |
|
|
243
|
+
| events, but no session | no `with failproofai_sdk.session():` — each call became its own session |
|
|
244
|
+
| `TypeError: ... missing session_id` | you emitted from a new thread; wrap it in `failproofai_sdk.propagate()` |
|
|
245
|
+
| spans that never finish | an opening event with no closing one — emit the pairs |
|
|
246
|
+
| null token counts on LlamaIndex | streaming has no usage; see [llama_index/](llama_index/) |
|
|
247
|
+
| `agent_id` full of uuids | keep it low-cardinality — a role or node name, never a run id |
|
|
248
|
+
| duplicated events on LangChain | you registered a second callback handler as well as `instrument()` |
|
|
249
|
+
| adapter seems to do nothing | set `FAILPROOFAI_SDK_STRICT=1` and run again |
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# _shared
|
|
2
|
+
|
|
3
|
+
Cosmetics for the runnable examples. **Nothing here is part of the SDK**, and no
|
|
4
|
+
example needs it to instrument correctly.
|
|
5
|
+
|
|
6
|
+
Two helpers:
|
|
7
|
+
|
|
8
|
+
- `model()` — reads `FPAI_MODEL` / `MODEL`, defaults to `gpt-4o-mini`, so one
|
|
9
|
+
export drives every example.
|
|
10
|
+
- `trace(session_id)` — prints the event stream the run produced.
|
|
11
|
+
|
|
12
|
+
`trace()` is why the examples are worth running rather than reading. An adapter
|
|
13
|
+
that "works" is one whose event stream you can see, so every example ends by
|
|
14
|
+
printing its own instead of asserting in a comment that events happened.
|
|
15
|
+
|
|
16
|
+
## why it taps the writer instead of reading the spool
|
|
17
|
+
|
|
18
|
+
When `failproofaid` is running it collects and **deletes** each batch file
|
|
19
|
+
within milliseconds of it appearing. A spool read therefore races the collector
|
|
20
|
+
and returns only whatever has not shipped yet — which looks exactly like an
|
|
21
|
+
adapter that emitted nothing but its closing events.
|
|
22
|
+
|
|
23
|
+
That is not hypothetical: it is what happened the first time these examples were
|
|
24
|
+
run, and it read as three adapter bugs that did not exist.
|
|
25
|
+
|
|
26
|
+
So `capture()` wraps `failproofai_sdk._writer.submit` and appends every entry to
|
|
27
|
+
a list first. Same dict that goes to disk, race-free, and it works whether or not
|
|
28
|
+
a daemon is running. `banner()` calls it, so every example is tapped from its
|
|
29
|
+
first line.
|
|
30
|
+
|
|
31
|
+
## removing it
|
|
32
|
+
|
|
33
|
+
Each example starts with two bootstrap lines that exist only to import this
|
|
34
|
+
package:
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
|
|
38
|
+
...
|
|
39
|
+
from _shared import banner, model, trace
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Delete those and the `banner()` / `trace()` calls, and the example still
|
|
43
|
+
instruments correctly. It just stops printing.
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"""Cosmetics shared by the examples. No SDK behaviour lives here.
|
|
2
|
+
|
|
3
|
+
Two helpers, both deliberately boring:
|
|
4
|
+
|
|
5
|
+
* `model()` — the model id, from `FPAI_MODEL` / `MODEL`, so one export drives
|
|
6
|
+
every example instead of a dozen edits.
|
|
7
|
+
* `trace()` — reads the spool back and prints what the run actually recorded.
|
|
8
|
+
|
|
9
|
+
`trace()` is the point of these examples. An adapter that "works" is one whose
|
|
10
|
+
event stream you can read, so every example ends by printing its own trace
|
|
11
|
+
rather than asserting in a comment that events were produced. It reads the same
|
|
12
|
+
JSONL the daemon collects, filtered to the session just run.
|
|
13
|
+
|
|
14
|
+
Nothing here is required to use the SDK. Delete this folder and the examples
|
|
15
|
+
still instrument correctly; they just stop printing.
|
|
16
|
+
"""
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import json
|
|
20
|
+
import os
|
|
21
|
+
import pathlib
|
|
22
|
+
import sys
|
|
23
|
+
|
|
24
|
+
import failproofai_sdk
|
|
25
|
+
|
|
26
|
+
# ── brand ────────────────────────────────────────────────────────────────────
|
|
27
|
+
# Exact hex from the design system: pink #e4587d, mint #66d1b5, ink #d8d6d2.
|
|
28
|
+
# Truecolor, and only when stdout is a terminal — a piped log gets clean text.
|
|
29
|
+
_TTY = sys.stdout.isatty()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _c(code: str, text: str) -> str:
|
|
33
|
+
return f"\033[{code}m{text}\033[0m" if _TTY else text
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def pink(t: str) -> str:
|
|
37
|
+
return _c("38;2;228;88;125", t)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def mint(t: str) -> str:
|
|
41
|
+
return _c("38;2;102;209;181", t)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def dim(t: str) -> str:
|
|
45
|
+
return _c("38;2;120;120;130", t)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def bold(t: str) -> str:
|
|
49
|
+
return _c("1", t)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
RULE = "━" * 68
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def model() -> str:
|
|
56
|
+
"""The model id every example runs against."""
|
|
57
|
+
return os.environ.get("FPAI_MODEL") or os.environ.get("MODEL") or "gpt-4o-mini"
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def banner(title: str, subtitle: str = "") -> None:
|
|
61
|
+
"""Print the example's header and start capturing events."""
|
|
62
|
+
capture()
|
|
63
|
+
print()
|
|
64
|
+
print(pink("━━ ") + bold(title.lower()))
|
|
65
|
+
if subtitle:
|
|
66
|
+
print(dim(" " + subtitle))
|
|
67
|
+
print()
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
# ── capturing what the run emitted ───────────────────────────────────────────
|
|
71
|
+
# NOT by reading the spool. When `failproofaid` is running it collects and
|
|
72
|
+
# DELETES each batch file within milliseconds of it appearing, so a spool read
|
|
73
|
+
# races the daemon and returns whatever happens to be left — which looks exactly
|
|
74
|
+
# like an adapter that only emitted its closing events. (That is a real thing
|
|
75
|
+
# that happened while writing these examples.)
|
|
76
|
+
#
|
|
77
|
+
# So the tap sits on the writer instead: the same dict that goes to disk is
|
|
78
|
+
# appended to a list first. Race-free, and it works whether or not a daemon is
|
|
79
|
+
# running.
|
|
80
|
+
_CAPTURED: list[dict] = []
|
|
81
|
+
_TAPPED = False
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def capture() -> None:
|
|
85
|
+
"""Start recording every event this process emits. Idempotent."""
|
|
86
|
+
global _TAPPED
|
|
87
|
+
if _TAPPED:
|
|
88
|
+
return
|
|
89
|
+
writer = failproofai_sdk._writer
|
|
90
|
+
original = writer.submit
|
|
91
|
+
|
|
92
|
+
def _tee(entry: dict) -> None:
|
|
93
|
+
_CAPTURED.append(entry)
|
|
94
|
+
return original(entry)
|
|
95
|
+
|
|
96
|
+
writer.submit = _tee # instance attribute; the real method is untouched
|
|
97
|
+
_TAPPED = True
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def events(session_id: str | None = None) -> list[dict]:
|
|
101
|
+
"""Everything captured, optionally narrowed to one session."""
|
|
102
|
+
rows = [r for r in _CAPTURED if session_id is None or r.get("session_id") == session_id]
|
|
103
|
+
return sorted(rows, key=lambda r: r.get("timestamp", ""))
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
_LEAF = {
|
|
107
|
+
"tool_use": "tool_result",
|
|
108
|
+
"model_request": "model_response",
|
|
109
|
+
"hook_triggered": "hook_completed",
|
|
110
|
+
"agent_start": "agent_end",
|
|
111
|
+
"human_wait": "human_input",
|
|
112
|
+
"agent_pause": "agent_resume",
|
|
113
|
+
}
|
|
114
|
+
_CLOSERS = set(_LEAF.values())
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _detail(row: dict) -> str:
|
|
118
|
+
t = row["type"]
|
|
119
|
+
if t in ("tool_use", "tool_result"):
|
|
120
|
+
bits = [row.get("tool_name") or "?"]
|
|
121
|
+
if row.get("error"):
|
|
122
|
+
bits.append(pink("error"))
|
|
123
|
+
elif t == "tool_result":
|
|
124
|
+
bits.append(mint("ok"))
|
|
125
|
+
return " · ".join(bits)
|
|
126
|
+
if t in ("model_request", "model_response"):
|
|
127
|
+
bits = [row.get("model") or "?"]
|
|
128
|
+
tok = row.get("output_tokens")
|
|
129
|
+
if tok:
|
|
130
|
+
bits.append(f"{tok} out-tok")
|
|
131
|
+
if row.get("error"):
|
|
132
|
+
bits.append(pink("error"))
|
|
133
|
+
return " · ".join(bits)
|
|
134
|
+
if t in ("agent_start", "agent_end"):
|
|
135
|
+
bits = [row.get("agent_id") or "?"]
|
|
136
|
+
if row.get("parent_id"):
|
|
137
|
+
bits.append(dim("under " + row["parent_id"]))
|
|
138
|
+
if row.get("outcome"):
|
|
139
|
+
good = row["outcome"] == "success"
|
|
140
|
+
bits.append((mint if good else pink)(row["outcome"]))
|
|
141
|
+
return " · ".join(bits)
|
|
142
|
+
if t in ("hook_triggered", "hook_completed"):
|
|
143
|
+
return " · ".join(x for x in (row.get("hook_name"), row.get("status")) if x)
|
|
144
|
+
if t == "error":
|
|
145
|
+
return pink(str(row.get("message", ""))[:48])
|
|
146
|
+
for key in ("prompt", "reason", "response", "summary", "goal"):
|
|
147
|
+
if row.get(key):
|
|
148
|
+
return dim(str(row[key])[:48])
|
|
149
|
+
return ""
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def trace(session_id: str, *, title: str = "trace") -> list[dict]:
|
|
153
|
+
"""Print the event stream this run produced. Returns the rows."""
|
|
154
|
+
rows = events(session_id)
|
|
155
|
+
if not rows:
|
|
156
|
+
print(pink(" no events — is the spool configured?"))
|
|
157
|
+
return rows
|
|
158
|
+
|
|
159
|
+
kinds = sorted({r["type"] for r in rows})
|
|
160
|
+
agents = sorted({r.get("agent_id") for r in rows if r.get("agent_id")})
|
|
161
|
+
t0 = rows[0]["timestamp"]
|
|
162
|
+
|
|
163
|
+
print(pink("━━ ") + bold(f"failproof_ai · {title}"))
|
|
164
|
+
print(dim(f" session {session_id}"))
|
|
165
|
+
print(dim(f" events {len(rows)} · agents {len(agents)} · types {len(kinds)}"))
|
|
166
|
+
print()
|
|
167
|
+
print(dim(f" {'№':>3} {'offset':>8} {'event':<16} detail"))
|
|
168
|
+
print(dim(" " + RULE))
|
|
169
|
+
|
|
170
|
+
depth = 0
|
|
171
|
+
for i, row in enumerate(rows, 1):
|
|
172
|
+
t = row["type"]
|
|
173
|
+
if t in _CLOSERS:
|
|
174
|
+
depth = max(depth - 1, 0)
|
|
175
|
+
indent = " " * depth
|
|
176
|
+
offset = _offset(t0, row["timestamp"])
|
|
177
|
+
name = f"{indent}{t}"
|
|
178
|
+
print(f" {i:>3} {dim(offset):>8} {name:<16} {_detail(row)}")
|
|
179
|
+
if t in _LEAF:
|
|
180
|
+
depth += 1
|
|
181
|
+
print(dim(" " + RULE))
|
|
182
|
+
print(dim(" " + " ".join(kinds)))
|
|
183
|
+
print()
|
|
184
|
+
return rows
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _offset(first: str, ts: str) -> str:
|
|
188
|
+
from datetime import datetime
|
|
189
|
+
|
|
190
|
+
try:
|
|
191
|
+
a = datetime.fromisoformat(first.replace("Z", "+00:00"))
|
|
192
|
+
b = datetime.fromisoformat(ts.replace("Z", "+00:00"))
|
|
193
|
+
return f"+{(b - a).total_seconds():.3f}s"
|
|
194
|
+
except Exception:
|
|
195
|
+
return ""
|