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
|
@@ -1,421 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cache and rate limit in front of a Jev transport, so a burst of tool calls
|
|
3
|
-
* stays under the provider's limit instead of degrading silently.
|
|
4
|
-
*
|
|
5
|
-
* `throttleTransport(t, opts?)` returns a transport with the same contract as
|
|
6
|
-
* `t`. It adds two things and nothing else:
|
|
7
|
-
*
|
|
8
|
-
* - **An LRU cache** keyed by the SHA-256 of the full request (model, state
|
|
9
|
-
* and questions, byte for byte as serialized, plus an optional `scope`).
|
|
10
|
-
* The request is everything Jev sees — no clock, no randomness — so an
|
|
11
|
-
* identical request is an identical question, and its answer is reused for
|
|
12
|
-
* a short TTL. The TTL runs from when the answer was fetched; a hit never
|
|
13
|
-
* extends it. Only answers the evaluator accepts are stored (`readAnswers`:
|
|
14
|
-
* a probability in [0, 1] for every question asked, from a model it
|
|
15
|
-
* accepts), bounded by entry count and by size, and
|
|
16
|
-
* every hit hands back a fresh copy, so a caller mutating its response can
|
|
17
|
-
* never change what the next caller gets. A side effect worth having: within
|
|
18
|
-
* the TTL, retrying a denied call gets the same answer rather than a fresh
|
|
19
|
-
* draw from a model that is ~98% run-to-run stable.
|
|
20
|
-
* - **A token bucket** (default 5 req/s, burst 5; see `ThrottleOptions` for
|
|
21
|
-
* what those bound) on the calls that actually go upstream; cache hits are
|
|
22
|
-
* free. Over budget, it throws
|
|
23
|
-
* `JevError("rate-limited")` at once, so the evaluator degrades and the
|
|
24
|
-
* caller falls back to the regex result with a recorded reason — visibly,
|
|
25
|
-
* not silently. `maxWaitMs` lets a call wait briefly for the next token
|
|
26
|
-
* instead. A provider 429 empties the bucket as of when the 429 arrived
|
|
27
|
-
* (however long that round-trip took), so the calls right behind it fall
|
|
28
|
-
* back locally instead of spending more requests on a full window.
|
|
29
|
-
*
|
|
30
|
-
* It never throws on its own except for those two cases: an over-budget call,
|
|
31
|
-
* and a signal that is already aborted (or aborts while waiting for a token).
|
|
32
|
-
* Every error from the wrapped transport is rethrown unchanged — the same
|
|
33
|
-
* object — and never cached. Internal failures (a request that cannot be
|
|
34
|
-
* serialized, say) skip the cache; they never fail the call.
|
|
35
|
-
*
|
|
36
|
-
* **State is module-level.** The daemon's warm worker (`worker-server.ts`) is
|
|
37
|
-
* the only evaluator on a configured machine and lives for hours, so the
|
|
38
|
-
* process is the cache and the bucket is the process's upstream budget: a
|
|
39
|
-
* caller may build a new wrapper per hook event and every wrapper shares both.
|
|
40
|
-
* The worker also serializes `evaluateHookEvent`, so there is never more than
|
|
41
|
-
* one Jev call in flight and no in-flight de-duplication is needed.
|
|
42
|
-
*
|
|
43
|
-
* **No on-disk cache**, deliberately. It would only help the one-shot
|
|
44
|
-
* in-process path, which on a configured machine does not exist (CLAUDE.md,
|
|
45
|
-
* "Enforcement routes through the daemon": only this repo's dogfood configs
|
|
46
|
-
* and not-yet-set-up machines evaluate in-process). And it would be a
|
|
47
|
-
* poisoning surface: every file under `~/.failproofai` is writable by the same
|
|
48
|
-
* user the agent runs as, and the request format is open source, so the agent
|
|
49
|
-
* being judged could compute the digest of the call it is about to make and
|
|
50
|
-
* pre-write an all-clear answer — clearing reviewable denies without Jev ever
|
|
51
|
-
* being asked. The worker's memory has no such surface. Signing the entries
|
|
52
|
-
* would not help: any key the hook can read, the agent can read too.
|
|
53
|
-
*
|
|
54
|
-
* **What a caller wiring this in must do** (T3), because the module cannot see
|
|
55
|
-
* any of it from here:
|
|
56
|
-
*
|
|
57
|
-
* - **Pass `scope`** naming where answers come from, e.g.
|
|
58
|
-
* `` `${route.via}|${route.endpoint}|${route.model}` `` from T1's route. The
|
|
59
|
-
* request alone does not say which provider, endpoint or model answered — a
|
|
60
|
-
* transport may send a model other than `request.model` — and the cache is
|
|
61
|
-
* process-wide, so without a scope a `jev.json` change in a long-lived
|
|
62
|
-
* worker serves the old provider's answers under the new one until they
|
|
63
|
-
* expire. The scope is only ever hashed into the key, never stored, so an
|
|
64
|
-
* endpoint carrying a credential in its query string is safe to pass. It
|
|
65
|
-
* cannot default to anything better: the transport's identity changes on
|
|
66
|
-
* every hook event (a new wrapper each time), which would turn the cache off.
|
|
67
|
-
* - **A hit is the original answer, `usage` included**, returned in ~0 ms.
|
|
68
|
-
* Anything that sums tokens or cost, or takes latency percentiles, must tell
|
|
69
|
-
* hits apart. `evaluateSemantic` never exposes the response, so wrap the
|
|
70
|
-
* throttled transport and ask {@link isCachedJevResponse}:
|
|
71
|
-
* `async (r, s) => { const res = await throttled(r, s); cached = isCachedJevResponse(res); return res; }`
|
|
72
|
-
* then record `inputTokens: null` (and flag the latency) when `cached`.
|
|
73
|
-
* - **Tests** that route through a throttled transport share this module's
|
|
74
|
-
* state across every file bun runs in one process: call
|
|
75
|
-
* `resetJevThrottle()` in `beforeEach`, or pass
|
|
76
|
-
* `{ cacheTtlMs: 0, ratePerSec: 1e6 }` where caching and limiting are not
|
|
77
|
-
* what is under test.
|
|
78
|
-
*/
|
|
79
|
-
import { createHash } from "node:crypto";
|
|
80
|
-
import { JevError, readAnswers, type JevTransport } from "./jev-client";
|
|
81
|
-
import type { JevRequest, JevResponse } from "./types";
|
|
82
|
-
|
|
83
|
-
export interface ThrottleOptions {
|
|
84
|
-
/**
|
|
85
|
-
* Sustained upstream requests per second. Default 5, from the one Cloudflare
|
|
86
|
-
* figure there is: a replay against one key sustained ~6 calls/s before
|
|
87
|
-
* HTTP 429s took over (measured over the replay as a whole, not over any
|
|
88
|
-
* one-second window). Cloudflare publishes its Workers AI limits per
|
|
89
|
-
* minute (300/min for text generation by default, i.e. 5/s); whether
|
|
90
|
-
* `typesafe/jev` is under that default, and so which window a burst runs
|
|
91
|
-
* into, is unconfirmed (R4 or a live check). TypeSafe documents 1,200/min
|
|
92
|
-
* (20/s). Must be a positive finite number, else the default.
|
|
93
|
-
*/
|
|
94
|
-
ratePerSec?: number;
|
|
95
|
-
/**
|
|
96
|
-
* Bucket capacity — how many calls may go out back to back. Default: one
|
|
97
|
-
* second's worth (`ratePerSec`, at least 1), so a handful of parallel tool
|
|
98
|
-
* calls after a pause are all judged. A bucket admits at most
|
|
99
|
-
* `burst + ratePerSec` calls in any one-second window (10 with the
|
|
100
|
-
* defaults) and `burst + 60 × ratePerSec` in any minute (305). Against a
|
|
101
|
-
* per-minute limit that is the sustained rate plus one burst; against a
|
|
102
|
-
* strict per-second one it could spend a few calls a provider refuses, and
|
|
103
|
-
* the first 429 then empties the bucket, so the loss stays at a few calls
|
|
104
|
-
* per burst. Pass `burst: 1` to cap any one second at `1 + ratePerSec`.
|
|
105
|
-
*/
|
|
106
|
-
burst?: number;
|
|
107
|
-
/** How long a call may wait for the next token before it is rate-limited. Default 0: over budget fails at once. */
|
|
108
|
-
maxWaitMs?: number;
|
|
109
|
-
/** How long an answer is reused, from when it was fetched. Default 5 minutes. 0 disables the cache. */
|
|
110
|
-
cacheTtlMs?: number;
|
|
111
|
-
/** Most answers kept. Default 512. 0 disables the cache. */
|
|
112
|
-
cacheMaxEntries?: number;
|
|
113
|
-
/** Most characters of serialized answers kept (≈ bytes; answers are ASCII JSON). Default 4 MiB. 0 disables the cache. */
|
|
114
|
-
cacheMaxBytes?: number;
|
|
115
|
-
/**
|
|
116
|
-
* Mixed into the cache key (hashed, never stored): where the answers came
|
|
117
|
-
* from — provider, endpoint and the model actually sent, e.g.
|
|
118
|
-
* `` `${via}|${endpoint}|${model}` ``. Answers cached under one scope are
|
|
119
|
-
* never served under another. Default `""`, which every unscoped wrapper in
|
|
120
|
-
* the process shares: a real caller should always pass one (see the module
|
|
121
|
-
* doc).
|
|
122
|
-
*/
|
|
123
|
-
scope?: string;
|
|
124
|
-
/** Monotonic clock in milliseconds. For tests; defaults to `performance.now()`. */
|
|
125
|
-
now?: () => number;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
export const DEFAULT_THROTTLE = Object.freeze({
|
|
129
|
-
ratePerSec: 5,
|
|
130
|
-
maxWaitMs: 0,
|
|
131
|
-
cacheTtlMs: 5 * 60_000,
|
|
132
|
-
cacheMaxEntries: 512,
|
|
133
|
-
cacheMaxBytes: 4 * 1024 * 1024,
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
/** One answer bigger than this is never cached. A full request's answers are a few KB. */
|
|
137
|
-
export const MAX_CACHED_ENTRY_CHARS = 64 * 1024;
|
|
138
|
-
|
|
139
|
-
interface ResolvedOptions {
|
|
140
|
-
ratePerSec: number;
|
|
141
|
-
burst: number;
|
|
142
|
-
maxWaitMs: number;
|
|
143
|
-
cacheEnabled: boolean;
|
|
144
|
-
cacheTtlMs: number;
|
|
145
|
-
cacheMaxEntries: number;
|
|
146
|
-
cacheMaxBytes: number;
|
|
147
|
-
scope: string;
|
|
148
|
-
now: () => number;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const positive = (v: unknown, fallback: number): number =>
|
|
152
|
-
typeof v === "number" && Number.isFinite(v) && v > 0 ? v : fallback;
|
|
153
|
-
const nonNegative = (v: unknown, fallback: number): number =>
|
|
154
|
-
typeof v === "number" && Number.isFinite(v) && v >= 0 ? v : fallback;
|
|
155
|
-
|
|
156
|
-
function resolveOptions(opts: ThrottleOptions): ResolvedOptions {
|
|
157
|
-
const ratePerSec = positive(opts.ratePerSec, DEFAULT_THROTTLE.ratePerSec);
|
|
158
|
-
const cacheTtlMs = nonNegative(opts.cacheTtlMs, DEFAULT_THROTTLE.cacheTtlMs);
|
|
159
|
-
const cacheMaxEntries = Math.floor(nonNegative(opts.cacheMaxEntries, DEFAULT_THROTTLE.cacheMaxEntries));
|
|
160
|
-
const cacheMaxBytes = nonNegative(opts.cacheMaxBytes, DEFAULT_THROTTLE.cacheMaxBytes);
|
|
161
|
-
return {
|
|
162
|
-
ratePerSec,
|
|
163
|
-
burst: Math.max(1, positive(opts.burst, ratePerSec)),
|
|
164
|
-
maxWaitMs: nonNegative(opts.maxWaitMs, DEFAULT_THROTTLE.maxWaitMs),
|
|
165
|
-
cacheEnabled: cacheTtlMs > 0 && cacheMaxEntries > 0 && cacheMaxBytes > 0,
|
|
166
|
-
cacheTtlMs,
|
|
167
|
-
cacheMaxEntries,
|
|
168
|
-
cacheMaxBytes,
|
|
169
|
-
scope: typeof opts.scope === "string" ? opts.scope : "",
|
|
170
|
-
now: typeof opts.now === "function" ? opts.now : () => performance.now(),
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// ── Module state (shared by every wrapper in the process) ────────────────────
|
|
175
|
-
|
|
176
|
-
interface Entry {
|
|
177
|
-
body: string;
|
|
178
|
-
expiresAt: number;
|
|
179
|
-
size: number;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const cache = new Map<string, Entry>();
|
|
183
|
-
let cacheChars = 0;
|
|
184
|
-
/** Tokens may go negative: a waiting call reserves the next one. NaN = not yet used. */
|
|
185
|
-
const bucket = { tokens: Number.NaN, last: Number.NaN };
|
|
186
|
-
const counters = { hits: 0, misses: 0, rateLimited: 0, upstreamErrors: 0, evictions: 0 };
|
|
187
|
-
/** Responses this module handed out from the cache; see {@link isCachedJevResponse}. */
|
|
188
|
-
let servedFromCache = new WeakSet<object>();
|
|
189
|
-
|
|
190
|
-
export interface JevThrottleStats {
|
|
191
|
-
/** Answers served from the cache. */
|
|
192
|
-
hits: number;
|
|
193
|
-
/** Lookups that found nothing (cache enabled only). */
|
|
194
|
-
misses: number;
|
|
195
|
-
/** Calls refused locally because the bucket was empty. */
|
|
196
|
-
rateLimited: number;
|
|
197
|
-
/** Errors the wrapped transport threw (passed through). */
|
|
198
|
-
upstreamErrors: number;
|
|
199
|
-
/** Entries dropped to stay within the size bounds (not counting expiry). */
|
|
200
|
-
evictions: number;
|
|
201
|
-
/** Answers currently cached. */
|
|
202
|
-
entries: number;
|
|
203
|
-
/** Characters currently cached. */
|
|
204
|
-
chars: number;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
export function jevThrottleStats(): JevThrottleStats {
|
|
208
|
-
return { ...counters, entries: cache.size, chars: cacheChars };
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/** Empties the cache and the bucket and zeroes the counters. */
|
|
212
|
-
export function resetJevThrottle(): void {
|
|
213
|
-
cache.clear();
|
|
214
|
-
cacheChars = 0;
|
|
215
|
-
bucket.tokens = Number.NaN;
|
|
216
|
-
bucket.last = Number.NaN;
|
|
217
|
-
counters.hits = 0;
|
|
218
|
-
counters.misses = 0;
|
|
219
|
-
counters.rateLimited = 0;
|
|
220
|
-
counters.upstreamErrors = 0;
|
|
221
|
-
counters.evictions = 0;
|
|
222
|
-
servedFromCache = new WeakSet<object>();
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* True when `response` came from the cache rather than the network — for a
|
|
227
|
-
* caller that wants to record it. A hit costs nothing and takes ~0 ms, but it
|
|
228
|
-
* still carries the original answer's `usage`: token and cost totals must
|
|
229
|
-
* skip it. Through `evaluateSemantic`, wrap the throttled transport to see
|
|
230
|
-
* the response (module doc).
|
|
231
|
-
*/
|
|
232
|
-
export function isCachedJevResponse(response: unknown): boolean {
|
|
233
|
-
return typeof response === "object" && response !== null && servedFromCache.has(response);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// ── Cache ────────────────────────────────────────────────────────────────────
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* The cache key: SHA-256 over the scope and the full request exactly as
|
|
240
|
-
* serialized. Exported so a replay (R4) can measure hit rates with the same
|
|
241
|
-
* key the worker uses. Throws if the request cannot be serialized.
|
|
242
|
-
*/
|
|
243
|
-
export function jevRequestDigest(request: JevRequest, scope = ""): string {
|
|
244
|
-
return createHash("sha256").update(scope).update("\0").update(JSON.stringify(request)).digest("hex");
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
function keyFor(cfg: ResolvedOptions, request: JevRequest): string | null {
|
|
248
|
-
if (!cfg.cacheEnabled) return null;
|
|
249
|
-
try {
|
|
250
|
-
return jevRequestDigest(request, cfg.scope);
|
|
251
|
-
} catch {
|
|
252
|
-
return null; // Unserializable: no cache for this call, never an error.
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
function dropEntry(key: string, entry: Entry): void {
|
|
257
|
-
cache.delete(key);
|
|
258
|
-
cacheChars -= entry.size;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
function cacheGet(key: string, now: number): JevResponse | null {
|
|
262
|
-
const entry = cache.get(key);
|
|
263
|
-
if (!entry) return null;
|
|
264
|
-
if (now >= entry.expiresAt) {
|
|
265
|
-
dropEntry(key, entry);
|
|
266
|
-
return null;
|
|
267
|
-
}
|
|
268
|
-
// Most recently used goes last; eviction takes from the front.
|
|
269
|
-
cache.delete(key);
|
|
270
|
-
cache.set(key, entry);
|
|
271
|
-
try {
|
|
272
|
-
return JSON.parse(entry.body) as JevResponse;
|
|
273
|
-
} catch {
|
|
274
|
-
dropEntry(key, entry);
|
|
275
|
-
return null;
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
/**
|
|
280
|
-
* Only an answer the evaluator could use is worth keeping. The rule is the
|
|
281
|
-
* evaluator's own (`readAnswers`: a probability in [0, 1] for every question,
|
|
282
|
-
* and a model it accepts), not a copy of it, so the two cannot drift apart: a
|
|
283
|
-
* wrong-model answer the evaluator rejects is never pinned for the TTL.
|
|
284
|
-
*/
|
|
285
|
-
function isUsableAnswer(request: JevRequest, response: JevResponse): boolean {
|
|
286
|
-
try {
|
|
287
|
-
readAnswers(request, response);
|
|
288
|
-
return true;
|
|
289
|
-
} catch {
|
|
290
|
-
return false;
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
function cachePut(cfg: ResolvedOptions, key: string, request: JevRequest, response: JevResponse, now: number): void {
|
|
295
|
-
if (!isUsableAnswer(request, response)) return;
|
|
296
|
-
let body: string;
|
|
297
|
-
try {
|
|
298
|
-
body = JSON.stringify(response);
|
|
299
|
-
} catch {
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
const size = key.length + body.length;
|
|
303
|
-
if (size > MAX_CACHED_ENTRY_CHARS || size > cfg.cacheMaxBytes) return;
|
|
304
|
-
const prev = cache.get(key);
|
|
305
|
-
if (prev) dropEntry(key, prev);
|
|
306
|
-
cache.set(key, { body, expiresAt: now + cfg.cacheTtlMs, size });
|
|
307
|
-
cacheChars += size;
|
|
308
|
-
for (const [k, e] of cache) {
|
|
309
|
-
const expired = now >= e.expiresAt;
|
|
310
|
-
if (!expired && cache.size <= cfg.cacheMaxEntries && cacheChars <= cfg.cacheMaxBytes) break;
|
|
311
|
-
dropEntry(k, e);
|
|
312
|
-
if (!expired) counters.evictions++;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
// ── Token bucket ─────────────────────────────────────────────────────────────
|
|
317
|
-
|
|
318
|
-
/** Error codes meaning the provider itself refused for rate: `http-429` from the HTTP layer, or a transport's own `rate-limited`. */
|
|
319
|
-
const PROVIDER_WINDOW_FULL = new Set(["http-429", "rate-limited"]);
|
|
320
|
-
|
|
321
|
-
function refill(cfg: ResolvedOptions, now: number): void {
|
|
322
|
-
if (!Number.isFinite(bucket.last) || !Number.isFinite(bucket.tokens)) {
|
|
323
|
-
bucket.tokens = cfg.burst;
|
|
324
|
-
bucket.last = now;
|
|
325
|
-
return;
|
|
326
|
-
}
|
|
327
|
-
const elapsed = Math.max(0, now - bucket.last);
|
|
328
|
-
bucket.last = now;
|
|
329
|
-
bucket.tokens = Math.min(cfg.burst, bucket.tokens + (elapsed * cfg.ratePerSec) / 1000);
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
function abortedError(signal: AbortSignal): JevError {
|
|
333
|
-
const name = (signal.reason as { name?: unknown } | undefined)?.name;
|
|
334
|
-
return name === "TimeoutError"
|
|
335
|
-
? new JevError("timeout", "Jev did not answer in time")
|
|
336
|
-
: new JevError("aborted", "the Jev request was aborted");
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
function sleep(ms: number, signal: AbortSignal | undefined): Promise<void> {
|
|
340
|
-
return new Promise<void>((resolve, reject) => {
|
|
341
|
-
const onAbort = () => {
|
|
342
|
-
clearTimeout(timer);
|
|
343
|
-
reject(abortedError(signal as AbortSignal));
|
|
344
|
-
};
|
|
345
|
-
const timer = setTimeout(() => {
|
|
346
|
-
signal?.removeEventListener("abort", onAbort);
|
|
347
|
-
resolve();
|
|
348
|
-
}, ms);
|
|
349
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
350
|
-
});
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
/** Takes one token, waiting up to `maxWaitMs` for it, or throws `rate-limited`. */
|
|
354
|
-
async function acquire(cfg: ResolvedOptions, signal: AbortSignal | undefined): Promise<void> {
|
|
355
|
-
refill(cfg, cfg.now());
|
|
356
|
-
bucket.tokens -= 1;
|
|
357
|
-
if (bucket.tokens >= 0) return;
|
|
358
|
-
const waitMs = (-bucket.tokens / cfg.ratePerSec) * 1000;
|
|
359
|
-
if (waitMs > cfg.maxWaitMs) {
|
|
360
|
-
bucket.tokens += 1;
|
|
361
|
-
counters.rateLimited++;
|
|
362
|
-
throw new JevError(
|
|
363
|
-
"rate-limited",
|
|
364
|
-
`local Jev budget of ${cfg.ratePerSec} request(s)/s is spent; next slot in ${Math.ceil(waitMs)} ms`,
|
|
365
|
-
);
|
|
366
|
-
}
|
|
367
|
-
try {
|
|
368
|
-
await sleep(waitMs, signal);
|
|
369
|
-
} catch (err) {
|
|
370
|
-
bucket.tokens += 1; // The reserved slot was never used.
|
|
371
|
-
throw err;
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
// ── The wrapper ──────────────────────────────────────────────────────────────
|
|
376
|
-
|
|
377
|
-
/**
|
|
378
|
-
* `t` behind the shared cache and token bucket. `opts` is read once, here;
|
|
379
|
-
* every call through the returned transport uses it.
|
|
380
|
-
*/
|
|
381
|
-
export function throttleTransport(t: JevTransport, opts?: ThrottleOptions | null): JevTransport {
|
|
382
|
-
const cfg = resolveOptions(opts ?? {});
|
|
383
|
-
return async (request, signal) => {
|
|
384
|
-
// The type says a signal is always passed; a caller that omits one still gets no throw from here.
|
|
385
|
-
if (signal?.aborted) throw abortedError(signal);
|
|
386
|
-
|
|
387
|
-
const key = keyFor(cfg, request);
|
|
388
|
-
if (key !== null) {
|
|
389
|
-
const hit = cacheGet(key, cfg.now());
|
|
390
|
-
if (hit) {
|
|
391
|
-
counters.hits++;
|
|
392
|
-
servedFromCache.add(hit);
|
|
393
|
-
return hit;
|
|
394
|
-
}
|
|
395
|
-
counters.misses++;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
await acquire(cfg, signal);
|
|
399
|
-
|
|
400
|
-
let response: JevResponse;
|
|
401
|
-
try {
|
|
402
|
-
response = await t(request, signal);
|
|
403
|
-
} catch (err) {
|
|
404
|
-
counters.upstreamErrors++;
|
|
405
|
-
// The provider's window is full: the calls right behind this one fall
|
|
406
|
-
// back locally until the bucket refills, rather than each spending a
|
|
407
|
-
// request to learn the same thing. Refill to now first: the bucket was
|
|
408
|
-
// last stamped when this call was admitted, so without it the next
|
|
409
|
-
// refill would credit the whole round-trip (hundreds of ms against a
|
|
410
|
-
// real provider, i.e. one or more tokens) and undo the emptying.
|
|
411
|
-
if (err instanceof JevError && PROVIDER_WINDOW_FULL.has(err.code)) {
|
|
412
|
-
refill(cfg, cfg.now());
|
|
413
|
-
bucket.tokens = Math.min(bucket.tokens, 0);
|
|
414
|
-
}
|
|
415
|
-
throw err;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
if (key !== null) cachePut(cfg, key, request, response, cfg.now());
|
|
419
|
-
return response;
|
|
420
|
-
};
|
|
421
|
-
}
|
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Which semantic policy set this machine runs: a pack's, or the compiled-in one.
|
|
3
|
-
*
|
|
4
|
-
* ## The replacement rule
|
|
5
|
-
*
|
|
6
|
-
* A pack that declares at least ONE `semantic` entry replaces
|
|
7
|
-
* `SEMANTIC_POLICIES` wholesale. It mirrors the rule already in force for the
|
|
8
|
-
* regex builtins — installing a pack stops the compiled builtins registering —
|
|
9
|
-
* and it exists for the same reason: one source of truth, so a name collision
|
|
10
|
-
* between a pack's `destructive-deletion` and the builtin of that name cannot
|
|
11
|
-
* arise, and `reviewedBy: ["destructive-deletion"]` in a pack manifest cannot
|
|
12
|
-
* silently mean the builtin's question set instead of the pack's.
|
|
13
|
-
*
|
|
14
|
-
* Two packs that both declare entries CONCATENATE; a name declared by two packs
|
|
15
|
-
* keeps the first and drops the later one, because the answer map is keyed by
|
|
16
|
-
* policy name and the second would overwrite the first's questions in the
|
|
17
|
-
* compiled request.
|
|
18
|
-
*
|
|
19
|
-
* ## Where the manifest ends and this begins
|
|
20
|
-
*
|
|
21
|
-
* `pack-manifest.ts` validates the shape — names, modes, probe ids, caps it can
|
|
22
|
-
* check by counting — because it runs on every hook event and may not touch a
|
|
23
|
-
* semantic module. Everything that needs the semantic side is here: binding a
|
|
24
|
-
* precondition NAME to its predicate, and the request budget, which is a
|
|
25
|
-
* character count and not a probe count.
|
|
26
|
-
*
|
|
27
|
-
* ## Dropping, not failing
|
|
28
|
-
*
|
|
29
|
-
* Every failure here drops ONE policy and records why. A semantic policy is what
|
|
30
|
-
* CLEARS a reviewable regex verdict, so losing one leaves the regex deny
|
|
31
|
-
* standing: noisier, never weaker. Dropping the whole set would be the same
|
|
32
|
-
* direction but much louder, and failing the pack would deny every event its
|
|
33
|
-
* regex policies cover — a machine locked out over a typo in the half of the
|
|
34
|
-
* system whose job is to let more real work through.
|
|
35
|
-
*/
|
|
36
|
-
import { hookLogWarn } from "../hook-logger";
|
|
37
|
-
import {
|
|
38
|
-
packSemantic,
|
|
39
|
-
readInstalledPacks,
|
|
40
|
-
semanticQuestions,
|
|
41
|
-
type ResolvedPack,
|
|
42
|
-
type SemanticManifestEntry,
|
|
43
|
-
} from "../pack-manifest";
|
|
44
|
-
import { MAX_REQUEST_CHARS, userAskedQuestion } from "./compile";
|
|
45
|
-
import { MAX_STATE_CHARS } from "./envelope";
|
|
46
|
-
import { INJECTION_PROBE, SCOPE_PROBE, SEMANTIC_POLICIES, TASK_PROBES } from "./policies";
|
|
47
|
-
import { preconditionFor } from "./preconditions";
|
|
48
|
-
import { isPackPreconditionName } from "./precondition-names";
|
|
49
|
-
import type { NoulQuestion, SemanticPolicy } from "./types";
|
|
50
|
-
|
|
51
|
-
/** The question object `compile.ts` builds for one probe. Shared so the measurement matches. */
|
|
52
|
-
function noulOf(probe: { instructions: string; criteria?: { true: string; false: string } }): NoulQuestion {
|
|
53
|
-
return { type: "noul", instructions: probe.instructions, ...(probe.criteria ? { criteria: { ...probe.criteria } } : {}) };
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* What the questions a call does NOT get to choose already cost: the injection
|
|
58
|
-
* probe, the v0 scope probe and the v1 task probes, whichever set is larger.
|
|
59
|
-
*
|
|
60
|
-
* Reserved out of the budget below because they are in every request that asks
|
|
61
|
-
* anything, so a pack budget that ignored them would be over by their size on
|
|
62
|
-
* every call.
|
|
63
|
-
*/
|
|
64
|
-
const GLOBAL_QUESTION_CHARS = Math.max(
|
|
65
|
-
JSON.stringify({ [INJECTION_PROBE.id]: noulOf(INJECTION_PROBE), [SCOPE_PROBE.id]: noulOf(SCOPE_PROBE) }).length,
|
|
66
|
-
JSON.stringify(
|
|
67
|
-
Object.fromEntries([INJECTION_PROBE, ...TASK_PROBES].map((p) => [p.id, noulOf(p)])),
|
|
68
|
-
).length,
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* How many characters of questions every installed pack may contribute,
|
|
73
|
-
* together.
|
|
74
|
-
*
|
|
75
|
-
* DERIVED, not chosen. `prepareSemantic` checks one number — the serialized
|
|
76
|
-
* request against `MAX_REQUEST_CHARS` — and the state side of that is already
|
|
77
|
-
* spent to the last character by `buildEnvelope` (`MAX_STATE_CHARS`), so what is
|
|
78
|
-
* left for questions is the difference, minus the globals above. A pack set that
|
|
79
|
-
* fits this fits at FULL state size, which is the only size worth budgeting for:
|
|
80
|
-
* the state is a function of the caps and not of what the agent sent, so a
|
|
81
|
-
* request that only fits on small inputs is a request that intermittently
|
|
82
|
-
* doesn't.
|
|
83
|
-
*
|
|
84
|
-
* Deriving it is the point. The count caps it replaced (24 policies, 80 probes)
|
|
85
|
-
* were set without reference to the envelope and permitted a question set 23,032
|
|
86
|
-
* characters past what a request can carry — at which point `PreparedCall
|
|
87
|
-
* .oversized` stops meaning "our own question set overran" and starts meaning
|
|
88
|
-
* "somebody installed a big pack", and the flag that was supposed to be
|
|
89
|
-
* unreachable from ordinary work becomes routine.
|
|
90
|
-
*
|
|
91
|
-
* The real sixteen use 19,787 characters at their worst, so this is not a
|
|
92
|
-
* constraint on the set we ship. It is the ceiling on what a stranger's pack may
|
|
93
|
-
* ask for.
|
|
94
|
-
*/
|
|
95
|
-
export const MAX_PACK_QUESTION_CHARS = MAX_REQUEST_CHARS - MAX_STATE_CHARS - GLOBAL_QUESTION_CHARS;
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* The compiled cost of one entry's questions, measured the way
|
|
99
|
-
* `prepareSemantic` measures the request: the serialized question map.
|
|
100
|
-
*
|
|
101
|
-
* `user_asked` is counted for an overridable policy even though the shipped
|
|
102
|
-
* path is intent v1, which does not ask it. A budget is worst-case over the
|
|
103
|
-
* modes a machine can run, and the alternative — a set that fits under v1 and
|
|
104
|
-
* overruns the moment anything asks in v0 — is a size cliff that depends on a
|
|
105
|
-
* flag rather than on the pack.
|
|
106
|
-
*/
|
|
107
|
-
export function questionChars(entry: SemanticManifestEntry): number {
|
|
108
|
-
const questions: Record<string, NoulQuestion> = {};
|
|
109
|
-
for (const probe of semanticQuestions(entry)) questions[`${entry.name}.${probe.id}`] = noulOf(probe);
|
|
110
|
-
if (entry.userCanOverride) {
|
|
111
|
-
// It reads `title` and nothing else (`actionPhrase` in `compile.ts`), so a
|
|
112
|
-
// stub is the honest argument here — building a whole `SemanticPolicy` to
|
|
113
|
-
// measure one string would invite it to drift from the real conversion.
|
|
114
|
-
questions[`${entry.name}.user_asked`] = userAskedQuestion({ title: entry.title } as SemanticPolicy);
|
|
115
|
-
}
|
|
116
|
-
return JSON.stringify(questions).length;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
export interface ResolvedSemanticPolicies {
|
|
120
|
-
policies: ReadonlyArray<SemanticPolicy>;
|
|
121
|
-
/** True when a pack supplied the set, so the compiled-in one is not in play. */
|
|
122
|
-
fromPack: boolean;
|
|
123
|
-
/** One line per dropped policy. Diagnostics; nothing here changes a verdict. */
|
|
124
|
-
errors: string[];
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/** Turn one validated manifest entry into a policy the compiler can use. */
|
|
128
|
-
function toSemanticPolicy(entry: SemanticManifestEntry): SemanticPolicy {
|
|
129
|
-
// An unknown precondition name DROPS the policy (the caller catches this),
|
|
130
|
-
// rather than compiling it with no gate at all. Ungating would be the wider
|
|
131
|
-
// direction, not the weaker one, but it is not what the author asked for: a
|
|
132
|
-
// question written for the one case its gate selects would then be put to Jev
|
|
133
|
-
// on every call, and nothing would say so. Unreachable through
|
|
134
|
-
// `parsePackSemanticPolicy`, which refuses the name; reachable if the two
|
|
135
|
-
// precondition files ever drift, which is what this is here for.
|
|
136
|
-
const name = entry.precondition;
|
|
137
|
-
if (name !== undefined && !isPackPreconditionName(name)) {
|
|
138
|
-
throw new Error(`precondition ${JSON.stringify(name)} is not a name this build has`);
|
|
139
|
-
}
|
|
140
|
-
const precondition = name === undefined ? null : preconditionFor(name);
|
|
141
|
-
return {
|
|
142
|
-
name: entry.name,
|
|
143
|
-
title: entry.title,
|
|
144
|
-
appliesTo: entry.appliesTo,
|
|
145
|
-
mode: entry.mode,
|
|
146
|
-
userCanOverride: entry.userCanOverride,
|
|
147
|
-
probes: entry.probes,
|
|
148
|
-
...(entry.exempt ? { exempt: entry.exempt } : {}),
|
|
149
|
-
// Absent, never `() => true`: `selectPolicies` treats an absent precondition
|
|
150
|
-
// as "ask", so `precondition: "always"` and an omitted field have to compile
|
|
151
|
-
// to the identical policy.
|
|
152
|
-
...(precondition ? { precondition } : {}),
|
|
153
|
-
guidance: entry.guidance,
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* The semantic set these packs declare, or the compiled-in set when none of them
|
|
159
|
-
* declares any.
|
|
160
|
-
*
|
|
161
|
-
* Pure: it takes the packs rather than reading them, so the caller that already
|
|
162
|
-
* has them does not read `installed.json` a second time and a test does not need
|
|
163
|
-
* a filesystem.
|
|
164
|
-
*/
|
|
165
|
-
export function semanticPoliciesFromPacks(
|
|
166
|
-
packs: ReadonlyArray<Pick<ResolvedPack, "id" | "semantic">>,
|
|
167
|
-
): ResolvedSemanticPolicies {
|
|
168
|
-
const declared = packs.filter((p) => packSemantic(p).length > 0);
|
|
169
|
-
if (declared.length === 0) return { policies: SEMANTIC_POLICIES, fromPack: false, errors: [] };
|
|
170
|
-
|
|
171
|
-
const policies: SemanticPolicy[] = [];
|
|
172
|
-
const errors: string[] = [];
|
|
173
|
-
const seen = new Set<string>();
|
|
174
|
-
let spent = 0;
|
|
175
|
-
for (const pack of declared) {
|
|
176
|
-
for (const entry of packSemantic(pack)) {
|
|
177
|
-
if (seen.has(entry.name)) {
|
|
178
|
-
errors.push(`pack ${pack.id} declares semantic policy ${entry.name}, which another pack already declared`);
|
|
179
|
-
continue;
|
|
180
|
-
}
|
|
181
|
-
const cost = questionChars(entry);
|
|
182
|
-
if (spent + cost > MAX_PACK_QUESTION_CHARS) {
|
|
183
|
-
errors.push(
|
|
184
|
-
`pack ${pack.id} semantic policy ${entry.name} was dropped: its questions need ${cost} characters and ` +
|
|
185
|
-
`only ${Math.max(0, MAX_PACK_QUESTION_CHARS - spent)} of the ${MAX_PACK_QUESTION_CHARS}-character ` +
|
|
186
|
-
`question budget one Jev request has are left`,
|
|
187
|
-
);
|
|
188
|
-
continue;
|
|
189
|
-
}
|
|
190
|
-
try {
|
|
191
|
-
policies.push(toSemanticPolicy(entry));
|
|
192
|
-
} catch (err) {
|
|
193
|
-
errors.push(`pack ${pack.id} semantic policy ${entry.name}: ${err instanceof Error ? err.message : String(err)}`);
|
|
194
|
-
continue;
|
|
195
|
-
}
|
|
196
|
-
seen.add(entry.name);
|
|
197
|
-
spent += cost;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// Every entry a declaring pack shipped was unusable. The compiled-in set is
|
|
202
|
-
// the honest answer — it is what the machine ran yesterday — and it is also
|
|
203
|
-
// the safe one: what a pack's regex half names in `reviewedBy` will not match
|
|
204
|
-
// it, so those policies stay hard rather than being cleared by questions
|
|
205
|
-
// nobody validated.
|
|
206
|
-
if (policies.length === 0) return { policies: SEMANTIC_POLICIES, fromPack: false, errors };
|
|
207
|
-
return { policies, fromPack: true, errors };
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
const warned = new Set<string>();
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* The live set, read from the installed packs.
|
|
214
|
-
*
|
|
215
|
-
* Called from `prepareSemantic`, so only on a machine that has a Jev config and
|
|
216
|
-
* is preparing a request. It re-reads the manifest rather than caching: the
|
|
217
|
-
* daemon's warm worker lives for hours, a pack can be installed or upgraded
|
|
218
|
-
* under it, and `readInstalledPacks` re-verifies each artifact digest for
|
|
219
|
-
* exactly that reason. The read costs one digest per pack against a call that is
|
|
220
|
-
* about to spend up to three seconds on the network.
|
|
221
|
-
*
|
|
222
|
-
* Never throws. An unreadable manifest yields the compiled-in set, which is the
|
|
223
|
-
* same fail-open posture every other reader of that file takes, and here it also
|
|
224
|
-
* fails in the safe direction: the set a pack's `reviewedBy` names is not the
|
|
225
|
-
* builtin set, so nothing gets cleared by a policy nobody could read.
|
|
226
|
-
*/
|
|
227
|
-
export function resolveSemanticPolicies(): ReadonlyArray<SemanticPolicy> {
|
|
228
|
-
let packs: ReadonlyArray<ResolvedPack> = [];
|
|
229
|
-
let manifestErrors: string[] = [];
|
|
230
|
-
try {
|
|
231
|
-
const read = readInstalledPacks();
|
|
232
|
-
packs = read.packs;
|
|
233
|
-
manifestErrors = read.warnings ?? [];
|
|
234
|
-
} catch {
|
|
235
|
-
return SEMANTIC_POLICIES;
|
|
236
|
-
}
|
|
237
|
-
const resolved = semanticPoliciesFromPacks(packs);
|
|
238
|
-
// Once per process per message, like `warnAuthority`: this runs on every gate
|
|
239
|
-
// event, and in the warm worker that is every tool call of every session.
|
|
240
|
-
for (const message of [...manifestErrors, ...resolved.errors]) {
|
|
241
|
-
if (warned.has(message)) continue;
|
|
242
|
-
warned.add(message);
|
|
243
|
-
hookLogWarn(message);
|
|
244
|
-
}
|
|
245
|
-
return resolved.policies;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
/** Forget which warnings were already said. Tests only. */
|
|
249
|
-
export function _resetSemanticWarningsForTest(): void {
|
|
250
|
-
warned.clear();
|
|
251
|
-
}
|