failproofai 1.0.7-beta.1 → 1.0.7
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 +4 -4
- 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 +4 -4
- 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 +4 -4
- 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.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route.js +7 -8
- 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.nft.json +1 -1
- 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.nft.json +1 -1
- 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 +5 -7
- 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 +6 -6
- 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 +14 -14
- package/.next/standalone/.next/server/app/policies/page.js +11 -13
- 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 +7 -8
- 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 +7 -7
- 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 +6 -7
- 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 +8 -41
- package/.next/standalone/.next/server/app/settings/page.js +9 -12
- 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]__1j-zsg5._.js → [externals]__1_bftcl._.js} +1 -1
- package/.next/standalone/.next/server/chunks/{[externals]__19_pzeq._.js → [externals]__1msfs-h._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1bf34x4._.js → [root-of-the-server]__1_r2rbg._.js} +7 -5
- package/.next/standalone/.next/server/chunks/_09dz7xv._.js +21 -21
- package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
- package/.next/standalone/.next/server/chunks/{_1q5i8mb._.js → _1c3k-8x._.js} +2 -2
- package/.next/standalone/.next/server/chunks/_1ek68ln._.js +16 -16
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_09z9-p7._.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_0iu54mz._.js +3 -0
- package/.next/standalone/.next/server/chunks/src_hooks_custom-hooks-loader_ts_0lnb3n3._.js +2 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0-_ki57._.js +4 -0
- 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]__0yxwl6j._.js → [root-of-the-server]__0bd3mje._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0cg-bgc._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0cpu_mj._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1mf3zp6._.js → [root-of-the-server]__0cxe_2_._.js} +3 -3
- 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]__0p-5p8u._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0u3w0ll._.js +22 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__17d_ffl._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__19d9tgz._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ctpynv._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1jiwfsj._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1p2otjt._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1phc187._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_06imw3p._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_1w_5l7t._.js → _0h_douw._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_214wgrp._.js → _1-i_gzc._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{_0bn2oo8._.js → _166t73i._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_1q46vxx._.js → _1_qswah._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{_1gb0ifp._.js → _1es2j7i._.js} +5 -5
- package/.next/standalone/.next/server/chunks/ssr/_1u8-lu2._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
- 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 +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{node_modules_next_dist_18_d8l1._.js → node_modules_next_dist_0drixxt._.js} +4 -4
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_1cv9_c4._.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/chunks/ssr/src_hooks_pack-cli_ts_0t7me65._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- 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 +23 -56
- package/.next/standalone/.next/static/chunks/094xgi4owxaqf.js +1 -0
- package/.next/standalone/.next/static/chunks/0__8a7m868fvf.js +1 -0
- package/.next/standalone/.next/static/chunks/{12tvm75t5ffui.js → 0o6qlkgubtoex.js} +1 -1
- package/.next/standalone/.next/static/chunks/13i7-9is-vhys.js +1 -0
- package/.next/standalone/.next/static/chunks/1rz20_pz828f3.js +6 -0
- package/.next/standalone/.next/static/chunks/2k9f4tyv04809.css +1 -0
- package/.next/standalone/.next/static/chunks/{0vmd180qfntfb.js → 2klitrtzpaoe0.js} +1 -1
- package/.next/standalone/.next/static/chunks/{258668t68du6b.js → 2mdh397ghgnvv.js} +1 -1
- package/.next/standalone/.next/static/chunks/2rshywgeqsyzk.css +2 -0
- package/.next/standalone/.next/static/chunks/3pzx4chkhko9k.js +1 -0
- package/.next/standalone/.next/static/chunks/{0qrbdkv9qmvli.js → 3rh5o7e16irrm.js} +1 -1
- package/.next/standalone/.next/static/chunks/{29fql3nbnfc9q.js → 43ufqrz8qo3h-.js} +1 -1
- package/.next/standalone/SECURITY.md +53 -0
- package/.next/standalone/app/actions/pack-actions.ts +0 -12
- package/.next/standalone/app/policies/hooks-client.tsx +0 -9
- package/.next/standalone/app/settings/page.tsx +1 -20
- package/.next/standalone/app/settings/settings-client.tsx +1 -27
- package/.next/standalone/app/settings/settings.css +0 -79
- package/.next/standalone/package.json +9 -9
- package/.next/standalone/sdk/python/skill/SKILL.md +60 -14
- package/.next/standalone/sdk/python/skill/agents/openai.yaml +2 -1
- package/.next/standalone/sdk/python/skill/references/evaluator.md +255 -0
- package/.next/standalone/sdk/python/skill/references/events.md +17 -8
- package/.next/standalone/sdk/python/skill/references/frameworks.md +3 -0
- package/.next/standalone/sdk/python/skill/references/install.md +3 -0
- package/.next/standalone/sdk/python/skill/references/integration.md +6 -2
- package/.next/standalone/sdk/python/skill/references/typescript.md +568 -0
- package/.next/standalone/sdk/typescript/CHANGELOG.md +133 -0
- package/.next/standalone/sdk/typescript/LICENSE +42 -0
- package/.next/standalone/sdk/typescript/README.md +552 -0
- package/.next/standalone/sdk/typescript/eslint.config.mjs +59 -0
- package/.next/standalone/sdk/typescript/examples/research-agent.ts +197 -0
- package/.next/standalone/sdk/typescript/integration/ai.test.ts +920 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/agent.ts +337 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/package-lock.json +261 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/package.json +16 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/surfaces.ts +605 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/tsconfig.json +12 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-4/tsconfig.surfaces.json +4 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/agent.ts +342 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/package-lock.json +156 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/package.json +16 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/surfaces.ts +628 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/tsconfig.json +12 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-5/tsconfig.surfaces.json +4 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/agent.ts +346 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/package-lock.json +156 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/package.json +13 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/surfaces.ts +651 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/tsconfig.json +12 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-6/tsconfig.surfaces.json +4 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/agent.ts +350 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/package-lock.json +153 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/package.json +13 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/surfaces.ts +651 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/tsconfig.json +12 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/ai-7/tsconfig.surfaces.json +4 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-0.3/agent.ts +623 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-0.3/package-lock.json +344 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-0.3/package.json +19 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-0.3/tsconfig.json +12 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/agent-v1.ts +99 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/agent.ts +623 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/package-lock.json +336 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/package.json +15 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-1/tsconfig.json +12 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/agent.ts +96 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/package-lock.json +441 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/package.json +19 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/tsconfig.json +12 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/vendor/lc-weather-provider/index.cjs +53 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/vendor/lc-weather-provider/index.mjs +55 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/langchain-dup-core/vendor/lc-weather-provider/package.json +18 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/agent.ts +659 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/package-lock.json +635 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/package.json +15 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.11/tsconfig.json +12 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/agent.ts +659 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/package-lock.json +553 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/package.json +15 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/llamaindex-0.12/tsconfig.json +12 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/agent.ts +877 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/mcp-server.mjs +66 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/package-lock.json +6797 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/package.json +24 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-0/tsconfig.json +12 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/agent.ts +872 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/mcp-server.mjs +66 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/package-lock.json +2540 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/package.json +15 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/mastra-1/tsconfig.json +12 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/actions.ts +18 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/ai/route.ts +42 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/edge/route.ts +29 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/langgraph/route.ts +21 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/llamaindex/route.ts +11 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/mastra/route.ts +19 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/api/status/route.ts +7 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/layout.tsx +9 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/app/page.tsx +15 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/instrumentation.ts +15 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/lib/ai.ts +61 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/lib/langgraph.ts +68 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/lib/llamaindex.ts +98 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/lib/mastra.ts +90 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/next.config.ts +52 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package-lock.json +4343 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/nextjs/package.json +28 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/agent.ts +51 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/deno-npm.ts +76 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/package-lock.json +484 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/runtimes/package.json +15 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/types/agent.ts +79 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/types/package-lock.json +740 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/types/package.json +11 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/vanilla/agent.ts +197 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/vanilla/package-lock.json +70 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/vanilla/package.json +12 -0
- package/.next/standalone/sdk/typescript/integration/fixtures/vanilla/tsconfig.json +12 -0
- package/.next/standalone/sdk/typescript/integration/global-setup.ts +29 -0
- package/.next/standalone/sdk/typescript/integration/harness.ts +451 -0
- package/.next/standalone/sdk/typescript/integration/langchain.test.ts +682 -0
- package/.next/standalone/sdk/typescript/integration/llamaindex.test.ts +709 -0
- package/.next/standalone/sdk/typescript/integration/mastra-coverage.test.ts +386 -0
- package/.next/standalone/sdk/typescript/integration/mastra.test.ts +311 -0
- package/.next/standalone/sdk/typescript/integration/nextjs.test.ts +341 -0
- package/.next/standalone/sdk/typescript/integration/runtime-parity.ts +180 -0
- package/.next/standalone/sdk/typescript/integration/runtimes.bun.test.ts +15 -0
- package/.next/standalone/sdk/typescript/integration/runtimes.core.test.ts +113 -0
- package/.next/standalone/sdk/typescript/integration/runtimes.deno.test.ts +19 -0
- package/.next/standalone/sdk/typescript/integration/types.test.ts +141 -0
- package/.next/standalone/sdk/typescript/integration/vanilla.test.ts +255 -0
- package/.next/standalone/sdk/typescript/package-lock.json +2640 -0
- package/.next/standalone/sdk/typescript/package.json +401 -0
- package/.next/standalone/sdk/typescript/scripts/finalize-build.mjs +123 -0
- package/.next/standalone/sdk/typescript/scripts/release.mjs +177 -0
- package/.next/standalone/sdk/typescript/src/clock.ts +58 -0
- package/.next/standalone/sdk/typescript/src/context.ts +214 -0
- package/.next/standalone/sdk/typescript/src/edge/adapter.ts +18 -0
- package/.next/standalone/sdk/typescript/src/edge/ai.ts +116 -0
- package/.next/standalone/sdk/typescript/src/edge/index.ts +238 -0
- package/.next/standalone/sdk/typescript/src/edge/langchain.ts +18 -0
- package/.next/standalone/sdk/typescript/src/edge/llamaindex.ts +12 -0
- package/.next/standalone/sdk/typescript/src/edge/mastra.ts +17 -0
- package/.next/standalone/sdk/typescript/src/edge/notice.ts +33 -0
- package/.next/standalone/sdk/typescript/src/environment.ts +75 -0
- package/.next/standalone/sdk/typescript/src/evaluator/authoring.ts +480 -0
- package/.next/standalone/sdk/typescript/src/evaluator/cli.ts +96 -0
- package/.next/standalone/sdk/typescript/src/evaluator/client.ts +421 -0
- package/.next/standalone/sdk/typescript/src/evaluator/expression.ts +1292 -0
- package/.next/standalone/sdk/typescript/src/evaluator/index.ts +144 -0
- package/.next/standalone/sdk/typescript/src/evaluator/protocol.ts +747 -0
- package/.next/standalone/sdk/typescript/src/evaluator/runtime.ts +930 -0
- package/.next/standalone/sdk/typescript/src/evaluator/sandbox-worker.ts +171 -0
- package/.next/standalone/sdk/typescript/src/evaluator/source-limits.ts +27 -0
- package/.next/standalone/sdk/typescript/src/evaluator/source.ts +509 -0
- package/.next/standalone/sdk/typescript/src/events.ts +879 -0
- package/.next/standalone/sdk/typescript/src/exit.ts +117 -0
- package/.next/standalone/sdk/typescript/src/index.ts +186 -0
- package/.next/standalone/sdk/typescript/src/integrations/ai.ts +1566 -0
- package/.next/standalone/sdk/typescript/src/integrations/compat.ts +322 -0
- package/.next/standalone/sdk/typescript/src/integrations/core.ts +1321 -0
- package/.next/standalone/sdk/typescript/src/integrations/index.ts +355 -0
- package/.next/standalone/sdk/typescript/src/integrations/langchain.ts +2340 -0
- package/.next/standalone/sdk/typescript/src/integrations/llamaindex.ts +2111 -0
- package/.next/standalone/sdk/typescript/src/integrations/mastra.ts +1802 -0
- package/.next/standalone/sdk/typescript/src/logger.ts +98 -0
- package/.next/standalone/sdk/typescript/src/next.ts +115 -0
- package/.next/standalone/sdk/typescript/src/node-require.ts +446 -0
- package/.next/standalone/sdk/typescript/src/redact.ts +305 -0
- package/.next/standalone/sdk/typescript/src/resolver.ts +120 -0
- package/.next/standalone/sdk/typescript/src/runtime.ts +29 -0
- package/.next/standalone/sdk/typescript/src/schema.ts +410 -0
- package/.next/standalone/sdk/typescript/src/scopes.ts +701 -0
- package/.next/standalone/sdk/typescript/src/shared.ts +33 -0
- package/.next/standalone/sdk/typescript/src/version.ts +5 -0
- package/.next/standalone/sdk/typescript/src/writer.ts +934 -0
- package/.next/standalone/sdk/typescript/test/adapters.test.ts +397 -0
- package/.next/standalone/sdk/typescript/test/ai.test.ts +1076 -0
- package/.next/standalone/sdk/typescript/test/copies.test.ts +204 -0
- package/.next/standalone/sdk/typescript/test/edge.test.ts +183 -0
- package/.next/standalone/sdk/typescript/test/evaluator-client.test.ts +234 -0
- package/.next/standalone/sdk/typescript/test/evaluator-protocol.test.ts +225 -0
- package/.next/standalone/sdk/typescript/test/events.test.ts +193 -0
- package/.next/standalone/sdk/typescript/test/expression.test.ts +181 -0
- package/.next/standalone/sdk/typescript/test/global-setup.ts +26 -0
- package/.next/standalone/sdk/typescript/test/helpers.ts +130 -0
- package/.next/standalone/sdk/typescript/test/integrations.test.ts +369 -0
- package/.next/standalone/sdk/typescript/test/langchain-copies.test.ts +204 -0
- package/.next/standalone/sdk/typescript/test/langchain.test.ts +999 -0
- package/.next/standalone/sdk/typescript/test/llamaindex.test.ts +1760 -0
- package/.next/standalone/sdk/typescript/test/mastra-coverage.test.ts +501 -0
- package/.next/standalone/sdk/typescript/test/mastra-lifecycle.test.ts +479 -0
- package/.next/standalone/sdk/typescript/test/mastra.test.ts +285 -0
- package/.next/standalone/sdk/typescript/test/next.test.ts +109 -0
- package/.next/standalone/sdk/typescript/test/packaging.test.ts +312 -0
- package/.next/standalone/sdk/typescript/test/redaction.test.ts +171 -0
- package/.next/standalone/sdk/typescript/test/runtimes.test.ts +101 -0
- package/.next/standalone/sdk/typescript/test/sandbox.test.ts +189 -0
- package/.next/standalone/sdk/typescript/test/scopes.test.ts +271 -0
- package/.next/standalone/sdk/typescript/test/setup.ts +19 -0
- package/.next/standalone/sdk/typescript/test/skill-snippets.test.ts +73 -0
- package/.next/standalone/sdk/typescript/test/spool-contract.test.ts +124 -0
- package/.next/standalone/sdk/typescript/test/tracker-bounds.test.ts +191 -0
- package/.next/standalone/sdk/typescript/test/wire-format.test.ts +214 -0
- package/.next/standalone/sdk/typescript/test/writer.test.ts +407 -0
- package/.next/standalone/sdk/typescript/tsconfig.build.json +15 -0
- package/.next/standalone/sdk/typescript/tsconfig.cjs.json +19 -0
- package/.next/standalone/sdk/typescript/tsconfig.json +28 -0
- package/.next/standalone/sdk/typescript/vitest.config.ts +33 -0
- package/.next/standalone/sdk/typescript/vitest.integration.config.ts +23 -0
- package/.next/standalone/server.js +1 -1
- package/bin/failproofai.mjs +2 -115
- package/dist/cli.mjs +6538 -13686
- package/dist/index.js +1 -19
- package/dist/worker.mjs +2085 -8012
- package/package.json +9 -9
- package/pi-extension/index.ts +0 -11
- package/scripts/build-policy-pack.mjs +2 -39
- package/src/hooks/builtin-policies.ts +3 -21
- package/src/hooks/cloud-enrollment-cli.ts +1 -1
- package/src/hooks/cloud-managed-policies.ts +0 -22
- package/src/hooks/custom-hooks-loader.ts +7 -45
- package/src/hooks/custom-hooks-registry.ts +1 -45
- package/src/hooks/first-run-gate.ts +0 -5
- package/src/hooks/fp-home.ts +0 -23
- package/src/hooks/handler.ts +6 -265
- package/src/hooks/hook-activity-store.ts +1 -105
- package/src/hooks/hook-telemetry.ts +0 -41
- package/src/hooks/loader-utils.ts +0 -6
- package/src/hooks/pack-cli.ts +17 -278
- package/src/hooks/pack-manifest.ts +7 -479
- package/src/hooks/pack-store.ts +10 -156
- package/src/hooks/policy-catalog.ts +0 -65
- package/src/hooks/policy-evaluator.ts +796 -940
- package/src/hooks/policy-registry.ts +0 -25
- package/src/hooks/policy-types.ts +0 -126
- package/src/hooks/worker-server.ts +26 -119
- package/src/index.ts +0 -6
- package/.next/standalone/.next/server/chunks/src_hooks_01frwmb._.js +0 -5
- package/.next/standalone/.next/server/chunks/src_hooks_18qtd42._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01bmjsj._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04usis8._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__056wjo4._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__059yza8._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0eip4_k._.js +0 -22
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n0xg95._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qcb0mg._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qxnccm._.js +0 -5
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0rwtwpm._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s_yomn._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0soxz2z._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0yrsbd_._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11mayhe._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__13d-wb6._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1dinjii._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1pprgri._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1q4p5b8._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1qiz0e4._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_042cgl1._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0bqoto4._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0uyu3jf._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_1feuvhb._.js +0 -5
- package/.next/standalone/.next/server/chunks/ssr/app_actions_get-scheduled-audit_ts_0ei9sni._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/app_settings_02tf1h4._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_0w6mzq5._.js +0 -151
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_095a_79._.js +0 -5
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_15t8kqj._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_18k8rl0._.js +0 -12
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_1fm2w5z._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_1j0zy3v._.js +0 -3
- package/.next/standalone/.next/static/chunks/0cd-_8-c-m1ea.js +0 -6
- package/.next/standalone/.next/static/chunks/0uldbut9y2-e8.js +0 -1
- package/.next/standalone/.next/static/chunks/1u5zsejmgrir_.js +0 -1
- package/.next/standalone/.next/static/chunks/285spx855h_3r.css +0 -2
- package/.next/standalone/.next/static/chunks/2qv4hshejedtx.css +0 -1
- package/.next/standalone/.next/static/chunks/2vkvu9-opa_1z.js +0 -1
- package/.next/standalone/.next/static/chunks/37lhv7wa3ywt6.js +0 -1
- package/.next/standalone/app/actions/get-jev-config.ts +0 -409
- package/.next/standalone/app/actions/update-jev-config.ts +0 -420
- package/.next/standalone/app/components/jev-notices.tsx +0 -96
- package/.next/standalone/app/settings/jev-panel.tsx +0 -469
- package/src/hooks/effective-reviewers.ts +0 -79
- package/src/hooks/jev-activity.ts +0 -385
- package/src/hooks/jev-cli.ts +0 -1193
- package/src/hooks/policy-authority.ts +0 -333
- package/src/hooks/policy-reviewability.ts +0 -229
- package/src/hooks/semantic/combine.ts +0 -541
- package/src/hooks/semantic/compile.ts +0 -176
- package/src/hooks/semantic/decide.ts +0 -392
- package/src/hooks/semantic/envelope.ts +0 -1296
- package/src/hooks/semantic/evaluator.ts +0 -547
- package/src/hooks/semantic/facts.ts +0 -292
- package/src/hooks/semantic/intent.ts +0 -1190
- package/src/hooks/semantic/jev-client.ts +0 -643
- package/src/hooks/semantic/jev-config.ts +0 -594
- package/src/hooks/semantic/jev-review.ts +0 -374
- package/src/hooks/semantic/jev-stats.ts +0 -289
- package/src/hooks/semantic/jev-throttle.ts +0 -421
- package/src/hooks/semantic/pack-policies.ts +0 -251
- package/src/hooks/semantic/policies.ts +0 -596
- package/src/hooks/semantic/precondition-names.ts +0 -60
- package/src/hooks/semantic/preconditions.ts +0 -58
- package/src/hooks/semantic/redact.ts +0 -2910
- package/src/hooks/semantic/types.ts +0 -145
- package/src/hooks/semver-precedence.ts +0 -128
- /package/.next/standalone/.next/static/{T8YAYM9h_64fKv705vug7 → PgeWCHmyVbjRznv2VO7KF}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{T8YAYM9h_64fKv705vug7 → PgeWCHmyVbjRznv2VO7KF}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{T8YAYM9h_64fKv705vug7 → PgeWCHmyVbjRznv2VO7KF}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,568 @@
|
|
|
1
|
+
# TypeScript and JavaScript agents — `@failproofai/sdk`
|
|
2
|
+
|
|
3
|
+
Everything in `SKILL.md` §2 (plan) and §6 (production) applies unchanged. The
|
|
4
|
+
TypeScript SDK writes the **same 15 events, the same wire format, into the same
|
|
5
|
+
spool directory** as the Python one, and `failproofaid` ships both. A fleet running
|
|
6
|
+
both languages writes into one pipe, and the dashboard cannot tell which language
|
|
7
|
+
wrote what. This page is what differs: install, names, adapters, bundlers, runtimes,
|
|
8
|
+
shutdown and verification.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @failproofai/sdk # or: pnpm add / yarn add / bun add
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Node ≥ 20.9, Bun, or Deno (`npm:@failproofai/sdk`). ES modules and CommonJS both
|
|
17
|
+
work. It has zero runtime dependencies. The framework packages are optional peer
|
|
18
|
+
dependencies, loaded only when you ask for them.
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import * as failproofai from "@failproofai/sdk"; // ESM
|
|
22
|
+
// const failproofai = require("@failproofai/sdk"); // CommonJS
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Confirm what you have:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
node -e 'console.log(require("@failproofai/sdk").version)'
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
| Import | What it holds |
|
|
32
|
+
|---|---|
|
|
33
|
+
| `@failproofai/sdk` | scopes, `event.*`, `configure`, `flush`/`flushSync`, `instrument`/`uninstrument` |
|
|
34
|
+
| `@failproofai/sdk/langchain` | `langchainHandler()` — a callback handler, no patching |
|
|
35
|
+
| `@failproofai/sdk/ai` | `telemetry()`, `wrapModel()` for the Vercel AI SDK |
|
|
36
|
+
| `@failproofai/sdk/mastra` | `wrapTool()`, `workflow()` |
|
|
37
|
+
| `@failproofai/sdk/llamaindex` | the adapter's internals — nothing to import; use `instrument("llamaindex", { … })` |
|
|
38
|
+
| `@failproofai/sdk/next` | `withFailproofai()` for `next.config` |
|
|
39
|
+
| `@failproofai/sdk/evaluator` | the evaluator worker — see `evaluator.md` |
|
|
40
|
+
|
|
41
|
+
The root import deliberately does not re-export the subpaths.
|
|
42
|
+
|
|
43
|
+
## Names: camelCase in, snake_case on the wire
|
|
44
|
+
|
|
45
|
+
Every Python name has a camelCase twin, and the file on disk is identical:
|
|
46
|
+
|
|
47
|
+
| Python | TypeScript |
|
|
48
|
+
|---|---|
|
|
49
|
+
| `failproofai_sdk.agent("x", goal=g)` | `failproofai.agent("x", { goal: g }, fn)` |
|
|
50
|
+
| `failproofai_sdk.tool_call(...)` | `failproofai.toolCall(name, { toolCallId, input }, fn)` |
|
|
51
|
+
| `failproofai_sdk.session(session_id=...)` | `failproofai.session({ sessionId }, fn)` |
|
|
52
|
+
| `event.tool_use(tool_name=, tool_call_id=)` | `event.toolUse({ toolName, toolCallId })` |
|
|
53
|
+
| `event.model_response(input_tokens=, stop_reason=, request_id=)` | `event.modelResponse({ inputTokens, stopReason, requestId })` |
|
|
54
|
+
| `event.error(error_type=, message=)` | `event.error({ errorType, message })` |
|
|
55
|
+
| `event.human_wait(input_id=)` / `agent_pause(pause_id=)` / `hook_triggered(hook_id=, trigger_event=)` | `inputId` / `pauseId` / `hookId`, `triggerEvent` |
|
|
56
|
+
| `configure(base_dir=, flush_interval=, environment=)` | `configure({ baseDir, flushInterval, environment })` |
|
|
57
|
+
| `failproofai_sdk._writer.flush_now()` | `await failproofai.flush()` / `failproofai.flushSync()` |
|
|
58
|
+
| `propagate(fn)` | `propagate(fn)` |
|
|
59
|
+
|
|
60
|
+
**Only declared option names are camelCase.** Any other key is a custom payload
|
|
61
|
+
field and is written **verbatim**, so `duration_ms` stays `duration_ms`. A camelCase
|
|
62
|
+
typo of a declared name (`toolCallID`) is not an error: it becomes a new field, and
|
|
63
|
+
nothing tells you.
|
|
64
|
+
|
|
65
|
+
## The contract, in TypeScript
|
|
66
|
+
|
|
67
|
+
`SKILL.md` §3 holds, with these spellings:
|
|
68
|
+
|
|
69
|
+
- **Identity is ambient.** It rides on `AsyncLocalStorage`, so it follows `await`,
|
|
70
|
+
`.then()`, timers and callbacks created inside the scope. Two concurrent runs in
|
|
71
|
+
one process never mix. A callback **stored** in one run and invoked from another
|
|
72
|
+
does not inherit it: wrap it with `failproofai.propagate(fn)`.
|
|
73
|
+
- **No session bound and none passed throws `TypeError`** from `event.*` and
|
|
74
|
+
`toolCall()`. `agent()` and `session()` mint a fresh session instead. A non-string id also
|
|
75
|
+
throws `TypeError`. An empty or whitespace id throws `Error`. `agentId` falls back
|
|
76
|
+
to `"main"`.
|
|
77
|
+
- **A reserved extra throws.** `timestamp`, `session_id`, `agent_id`, `type` and
|
|
78
|
+
`environment` cannot be custom fields.
|
|
79
|
+
- **Token counts must be integers.** `inputTokens: 12.5` throws `TypeError`.
|
|
80
|
+
`null` is fine: the key is omitted.
|
|
81
|
+
- **`duration_ms` is refused on the four paired closers**: `toolResult`,
|
|
82
|
+
`hookCompleted`, `humanInput` and `agentResume`. They compute it. On every other
|
|
83
|
+
method, including `modelResponse`, it is accepted as a custom field, and that is
|
|
84
|
+
how you time a model call yourself.
|
|
85
|
+
- **`configure()`**: call it once, at startup, before the first event.
|
|
86
|
+
- Omitted options reset to their defaults.
|
|
87
|
+
- Nothing is applied unless every option validates.
|
|
88
|
+
- A comma in `environment` throws.
|
|
89
|
+
- A comma in `AGENTEYE_ENVIRONMENT` does not throw. It warns and falls back to
|
|
90
|
+
`"dev"`.
|
|
91
|
+
- `environment` and `baseDir` apply to the whole process — every copy of the
|
|
92
|
+
SDK loaded into it (the ESM and CommonJS builds, or a copy a bundler put in a
|
|
93
|
+
Next.js route) — so configure once, anywhere at startup.
|
|
94
|
+
- **`environment` defaults to `"dev"`.** Set it in `configure` or with
|
|
95
|
+
`AGENTEYE_ENVIRONMENT`.
|
|
96
|
+
- **Scope outcomes**:
|
|
97
|
+
- The body returned: `agent_end` with `outcome: "success"`.
|
|
98
|
+
- The body threw: `error`, then `agent_end` with `outcome: "failed"`.
|
|
99
|
+
- An `AbortError`: `agent_end` with `outcome: "cancelled"`.
|
|
100
|
+
|
|
101
|
+
The error is always rethrown. A tool failure is recorded on its `tool_result` and
|
|
102
|
+
emits no run-level `error`.
|
|
103
|
+
- **`error_type` is the error's class.** When an error's `name` is just `"Error"`
|
|
104
|
+
(openai's `BadRequestError`, many SDK errors) the class name is recorded instead.
|
|
105
|
+
- **Timestamps order events within a millisecond.** The last three of the six
|
|
106
|
+
fractional digits are a per-process sequence, not a measurement, so events
|
|
107
|
+
emitted in the same millisecond still sort in the order they happened.
|
|
108
|
+
- **Unencodable values never take the process down.** Circular references,
|
|
109
|
+
`BigInt`, throwing getters and lone surrogates are handled. One bad event is
|
|
110
|
+
dropped alone, not the batch around it.
|
|
111
|
+
- **Credentials are redacted before the bytes reach disk.** That covers API keys,
|
|
112
|
+
tokens, JWTs and bearer headers.
|
|
113
|
+
- **The SDK's own warnings go to stderr, prefixed `[failproofai-sdk]`.**
|
|
114
|
+
- Route them with `failproofai.setLogger({ debug, info, warn, error })`.
|
|
115
|
+
- Set verbosity with `FAILPROOFAI_SDK_LOG_LEVEL`: `debug`, `info`, `warn`
|
|
116
|
+
(the default), `error` or `silent`.
|
|
117
|
+
- `FAILPROOFAI_SDK_STRICT=1` makes a swallowed adapter failure throw.
|
|
118
|
+
|
|
119
|
+
## Shutdown — the part that loses data
|
|
120
|
+
|
|
121
|
+
- **A normal exit is covered.** Buffered events flush on `process.on("exit")`, and
|
|
122
|
+
the flush timer is `unref`'d, so importing the SDK never keeps a script alive.
|
|
123
|
+
- **Short-lived work that returns rather than exits** — a serverless handler, a
|
|
124
|
+
queue job in a long-lived worker — should `await failproofai.flush()` before
|
|
125
|
+
returning: the process lives on, so no exit flush comes.
|
|
126
|
+
- **Signals.** `SIGTERM` (every deploy, `docker stop`, a Kubernetes eviction) kills
|
|
127
|
+
Node **without** running exit handlers. The SDK will not install a signal handler
|
|
128
|
+
in your process (that would change what Ctrl-C does), so add one at startup:
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
for (const [signal, code] of [["SIGINT", 130], ["SIGTERM", 143]] as const) {
|
|
132
|
+
process.once(signal, () => {
|
|
133
|
+
failproofai.flushSync();
|
|
134
|
+
process.exit(code); // 128 + signal number: the orchestrator sees a termination, not a success
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
On the way out the SDK **closes whatever is still open**, most recently opened
|
|
140
|
+
first — including what an adapter opened: an interrupted tool gets its
|
|
141
|
+
`tool_result`, a hook its `hook_completed`, a model call its `model_response`
|
|
142
|
+
(`stop_reason: "error"`), each with a `ProcessExit: …` error, and each open agent
|
|
143
|
+
gets an `error` event and `agent_end` with `outcome: "failed"`. So a deploy never
|
|
144
|
+
leaves a run showing as running forever. (Python gets the same through
|
|
145
|
+
`SystemExit` unwinding.) A `flushSync()` while the process carries on closes
|
|
146
|
+
nothing, and a run paused on a human is left open for whoever resumes it.
|
|
147
|
+
- **Every exit path, not just signals.** The same closing happens on an uncaught
|
|
148
|
+
exception or unhandled rejection (the message names it — `… on an uncaught
|
|
149
|
+
QuotaError: …`), on `process.exit()` from anywhere, and when the event loop
|
|
150
|
+
drains with a run still pending. A run still open when the process ends is a
|
|
151
|
+
failed run, whatever the exit code.
|
|
152
|
+
- **Your own records.** `process.exit()` in that handler skips your code's
|
|
153
|
+
`catch`/`finally`, so a job that records its own result (a database row, a
|
|
154
|
+
status file) should record "interrupted" in the handler too, before
|
|
155
|
+
`flushSync()` — or the dashboard shows a failed run your own store never heard of.
|
|
156
|
+
- **Run `node` directly in services and containers.** `npx tsx` does not pass
|
|
157
|
+
SIGTERM on to the program, which then runs on, finishes, and records `success`
|
|
158
|
+
for a job that was killed. Use `node --import tsx app.ts`, or compile.
|
|
159
|
+
- **Next.js:** put that handler in its own module and import it from
|
|
160
|
+
`instrumentation.ts` behind the runtime check (see *Next.js* below) — `process.once`
|
|
161
|
+
in `instrumentation.ts` itself makes Turbopack warn about the Edge runtime.
|
|
162
|
+
|
|
163
|
+
## A framework agent — turn it on
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
import * as failproofai from "@failproofai/sdk";
|
|
167
|
+
|
|
168
|
+
failproofai.configure({ environment: "production" });
|
|
169
|
+
await failproofai.instrument("langchain"); // name the framework you use
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
| Framework | Tested range | How it attaches |
|
|
173
|
+
|---|---|---|
|
|
174
|
+
| LangChain.js / LangGraph.js | `@langchain/core` 0.3 – 1.x, LangGraph 0.4 – 1.x | global callback configuration — no `callbacks:` needed. Or pass `langchainHandler()` yourself and patch nothing |
|
|
175
|
+
| Vercel AI SDK | `ai` 4 – 7 | `telemetry()` at the call site (every major); `instrument("ai")` process-wide on `ai` 7 only |
|
|
176
|
+
| Mastra | `@mastra/core` 0.20 – 1.x | `Agent.generate`/`.stream`, tool resolution, the workflow engine |
|
|
177
|
+
| LlamaIndex.TS | `llamaindex` 0.11.4 – 0.x | `Settings.callbackManager` plus `AgentWorkflow.runStream` |
|
|
178
|
+
|
|
179
|
+
**`instrument()` — the rules:**
|
|
180
|
+
|
|
181
|
+
- **Await it, before the first run.** An unawaited `instrument()` may happen to
|
|
182
|
+
work when the first run starts late — which is why it passes a local test and
|
|
183
|
+
fails under load. When it loses the race it does not record nothing; it records a
|
|
184
|
+
*wrong* trace: the root run starts before the adapter
|
|
185
|
+
exists, so a graph node, a tool or a bare model call becomes the session's agent,
|
|
186
|
+
or each becomes its own one-call session. The LangChain adapter warns when it sees
|
|
187
|
+
this (`… started under a parent run the langchain adapter never saw …`); the
|
|
188
|
+
others cannot tell it apart from a bare call.
|
|
189
|
+
- **Name the framework.** A bare `instrument()` patches *every* supported framework
|
|
190
|
+
that resolves from the project — including ones installed but unused, and ones
|
|
191
|
+
resolving from a parent directory's `node_modules`. It resolves to the names it
|
|
192
|
+
instrumented, and `[]` plus a warning when it found nothing. An unknown name throws.
|
|
193
|
+
- **Options** go in the second argument, `instrument("<name>", { … })`:
|
|
194
|
+
|
|
195
|
+
| Adapter | Options |
|
|
196
|
+
|---|---|
|
|
197
|
+
| `langchain` | `sessionId`, `captureContent` (default `true`), `includeChains`, `graphCallbacks`, `captureLimit` — also accepted by `langchainHandler({ … })` |
|
|
198
|
+
| `llamaindex` | `captureMessages` (default `true`), `steps` (default `true`; `false` drops the workflow-step hooks), `embeddings`, `staleAfter`, `reaperInterval`, `captureLimit` |
|
|
199
|
+
| `ai` | `registerGlobalTracer` (ai 4–6 only, see below), `captureLimit` |
|
|
200
|
+
| `mastra` | `captureLimit` |
|
|
201
|
+
|
|
202
|
+
Content capture is **on** by default: a LangGraph node's `hook_triggered` carries
|
|
203
|
+
the message history as `input`, and a hand-written `model_request` carries what
|
|
204
|
+
you pass. `captureContent: false` / `captureMessages: false` keep structure,
|
|
205
|
+
durations and tokens and drop the text.
|
|
206
|
+
|
|
207
|
+
**The mapping is the Python SDK's.** An **agent** is anything that owns an LLM
|
|
208
|
+
decision loop: a graph or chain run, `generateText`/`streamText`, a Mastra agent or
|
|
209
|
+
workflow, a LlamaIndex agent run. A LangGraph node or a workflow step is a **hook**
|
|
210
|
+
(`hook_triggered`/`hook_completed` with a `trigger_event`), never a nested agent.
|
|
211
|
+
Model pairs carry token counts; tool pairs carry the model's own tool-call id. A
|
|
212
|
+
failure is recorded once, where it happened — a tool that throws is an `error` on its
|
|
213
|
+
`tool_result`, and if the model then recovers the run still ends `success`.
|
|
214
|
+
|
|
215
|
+
### Naming the agent, and owning the session id
|
|
216
|
+
|
|
217
|
+
`agent_id` is the facet every dashboard view groups by, and each framework takes it
|
|
218
|
+
from a different place. Set it, or you get the framework's default:
|
|
219
|
+
|
|
220
|
+
| Framework | `agent_id` comes from | Default when unset |
|
|
221
|
+
|---|---|---|
|
|
222
|
+
| LangGraph / LangChain | the root run's name: `createReactAgent({ name })`, or `.withConfig({ runName })` on a compiled graph | `"LangGraph"` |
|
|
223
|
+
| Vercel AI SDK | `functionId` in the call's telemetry settings — `telemetry({ functionId })`. An agent class's own `id` (`ToolLoopAgent({ id })`) is **not** passed through | `"ai.generateText"` / `"ai.streamText"` |
|
|
224
|
+
| Mastra | the agent's `name` (not its `id`, not its registration key). A workflow run is rooted under the **workflow's** id, with the agent nested under it | — |
|
|
225
|
+
| LlamaIndex.TS | `agent({ name })` | the class or operation name |
|
|
226
|
+
|
|
227
|
+
Mastra's `tool_name` is the key in the agent's `tools` map, not the `createTool` id.
|
|
228
|
+
|
|
229
|
+
An adapter mints a random session id when nothing is bound, and nothing reads it
|
|
230
|
+
back to you. To use your own — a request or job id, so a dashboard session and your
|
|
231
|
+
own logs or database share it — bind it around the framework call:
|
|
232
|
+
|
|
233
|
+
```ts
|
|
234
|
+
await failproofai.session({ sessionId: requestId }, () => graph.invoke(input));
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
`session()` emits nothing; each framework run inside it is its own agent — so
|
|
238
|
+
three AI SDK calls under one `session()` are three agents in one session. Wrapping in
|
|
239
|
+
`agent()` also works: under the **same** name as the framework agent it becomes that
|
|
240
|
+
agent (one `agent_start`, and every call inside joins it — how several AI SDK
|
|
241
|
+
calls become one agent); under a **different** name the framework agent nests
|
|
242
|
+
under yours (`parent_id` = your name), which is right when your wrapper is a real
|
|
243
|
+
outer agent. A joined agent's `agent_start` is yours, so put the `goal` on it. Inside either, `failproofai.current().sessionId` is the id.
|
|
244
|
+
|
|
245
|
+
Two consequences of owning it: a **retried** job that reuses its job id lands in the
|
|
246
|
+
**same** session, as a second run in it — append the attempt (`${jobId}-2`) if you
|
|
247
|
+
want retries separate. And LangChain also accepts it per call, as
|
|
248
|
+
`metadata: { failproofai_sdk_session_id }`.
|
|
249
|
+
|
|
250
|
+
### Per framework
|
|
251
|
+
|
|
252
|
+
- **Vercel AI SDK.** `telemetry()` at each call site works on every major and is the
|
|
253
|
+
one way to name the agent. On `ai` 7, `instrument("ai")` covers every call in the
|
|
254
|
+
process too; using both does not double-record.
|
|
255
|
+
|
|
256
|
+
```ts
|
|
257
|
+
import { telemetry } from "@failproofai/sdk/ai";
|
|
258
|
+
|
|
259
|
+
await generateText({
|
|
260
|
+
model,
|
|
261
|
+
prompt,
|
|
262
|
+
telemetry: telemetry({ functionId: "answer-question" }), // ai 4–6: `experimental_telemetry:`
|
|
263
|
+
});
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
On `ai` 4–6, `instrument("ai")` records nothing by itself and warns: the only
|
|
267
|
+
process-wide hook there is the global OpenTelemetry tracer, and taking it would
|
|
268
|
+
break the app's own tracing. `instrument("ai", { registerGlobalTracer: true })`
|
|
269
|
+
opts in when the process runs no OpenTelemetry of its own. An agent class takes
|
|
270
|
+
it the same way — `new ToolLoopAgent({ model, tools, telemetry: telemetry({
|
|
271
|
+
functionId: "ai-research" }) })` — since its own `id` is not passed through.
|
|
272
|
+
`await wrapModel(model)`
|
|
273
|
+
(async — pass the resolved model) records model calls only; tools run above the
|
|
274
|
+
model layer. In a route handler on `ai` 7, pass `abortSignal: request.signal` so a
|
|
275
|
+
client that disconnects mid-stream closes the run instead of leaving it open.
|
|
276
|
+
- **Mastra.** `instrument("mastra")` is enough for agents on a `Mastra` instance,
|
|
277
|
+
their tools, and workflows. `wrapTool(tool)` is only for a tool called directly —
|
|
278
|
+
from your own code or a workflow step, not by an agent; `workflow(name, body)` only
|
|
279
|
+
groups work that is not a Mastra workflow under one named span.
|
|
280
|
+
- **LlamaIndex.TS.** A tool or LLM call made *outside* an agent workflow is recorded
|
|
281
|
+
as its own one-call run — that is how bare calls are shown, not a bug. Its
|
|
282
|
+
`openai()` client sends `temperature: 0.1` by default, which some models reject
|
|
283
|
+
with a 400 that crashes the workflow; set `temperature` on `openai({ … })` then.
|
|
284
|
+
|
|
285
|
+
**Token counts — set usage on the model client, or they are silently missing.**
|
|
286
|
+
OpenAI-compatible APIs report usage on a stream only when asked, and some framework
|
|
287
|
+
clients stream even for a non-streaming call:
|
|
288
|
+
|
|
289
|
+
| Framework | Where | Needed for |
|
|
290
|
+
|---|---|---|
|
|
291
|
+
| Vercel AI SDK + `@ai-sdk/openai-compatible` | `createOpenAICompatible({ …, includeUsage: true })` | `streamText` |
|
|
292
|
+
| Mastra (same provider package) | `createOpenAICompatible({ …, includeUsage: true })` | `.stream()` |
|
|
293
|
+
| LlamaIndex.TS | `openai({ …, additionalChatOptions: { stream_options: { include_usage: true } } })` | **every** agent run — its agent streams internally even for `run()` |
|
|
294
|
+
|
|
295
|
+
LangChain's `ChatOpenAI` already asks. For any other client, check for
|
|
296
|
+
`input_tokens`/`output_tokens` on each `model_response` when you verify.
|
|
297
|
+
|
|
298
|
+
### Bundlers — the silent one
|
|
299
|
+
|
|
300
|
+
Most of these frameworks ship an ESM build and a CJS build. Node loads them as two
|
|
301
|
+
unrelated copies. The adapters patch the copy your app loads, plus a CJS copy that
|
|
302
|
+
something has already `require`d.
|
|
303
|
+
|
|
304
|
+
No adapter can reach a framework **bundled into your own output** (esbuild,
|
|
305
|
+
webpack, `ncc`). The copy in `node_modules` is not the one running, and nothing is
|
|
306
|
+
recorded. Either keep the framework external in the bundler config, or use the
|
|
307
|
+
call-site helpers, which work bundled: `langchainHandler()`, `telemetry()`,
|
|
308
|
+
`wrapTool()`.
|
|
309
|
+
|
|
310
|
+
### Next.js
|
|
311
|
+
|
|
312
|
+
`next build` bundles server dependencies by default. Wrap the config, and configure
|
|
313
|
+
and instrument from Next's startup hook:
|
|
314
|
+
|
|
315
|
+
```ts
|
|
316
|
+
// next.config.ts
|
|
317
|
+
import { withFailproofai } from "@failproofai/sdk/next";
|
|
318
|
+
export default withFailproofai({ /* your config */ });
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
```ts
|
|
322
|
+
// instrumentation.ts
|
|
323
|
+
export async function register() {
|
|
324
|
+
if (process.env.NEXT_RUNTIME !== "nodejs") return;
|
|
325
|
+
const failproofai = await import("@failproofai/sdk");
|
|
326
|
+
failproofai.configure({ environment: "production" });
|
|
327
|
+
await failproofai.instrument("langchain");
|
|
328
|
+
await import("./instrumentation-node"); // the signal handler from *Shutdown*
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
- `withFailproofai` adds LangChain, Mastra, LlamaIndex and the SDK to
|
|
333
|
+
`serverExternalPackages` and keeps your own list. Without it, `instrument()` warns
|
|
334
|
+
when `next start` boots — not at `next build` — for each framework it cannot
|
|
335
|
+
reach, and those frameworks record nothing. If you list the packages by hand,
|
|
336
|
+
`FAILPROOFAI_NEXT_EXTERNALS=1` silences the warning.
|
|
337
|
+
- The Vercel AI SDK is not externalized and does not need to be: `telemetry()` and
|
|
338
|
+
`instrument("ai")` on `ai` 7 both work in a bundled route.
|
|
339
|
+
- `configure()` in `register()` applies to the whole server process, including a copy
|
|
340
|
+
of the SDK bundled into a route.
|
|
341
|
+
- Route handlers have no request id of their own: use the `x-request-id` header your
|
|
342
|
+
platform or proxy sets, with a fallback —
|
|
343
|
+
`session({ sessionId: request.headers.get("x-request-id") ?? randomUUID() }, …)`.
|
|
344
|
+
- Pass the request's signal down, so a client that disconnects ends the run
|
|
345
|
+
(`cancelled`) instead of it running on: `graph.invoke(input, { signal:
|
|
346
|
+
request.signal })` for LangGraph, `abortSignal: request.signal` for the AI SDK.
|
|
347
|
+
- **Edge runtimes** (Next.js Edge routes, workers) get a no-op build. Importing is
|
|
348
|
+
safe, and nothing is recorded there. Instrument the Node side.
|
|
349
|
+
|
|
350
|
+
## An agent with no framework — three edit sites
|
|
351
|
+
|
|
352
|
+
This is the path for a hand-built loop: an OpenAI or Anthropic client, a `for` loop
|
|
353
|
+
and a tool table. It also covers any framework without an adapter, whatever else the
|
|
354
|
+
agent does, such as writing its own records to a database. You emit the events
|
|
355
|
+
yourself with the same API the adapters use, so the trace is the same shape — and,
|
|
356
|
+
if you record what the snippet below records, the same quality.
|
|
357
|
+
|
|
358
|
+
Every hand-built agent already has these three places, whatever its functions are
|
|
359
|
+
called. Find them in the codebase first:
|
|
360
|
+
|
|
361
|
+
| Where | Add | Emits |
|
|
362
|
+
|---|---|---|
|
|
363
|
+
| where **one run** starts and ends | `failproofai.agent("name", { goal }, async () => …)` | `agent_start` / `agent_end` |
|
|
364
|
+
| the **one function that calls the model** | `event.modelRequest` before, `event.modelResponse` after — **both halves, even on failure** | one pair per model turn |
|
|
365
|
+
| the **one function that runs tools** | `failproofai.toolCall(name, { toolCallId, input }, () => run())` | `tool_use` / `tool_result` |
|
|
366
|
+
|
|
367
|
+
```ts
|
|
368
|
+
import { randomUUID } from "node:crypto";
|
|
369
|
+
import * as failproofai from "@failproofai/sdk";
|
|
370
|
+
import OpenAI from "openai";
|
|
371
|
+
import type { ChatCompletionMessageParam } from "openai/resources/chat/completions";
|
|
372
|
+
|
|
373
|
+
// 1. the run — everything inside lands on this session, with no ids passed
|
|
374
|
+
const answer = await failproofai.agent("inventory", { goal: question }, async () => {
|
|
375
|
+
for (let turn = 0; turn < 6; turn++) {
|
|
376
|
+
const message = await callModel(messages);
|
|
377
|
+
const calls = (message.tool_calls ?? []).filter((c) => c.type === "function");
|
|
378
|
+
if (calls.length === 0) return message.content ?? "";
|
|
379
|
+
messages.push(message);
|
|
380
|
+
for (const call of calls) {
|
|
381
|
+
messages.push({ role: "tool", tool_call_id: call.id, content: await dispatch(call) });
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return "(gave up)";
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
// 2. the model call — pair on requestId, time it yourself, close it on failure
|
|
388
|
+
async function callModel(messages: ChatCompletionMessageParam[]) {
|
|
389
|
+
const requestId = randomUUID();
|
|
390
|
+
const started = Date.now();
|
|
391
|
+
failproofai.event.modelRequest({
|
|
392
|
+
model: MODEL,
|
|
393
|
+
requestId,
|
|
394
|
+
// Role and content, plus the ids linking a tool result to its call. (openai's
|
|
395
|
+
// own message types do not satisfy the SDK's JSON types under `tsc --strict`.)
|
|
396
|
+
messages: messages.map((m) => ({
|
|
397
|
+
role: m.role,
|
|
398
|
+
content: typeof m.content === "string" ? m.content : m.content == null ? "" : JSON.stringify(m.content),
|
|
399
|
+
...(m.role === "tool" ? { tool_call_id: m.tool_call_id } : {}),
|
|
400
|
+
...(m.role === "assistant" && m.tool_calls
|
|
401
|
+
? { tool_calls: m.tool_calls.map((c) => ({ id: c.id, name: c.type === "function" ? c.function.name : c.type })) }
|
|
402
|
+
: {}),
|
|
403
|
+
})),
|
|
404
|
+
// Tool and tool-call types are unions in openai ≥ 6 (custom tools): narrow them.
|
|
405
|
+
tools: TOOLS.flatMap((t) => (t.type === "function" ? [{ name: t.function.name, description: t.function.description ?? "" }] : [])),
|
|
406
|
+
});
|
|
407
|
+
let reply: OpenAI.Chat.Completions.ChatCompletion;
|
|
408
|
+
try {
|
|
409
|
+
// Only the provider call in the `try`: nothing else can reach the error path.
|
|
410
|
+
reply = await client.chat.completions.create({ model: MODEL, messages, tools: TOOLS });
|
|
411
|
+
} catch (error) {
|
|
412
|
+
failproofai.event.modelResponse({
|
|
413
|
+
model: MODEL,
|
|
414
|
+
requestId,
|
|
415
|
+
stopReason: "error",
|
|
416
|
+
error: error instanceof Error ? `${error.constructor.name}: ${error.message}` : String(error),
|
|
417
|
+
duration_ms: Date.now() - started,
|
|
418
|
+
});
|
|
419
|
+
throw error; // the enclosing agent() then ends "failed"
|
|
420
|
+
}
|
|
421
|
+
const choice = reply.choices[0]!;
|
|
422
|
+
const calls = (choice.message.tool_calls ?? []).filter((c) => c.type === "function");
|
|
423
|
+
failproofai.event.modelResponse({
|
|
424
|
+
model: reply.model,
|
|
425
|
+
requestId,
|
|
426
|
+
role: choice.message.role,
|
|
427
|
+
content: choice.message.content ?? "",
|
|
428
|
+
stopReason: choice.finish_reason,
|
|
429
|
+
inputTokens: reply.usage?.prompt_tokens ?? null,
|
|
430
|
+
outputTokens: reply.usage?.completion_tokens ?? null,
|
|
431
|
+
duration_ms: Date.now() - started,
|
|
432
|
+
// the field and shape the adapters write
|
|
433
|
+
fw_tool_calls: calls.map((c) => ({ toolCallId: c.id, toolName: c.function.name, input: c.function.arguments })),
|
|
434
|
+
});
|
|
435
|
+
return choice.message;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// 3. the tool dispatcher — reuse the model's own tool-call id
|
|
439
|
+
async function dispatch(call: { id: string; function: { name: string; arguments: string } }): Promise<string> {
|
|
440
|
+
// Malformed arguments are still a tool call: recorded, and failed inside
|
|
441
|
+
// toolCall(), so the trace shows it and the model gets an error to recover from.
|
|
442
|
+
let input: Record<string, unknown> = {};
|
|
443
|
+
let malformed: unknown;
|
|
444
|
+
try {
|
|
445
|
+
const parsed: unknown = JSON.parse(call.function.arguments || "{}");
|
|
446
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
447
|
+
throw new TypeError("tool arguments must be a JSON object");
|
|
448
|
+
}
|
|
449
|
+
input = parsed as Record<string, unknown>;
|
|
450
|
+
} catch (error) {
|
|
451
|
+
malformed = error;
|
|
452
|
+
input = { arguments: call.function.arguments };
|
|
453
|
+
}
|
|
454
|
+
try {
|
|
455
|
+
return await failproofai.toolCall(call.function.name, { toolCallId: call.id, input }, async () => {
|
|
456
|
+
if (malformed !== undefined) throw malformed;
|
|
457
|
+
return runTool(call.function.name, input);
|
|
458
|
+
});
|
|
459
|
+
} catch (error) {
|
|
460
|
+
return `error: ${error instanceof Error ? error.message : String(error)}`; // let the model recover
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
The rules that make this correct:
|
|
466
|
+
|
|
467
|
+
- **Emit both halves of the model pair.** A `modelRequest` with no `modelResponse`
|
|
468
|
+
is a span the dashboard shows as running forever — hence the `catch`.
|
|
469
|
+
- **Record what the adapters record.** `role`, `content`, the tool calls the model
|
|
470
|
+
asked for, tokens, stop reason and duration on the response. Leave them out and the
|
|
471
|
+
trace has the shape but not the substance.
|
|
472
|
+
- **Pair model calls on `requestId`**, generated per call, so overlapping calls
|
|
473
|
+
cannot cross-pair.
|
|
474
|
+
- **Model calls are not timed for you.** Pass `duration_ms` yourself — an integer
|
|
475
|
+
(`Date.now()` differences are); a float throws `TypeError`.
|
|
476
|
+
- **Reuse the model's tool-call id** as `toolCallId`, so a `tool_use` lines up with
|
|
477
|
+
the `tool_calls[]` entry that asked for it. `toolCall()` times the call and records
|
|
478
|
+
a throw as `tool_result.error`, then rethrows.
|
|
479
|
+
- **Services and workers.** Pass your own request or job id as `sessionId`
|
|
480
|
+
(`agent("assistant", { sessionId: jobId }, fn)`). A dashboard session and the
|
|
481
|
+
record in your own logs or database are then the same string. (Retries: see
|
|
482
|
+
*Naming the agent, and owning the session id*.)
|
|
483
|
+
- **Sub-agents.** Nest `agent()` calls — directly, or from inside a tool the outer
|
|
484
|
+
agent runs. The inner one joins the session, and its `parent_id` is the outer
|
|
485
|
+
agent's name.
|
|
486
|
+
- **Don't reach for a module-level session variable.** Two overlapping runs mix
|
|
487
|
+
their events. `AsyncLocalStorage` already does this correctly.
|
|
488
|
+
- **A failed tool does not fail the run.** It is an `error` on its `tool_result`,
|
|
489
|
+
and if the model recovers the run ends `success` with no `error` event — so an
|
|
490
|
+
evaluation that counts `error` events will not see it. Count `tool_result`s
|
|
491
|
+
with an `error` instead.
|
|
492
|
+
- **Types are the only guard on names in plain JavaScript.** A misspelt required
|
|
493
|
+
option (`toolCallID`) is not a runtime error: the event is written without it and
|
|
494
|
+
never pairs. Use TypeScript, or check the ids when you verify.
|
|
495
|
+
- **`input` is typed as an object.** The SDK does not reject a primitive at
|
|
496
|
+
runtime, so wrap it yourself: `{ query: q }`.
|
|
497
|
+
- **Watch the size of `messages`.** Each `model_request` carries whatever you pass,
|
|
498
|
+
and the history grows every turn — including provider blobs such as encrypted
|
|
499
|
+
reasoning. Send role/content, and trim what a reader does not need.
|
|
500
|
+
- **Don't emit your own `agent_end` inside `agent()`.** The scope emits one; a second
|
|
501
|
+
is accepted and duplicates it.
|
|
502
|
+
|
|
503
|
+
The complete, runnable version is `sdk/typescript/examples/research-agent.ts` in the
|
|
504
|
+
FailproofAI/failproofai repo. CI runs it, as an ES module and as CommonJS, against
|
|
505
|
+
the real `openai` client.
|
|
506
|
+
|
|
507
|
+
**`using`, when a callback will not fit.** Use it for a scope opened in a
|
|
508
|
+
constructor and closed in a teardown:
|
|
509
|
+
|
|
510
|
+
```ts
|
|
511
|
+
{
|
|
512
|
+
using span = failproofai.agent.open("planner", { goal });
|
|
513
|
+
using call = failproofai.toolCall.open("search", { input: { q } });
|
|
514
|
+
call.call.output = await search(q);
|
|
515
|
+
} // tool_result, then agent_end
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
Prefer the callback form. It has nothing to unwind.
|
|
519
|
+
|
|
520
|
+
## Verify
|
|
521
|
+
|
|
522
|
+
The spool is the same directory the Python SDK uses:
|
|
523
|
+
`${FAILPROOFAI_HOME:-~/.failproofai}/custom-agents/events/`, unless the app passed
|
|
524
|
+
`configure({ baseDir })`.
|
|
525
|
+
|
|
526
|
+
**On a machine running `failproofaid`, that directory is empty seconds after a
|
|
527
|
+
healthy run** — the daemon ships each file and deletes it. An empty real spool
|
|
528
|
+
means nothing; check with a throwaway spool the daemon does not watch. Use a
|
|
529
|
+
directory of your own, so parallel checks on one machine cannot delete each other's:
|
|
530
|
+
|
|
531
|
+
```bash
|
|
532
|
+
export FAILPROOFAI_HOME="$(mktemp -d)"
|
|
533
|
+
npx tsx your-agent.ts # Next.js: set it on `next start`
|
|
534
|
+
node -e '
|
|
535
|
+
const fs = require("fs"), d = process.env.FAILPROOFAI_HOME + "/custom-agents/events";
|
|
536
|
+
for (const f of fs.readdirSync(d).filter(f => f.endsWith(".jsonl")).sort())
|
|
537
|
+
for (const l of fs.readFileSync(d + "/" + f, "utf8").split("\n").filter(Boolean)) {
|
|
538
|
+
const e = JSON.parse(l);
|
|
539
|
+
console.log(e.timestamp, e.session_id, e.agent_id, e.type, e.tool_name ?? "",
|
|
540
|
+
e.tool_call_id ?? e.request_id ?? "", e.input_tokens ?? "", e.output_tokens ?? "",
|
|
541
|
+
e.outcome ?? "", e.error ?? "", e.environment);
|
|
542
|
+
}'
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
Then walk the same checklist as `SKILL.md` §5 (its first item — a dead flush
|
|
546
|
+
thread — is Python's; the TypeScript SDK logs `[failproofai-sdk]` warnings to
|
|
547
|
+
stderr instead):
|
|
548
|
+
|
|
549
|
+
1. **One `agent_start`/`agent_end` pair per agent per run** — two when a sub-agent
|
|
550
|
+
runs, each with the right `parent_id`. No files at all usually means one of these:
|
|
551
|
+
- The process was killed by a signal with no handler, or returned from a
|
|
552
|
+
serverless handler without `await failproofai.flush()`.
|
|
553
|
+
- `instrument()` found nothing, or was not awaited: look for the
|
|
554
|
+
`[failproofai-sdk]` warning on stderr.
|
|
555
|
+
- The framework is bundled.
|
|
556
|
+
2. **Every pair closed, with the ids you expect** — each
|
|
557
|
+
`model_request`/`model_response` on `request_id`, each `tool_use`/`tool_result` on
|
|
558
|
+
`tool_call_id` — and **token counts** on every `model_response` (missing on
|
|
559
|
+
streams: see *Token counts*).
|
|
560
|
+
3. **Two overlapping runs give two session ids, with no events crossing.**
|
|
561
|
+
4. **`environment` is the label you expect** on every event.
|
|
562
|
+
5. **The `agent_id`s are your names**, not `LangGraph` or `ai.generateText`.
|
|
563
|
+
|
|
564
|
+
Then confirm the real thing arrived, from a separate environment, with the
|
|
565
|
+
`fp-cloud-cli` skill: `fp sessions --session-id <id> --since 1h` (the id you bound
|
|
566
|
+
with `session()`, or read with `failproofai.current()`). A session's `status` says
|
|
567
|
+
whether it finished, not whether it succeeded — a killed run is `done` too; its
|
|
568
|
+
`agent_end` `outcome` (`fp events --session-id <id> --full`) is what says `failed`.
|