failproofai 1.0.3 → 1.0.4-beta.2
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 +5 -5
- package/.next/standalone/.next/prerender-manifest.json +5 -5
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +2 -2
- 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.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/build-manifest.json +2 -2
- 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.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/invite/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route.js +4 -4
- package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/status/route_client-reference-manifest.js +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-request/route_client-reference-manifest.js +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/login-verify/route_client-reference-manifest.js +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/logout/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/audit/page/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +37 -4
- package/.next/standalone/.next/server/app/audit/page.js +2 -2
- package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/page/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- 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/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
- 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/build-manifest.json +2 -2
- 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.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/build-manifest.json +2 -2
- 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.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/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- 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/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +4 -4
- 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]__0-9ti7z._.js → [externals]__1lh7m5d._.js} +1 -1
- package/.next/standalone/.next/server/chunks/{[externals]__0u3wrvq._.js → [externals]__1rqkg_y._.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]__1adacul._.js +1 -1
- package/.next/standalone/.next/server/chunks/{_1-akg6w._.js → _08w6xzm._.js} +2 -2
- 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/_1ek68ln._.js +4 -4
- package/.next/standalone/.next/server/chunks/lib_telemetry_ts_0dctyyw._.js +1 -1
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_01r25oi._.js +2 -2
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_09z9-p7._.js +2 -2
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
- package/.next/standalone/.next/server/chunks/src_hooks_fp-home_ts_09kv0bn._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__013jr2b._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01wy8d-._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02npjtd._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0da85px._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ftmoxc._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0oa1lav._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0p-5p8u._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0rgu2r3._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s740oi._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1p2otjt._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_0-oij9d._.js +23 -0
- package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0l2hi_d._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0oq1dh6._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1es2j7i._.js +47 -13
- package/.next/standalone/.next/server/chunks/ssr/_1u8-lu2._.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 -69
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_rerun-button_tsx_0blihgw._.js +3 -0
- 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 +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_13n822a._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_posthog-node_dist_entrypoints_index_node_mjs_11bnuzn._.js +2 -2
- 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-config_ts_04t589g._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-home_ts_0je3xkv._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +5 -5
- 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 +54 -21
- package/.next/standalone/.next/static/chunks/010bv1w6j171t.js +1 -0
- package/.next/standalone/.next/static/chunks/04r6ch8uf_n8m.js +1 -0
- package/.next/standalone/.next/static/chunks/{29-iqnp9v_axt.css → 0o-hh5_turzlz.css} +1 -1
- package/.next/standalone/.next/static/chunks/{40nr6ehj4p3cw.css → 0qmsunv04x4na.css} +1 -1
- package/.next/standalone/.next/static/chunks/{0ollg-nnu3t3e.js → 0wz8yftk18ts2.js} +1 -1
- package/.next/standalone/.next/static/chunks/0zebh1n9jkfbt.js +1 -0
- package/.next/standalone/.next/static/chunks/1eyl7fzkmnkf_.js +1 -0
- package/.next/standalone/.next/static/chunks/1pb1oztsbwcss.js +1 -0
- package/.next/standalone/.next/static/chunks/{1-_zkmnm-jwei.js → 2aquitk72k2op.js} +1 -1
- package/.next/standalone/.next/static/chunks/2bi_1y0a_smt7.js +6 -0
- package/.next/standalone/.next/static/chunks/{42yfkhekx440s.js → 2ej3b8gk5ittu.js} +1 -1
- package/.next/standalone/.next/static/chunks/{354-n7p7labpn.js → 2zafgs90r_leq.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2xm5mj1d21b4n.js → 32spub4wqjem-.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1a6u7l3giejch.js → 3m4upvybtrexd.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2k9f4tyv04809.css → 3uyhmm01g64k4.css} +1 -0
- package/.next/standalone/.next/static/chunks/{turbopack-2x-o099q64i8h.js → turbopack-3s3c-u_u_l0u9.js} +1 -1
- package/.next/standalone/.opencode/plugins/failproofai.mjs +51 -27
- package/.next/standalone/app/actions/get-leaks.ts +100 -0
- package/.next/standalone/app/audit/_components/audit-dashboard.tsx +112 -33
- package/.next/standalone/app/audit/_components/audit-poster.tsx +29 -10
- package/.next/standalone/app/audit/_components/come-back-better-section.tsx +6 -1
- package/.next/standalone/app/audit/_components/empty-state.tsx +4 -1
- package/.next/standalone/app/audit/_components/how-to-improve-section.tsx +19 -5
- package/.next/standalone/app/audit/_components/leak-section.tsx +179 -0
- package/.next/standalone/app/audit/_components/share-templates.ts +110 -44
- package/.next/standalone/app/audit/audit-styles.css +114 -1
- package/.next/standalone/fp-cloud-cli/CHANGELOG.md +26 -3
- package/.next/standalone/fp-cloud-cli/fp_cli/_click_compat.py +31 -8
- package/.next/standalone/fp-cloud-cli/fp_cli/permissions.py +1 -0
- package/.next/standalone/fp-cloud-cli/pyproject.toml +9 -2
- package/.next/standalone/fp-cloud-cli/tests/test_click_compat.py +54 -0
- package/.next/standalone/fp-cloud-cli/uv.lock +9 -12
- package/.next/standalone/lib/auth/api-server-client.ts +28 -0
- package/.next/standalone/lib/claude-sessions.ts +101 -27
- package/.next/standalone/node_modules/@next/env/package.json +1 -1
- package/.next/standalone/node_modules/next/dist/build/swc/index.js +1 -1
- package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo-experimental.runtime.prod.js +1 -1
- package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js +1 -1
- package/.next/standalone/node_modules/next/dist/compiled/next-server/app-route-turbo.runtime.prod.js +1 -1
- package/.next/standalone/node_modules/next/dist/compiled/next-server/pages-turbo.runtime.prod.js +5 -5
- package/.next/standalone/node_modules/next/dist/experimental/testmode/fetch.js +10 -2
- package/.next/standalone/node_modules/next/dist/lib/patch-incorrect-lockfile.js +3 -3
- package/.next/standalone/node_modules/next/dist/lib/typescript/runTypeScriptCli.js +2 -2
- package/.next/standalone/node_modules/next/dist/lib/verify-typescript-setup.js +3 -1
- package/.next/standalone/node_modules/next/dist/server/config.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-turbopack.js +2 -2
- package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-webpack.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/lib/app-info-log.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/lib/incremental-cache/file-system-cache.js +17 -4
- package/.next/standalone/node_modules/next/dist/server/lib/start-server.js +1 -1
- package/.next/standalone/node_modules/next/dist/shared/lib/router/utils/escape-path-delimiters.js +1 -1
- package/.next/standalone/node_modules/next/dist/telemetry/anonymous-meta.js +1 -1
- package/.next/standalone/node_modules/next/dist/telemetry/events/swc-load-failure.js +1 -1
- package/.next/standalone/node_modules/next/dist/telemetry/events/version.js +2 -2
- package/.next/standalone/node_modules/next/package.json +11 -11
- package/.next/standalone/package.json +14 -13
- package/.next/standalone/sdk/python/CHANGELOG.md +155 -0
- package/.next/standalone/sdk/python/README.md +8 -0
- package/.next/standalone/sdk/python/examples/evaluator_worker.py +121 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_version.py +1 -1
- package/.next/standalone/sdk/python/failproofai_sdk/evaluator/__init__.py +101 -0
- package/.next/standalone/sdk/python/failproofai_sdk/evaluator/__main__.py +49 -0
- package/.next/standalone/sdk/python/failproofai_sdk/evaluator/_sandbox_runner.py +63 -0
- package/.next/standalone/sdk/python/failproofai_sdk/evaluator/authoring.py +404 -0
- package/.next/standalone/sdk/python/failproofai_sdk/evaluator/client.py +299 -0
- package/.next/standalone/sdk/python/failproofai_sdk/evaluator/protocol.py +754 -0
- package/.next/standalone/sdk/python/failproofai_sdk/evaluator/runtime.py +936 -0
- package/.next/standalone/sdk/python/failproofai_sdk/evaluator/source.py +684 -0
- package/.next/standalone/sdk/python/tests/fixtures/evaluator_v2/README.md +28 -0
- package/.next/standalone/sdk/python/tests/fixtures/evaluator_v2/contract.json +252 -0
- package/.next/standalone/sdk/python/tests/test_evaluator_authoring.py +124 -0
- package/.next/standalone/sdk/python/tests/test_evaluator_client.py +253 -0
- package/.next/standalone/sdk/python/tests/test_evaluator_example.py +35 -0
- package/.next/standalone/sdk/python/tests/test_evaluator_http_e2e.py +636 -0
- package/.next/standalone/sdk/python/tests/test_evaluator_main.py +47 -0
- package/.next/standalone/sdk/python/tests/test_evaluator_protocol.py +246 -0
- package/.next/standalone/sdk/python/tests/test_evaluator_review_fixes.py +164 -0
- package/.next/standalone/sdk/python/tests/test_evaluator_runtime.py +1103 -0
- package/.next/standalone/sdk/python/tests/test_evaluator_source.py +430 -0
- package/.next/standalone/sdk/python/tests/test_zero_dependencies.py +17 -0
- package/.next/standalone/sdk/python/uv.lock +29 -29
- package/.next/standalone/server.js +1 -1
- package/README.md +13 -58
- package/dist/cli.mjs +5368 -8756
- package/dist/worker.mjs +539 -312
- package/lib/auth/api-server-client.ts +28 -0
- package/lib/claude-sessions.ts +101 -27
- package/package.json +14 -13
- package/pi-extension/index.ts +42 -4
- package/scripts/changelog-open.py +115 -0
- package/src/audit/cli.ts +134 -0
- package/src/audit/desktop-notify.ts +420 -0
- package/src/audit/harm-report.ts +101 -0
- package/src/audit/index.ts +141 -13
- package/src/audit/leak-fingerprint.ts +200 -0
- package/src/audit/leak-notice.ts +161 -0
- package/src/audit/leak-record.ts +232 -0
- package/src/audit/leak-scan.ts +292 -0
- package/src/audit/leak-store.ts +217 -0
- package/src/audit/macos-notifier.ts +310 -0
- package/src/audit/redact-example.ts +266 -14
- package/src/audit/report-harm.ts +12 -1
- package/src/audit/report.ts +6 -3
- package/src/audit/schedule-cli.ts +37 -0
- package/src/audit/scoring.ts +49 -0
- package/src/audit/types.ts +41 -0
- package/src/hooks/builtin-policies.ts +67 -2
- package/src/hooks/configure-wizard.ts +20 -0
- package/src/hooks/fp-config.ts +71 -11
- package/src/hooks/fp-home.ts +27 -0
- package/src/hooks/handler.ts +59 -1
- package/src/hooks/integrations.ts +47 -13
- package/src/hooks/notice.ts +155 -0
- package/src/hooks/uninstall-cli.ts +15 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1b5jzxr._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0j6gd_k._.js +0 -23
- package/.next/standalone/.next/server/chunks/ssr/_0v8eebd._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_1ylae7o._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/node_modules_html-to-image_es_index_1ao30b1.js +0 -3
- package/.next/standalone/.next/static/chunks/03slu0c8_71y7.js +0 -1
- package/.next/standalone/.next/static/chunks/0nm11ysn0153h.js +0 -1
- package/.next/standalone/.next/static/chunks/0u64yey446k4f.css +0 -1
- package/.next/standalone/.next/static/chunks/1r9676mkvihto.js +0 -1
- package/.next/standalone/.next/static/chunks/30pct5s734jua.js +0 -6
- package/.next/standalone/.next/static/chunks/3pibxnbhjza7n.js +0 -69
- package/.next/standalone/.next/static/chunks/3qfoeqhy5l10x.js +0 -1
- package/.next/standalone/.next/static/chunks/3zkg2s2vzxc3d.js +0 -1
- package/.next/standalone/.next/static/chunks/41b5ptaocvi_l.js +0 -1
- /package/.next/standalone/.next/static/{JBYgkXkA1PS48m9P_hKNw → aKNv4Kmv98Xpwns0Xa-C-}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{JBYgkXkA1PS48m9P_hKNw → aKNv4Kmv98Xpwns0Xa-C-}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{JBYgkXkA1PS48m9P_hKNw → aKNv4Kmv98Xpwns0Xa-C-}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""Customer evaluator with deterministic and optional async judge checks."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import ipaddress
|
|
7
|
+
import json
|
|
8
|
+
import os
|
|
9
|
+
from urllib.parse import urlsplit
|
|
10
|
+
from urllib.request import HTTPRedirectHandler, Request, build_opener
|
|
11
|
+
|
|
12
|
+
from failproofai_sdk.evaluator import (
|
|
13
|
+
ConditionResult,
|
|
14
|
+
EvalResult,
|
|
15
|
+
Evaluator,
|
|
16
|
+
Metric,
|
|
17
|
+
Score,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
app = Evaluator(name="customer-production", version="2026.08.1")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class _RejectRedirects(HTTPRedirectHandler):
|
|
24
|
+
def redirect_request(self, request, file_pointer, code, message, headers, new_url):
|
|
25
|
+
return None
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@app.eval(
|
|
29
|
+
"tool_efficiency",
|
|
30
|
+
version="1.0.0",
|
|
31
|
+
labels=["tools", "deterministic"],
|
|
32
|
+
when=lambda session: ConditionResult(
|
|
33
|
+
session.count("tool_use") > 0, "no_tool_calls"
|
|
34
|
+
),
|
|
35
|
+
)
|
|
36
|
+
def tool_efficiency(session):
|
|
37
|
+
calls = session.events_of_type("tool_use")
|
|
38
|
+
distinct = {
|
|
39
|
+
event.payload.get("tool_name")
|
|
40
|
+
for event in calls
|
|
41
|
+
if event.payload.get("tool_name")
|
|
42
|
+
}
|
|
43
|
+
value = len(distinct) / len(calls)
|
|
44
|
+
return EvalResult(
|
|
45
|
+
score=Score(value, passed=value >= 0.7),
|
|
46
|
+
metrics={
|
|
47
|
+
"tool_call_count": Metric(len(calls), unit="events"),
|
|
48
|
+
"distinct_tool_count": Metric(len(distinct), unit="tools"),
|
|
49
|
+
},
|
|
50
|
+
reasoning=f"{len(distinct)} distinct tools across {len(calls)} calls",
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _judge_configured(session):
|
|
55
|
+
configured = bool(os.environ.get("EXAMPLE_JUDGE_URL"))
|
|
56
|
+
return ConditionResult(configured, "judge_not_configured")
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _last_content(session, event_type):
|
|
60
|
+
events = session.events_of_type(event_type)
|
|
61
|
+
if not events:
|
|
62
|
+
return None
|
|
63
|
+
payload = events[-1].payload
|
|
64
|
+
fields = {
|
|
65
|
+
"human_input": ("response",),
|
|
66
|
+
"model_response": ("content",),
|
|
67
|
+
"agent_end": ("summary",),
|
|
68
|
+
}.get(event_type, ("content", "summary", "response"))
|
|
69
|
+
return next((payload.get(field) for field in fields if payload.get(field)), None)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _call_judge(question, answer):
|
|
73
|
+
url = os.environ["EXAMPLE_JUDGE_URL"]
|
|
74
|
+
parsed = urlsplit(url)
|
|
75
|
+
if parsed.scheme not in {"http", "https"} or not parsed.netloc:
|
|
76
|
+
raise ValueError("EXAMPLE_JUDGE_URL must be an absolute http(s) URL")
|
|
77
|
+
hostname = parsed.hostname
|
|
78
|
+
loopback = hostname == "localhost"
|
|
79
|
+
if hostname is not None and not loopback:
|
|
80
|
+
try:
|
|
81
|
+
loopback = ipaddress.ip_address(hostname).is_loopback
|
|
82
|
+
except ValueError:
|
|
83
|
+
loopback = False
|
|
84
|
+
if parsed.scheme != "https" and not loopback:
|
|
85
|
+
raise ValueError("EXAMPLE_JUDGE_URL must use https unless it targets loopback")
|
|
86
|
+
token = os.environ.get("EXAMPLE_JUDGE_TOKEN")
|
|
87
|
+
body = json.dumps({"question": question, "answer": answer}).encode("utf-8")
|
|
88
|
+
headers = {"Content-Type": "application/json", "Accept": "application/json"}
|
|
89
|
+
if token:
|
|
90
|
+
headers["Authorization"] = f"Bearer {token}"
|
|
91
|
+
request = Request(url, data=body, headers=headers, method="POST")
|
|
92
|
+
with build_opener(_RejectRedirects()).open(request, timeout=25) as response: # nosec B310
|
|
93
|
+
result = json.loads(response.read(64 * 1024))
|
|
94
|
+
return float(result["score"]), str(
|
|
95
|
+
result.get("reasoning") or "Judge returned no reasoning"
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@app.eval(
|
|
100
|
+
"answer_relevance",
|
|
101
|
+
version="judge-api-v1",
|
|
102
|
+
labels=["llm_judge", "relevance"],
|
|
103
|
+
when=_judge_configured,
|
|
104
|
+
timeout_seconds=30,
|
|
105
|
+
)
|
|
106
|
+
async def answer_relevance(session):
|
|
107
|
+
question = _last_content(session, "human_input")
|
|
108
|
+
answer = _last_content(session, "model_response")
|
|
109
|
+
if question is None or answer is None:
|
|
110
|
+
raise ValueError("answer relevance requires human input and model output")
|
|
111
|
+
value, reasoning = await asyncio.to_thread(_call_judge, question, answer)
|
|
112
|
+
value = min(max(value, 0.0), 1.0)
|
|
113
|
+
return EvalResult(
|
|
114
|
+
score=Score(value, passed=value >= 0.7),
|
|
115
|
+
reasoning=reasoning,
|
|
116
|
+
labels=("llm_judge", "relevance"),
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
if __name__ == "__main__":
|
|
121
|
+
app.run_from_env()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.0.
|
|
1
|
+
__version__ = "0.0.1b3"
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""Authoring and worker primitives for FailproofAI Evaluator v2.
|
|
2
|
+
|
|
3
|
+
This namespace is intentionally lazy relative to :mod:`failproofai_sdk`: users
|
|
4
|
+
who only emit telemetry do not import evaluator networking or runtime code.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from failproofai_sdk.evaluator.authoring import (
|
|
8
|
+
Assertion,
|
|
9
|
+
ConditionResult,
|
|
10
|
+
EvalDefinition,
|
|
11
|
+
EvalResult,
|
|
12
|
+
Evaluator,
|
|
13
|
+
Metric,
|
|
14
|
+
Score,
|
|
15
|
+
)
|
|
16
|
+
from failproofai_sdk.evaluator.client import EvaluatorAPIError, EvaluatorClient
|
|
17
|
+
from failproofai_sdk.evaluator.protocol import (
|
|
18
|
+
Assignment,
|
|
19
|
+
AssignmentDefinition,
|
|
20
|
+
CatalogDefinition,
|
|
21
|
+
ClaimRequest,
|
|
22
|
+
ClaimResponse,
|
|
23
|
+
ErrorResponse,
|
|
24
|
+
EvalSelection,
|
|
25
|
+
ExecutionMode,
|
|
26
|
+
EvaluatorKind,
|
|
27
|
+
HeartbeatRequest,
|
|
28
|
+
HeartbeatResponse,
|
|
29
|
+
HeartbeatRun,
|
|
30
|
+
PlannedRun,
|
|
31
|
+
PlanRequest,
|
|
32
|
+
PlanResponse,
|
|
33
|
+
DefinitionsResponse,
|
|
34
|
+
ProtocolError,
|
|
35
|
+
RegisterRequest,
|
|
36
|
+
RegisterResponse,
|
|
37
|
+
RemoteError,
|
|
38
|
+
ResultItem,
|
|
39
|
+
ResultKind,
|
|
40
|
+
ResultRequest,
|
|
41
|
+
ResultResponse,
|
|
42
|
+
SessionTranscript,
|
|
43
|
+
SkippedEval,
|
|
44
|
+
TerminalRunStatus,
|
|
45
|
+
TranscriptEvent,
|
|
46
|
+
UnsupportedProtocolVersion,
|
|
47
|
+
)
|
|
48
|
+
from failproofai_sdk.evaluator.runtime import WorkerConfig, WorkerRuntime
|
|
49
|
+
from failproofai_sdk.evaluator.source import (
|
|
50
|
+
UnsafeEvaluatorSource,
|
|
51
|
+
compile_condition,
|
|
52
|
+
compile_evaluator,
|
|
53
|
+
source_checksum,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
__all__ = [
|
|
57
|
+
"Assertion",
|
|
58
|
+
"Assignment",
|
|
59
|
+
"AssignmentDefinition",
|
|
60
|
+
"CatalogDefinition",
|
|
61
|
+
"ClaimRequest",
|
|
62
|
+
"ClaimResponse",
|
|
63
|
+
"ConditionResult",
|
|
64
|
+
"ErrorResponse",
|
|
65
|
+
"EvalDefinition",
|
|
66
|
+
"EvalResult",
|
|
67
|
+
"EvalSelection",
|
|
68
|
+
"ExecutionMode",
|
|
69
|
+
"Evaluator",
|
|
70
|
+
"EvaluatorAPIError",
|
|
71
|
+
"EvaluatorClient",
|
|
72
|
+
"EvaluatorKind",
|
|
73
|
+
"HeartbeatRequest",
|
|
74
|
+
"HeartbeatResponse",
|
|
75
|
+
"HeartbeatRun",
|
|
76
|
+
"Metric",
|
|
77
|
+
"PlanRequest",
|
|
78
|
+
"PlanResponse",
|
|
79
|
+
"DefinitionsResponse",
|
|
80
|
+
"PlannedRun",
|
|
81
|
+
"ProtocolError",
|
|
82
|
+
"RegisterRequest",
|
|
83
|
+
"RegisterResponse",
|
|
84
|
+
"RemoteError",
|
|
85
|
+
"ResultItem",
|
|
86
|
+
"ResultKind",
|
|
87
|
+
"ResultRequest",
|
|
88
|
+
"ResultResponse",
|
|
89
|
+
"Score",
|
|
90
|
+
"SessionTranscript",
|
|
91
|
+
"SkippedEval",
|
|
92
|
+
"TerminalRunStatus",
|
|
93
|
+
"TranscriptEvent",
|
|
94
|
+
"UnsupportedProtocolVersion",
|
|
95
|
+
"WorkerConfig",
|
|
96
|
+
"WorkerRuntime",
|
|
97
|
+
"UnsafeEvaluatorSource",
|
|
98
|
+
"compile_condition",
|
|
99
|
+
"compile_evaluator",
|
|
100
|
+
"source_checksum",
|
|
101
|
+
]
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Run an evaluator declared as ``module:attribute``."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import importlib
|
|
7
|
+
import os
|
|
8
|
+
from collections.abc import Sequence
|
|
9
|
+
|
|
10
|
+
from failproofai_sdk.evaluator.authoring import Evaluator
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def load_evaluator(spec: str) -> Evaluator:
|
|
14
|
+
module_name, separator, attribute = spec.partition(":")
|
|
15
|
+
if not module_name:
|
|
16
|
+
raise ValueError("evaluator module must not be empty")
|
|
17
|
+
if not separator:
|
|
18
|
+
attribute = "app"
|
|
19
|
+
if not attribute:
|
|
20
|
+
raise ValueError("evaluator attribute must not be empty")
|
|
21
|
+
module = importlib.import_module(module_name)
|
|
22
|
+
try:
|
|
23
|
+
evaluator = getattr(module, attribute)
|
|
24
|
+
except AttributeError as error:
|
|
25
|
+
raise ValueError(f"{spec!r} does not define {attribute!r}") from error
|
|
26
|
+
if not isinstance(evaluator, Evaluator):
|
|
27
|
+
raise TypeError(
|
|
28
|
+
f"{spec!r} resolved to {type(evaluator).__name__}, not Evaluator"
|
|
29
|
+
)
|
|
30
|
+
return evaluator
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def main(argv: Sequence[str] | None = None) -> int:
|
|
34
|
+
parser = argparse.ArgumentParser(prog="python -m failproofai_sdk.evaluator")
|
|
35
|
+
parser.add_argument(
|
|
36
|
+
"module",
|
|
37
|
+
nargs="?",
|
|
38
|
+
default=os.environ.get("FAILPROOFAI_EVALUATOR_MODULE"),
|
|
39
|
+
help="Python module and optional attribute (for example my_evals:app)",
|
|
40
|
+
)
|
|
41
|
+
args = parser.parse_args(argv)
|
|
42
|
+
if not args.module:
|
|
43
|
+
parser.error("module is required (or set FAILPROOFAI_EVALUATOR_MODULE)")
|
|
44
|
+
load_evaluator(args.module).run_from_env()
|
|
45
|
+
return 0
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
if __name__ == "__main__":
|
|
49
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""Subprocess entry point for the managed-source sandbox.
|
|
2
|
+
|
|
3
|
+
Invoked as ``python -m failproofai_sdk.evaluator._sandbox_runner <input-file>`` by
|
|
4
|
+
``source._run_sandboxed``. The input file holds a pickled
|
|
5
|
+
``(kind, source, session_wire, cpu_seconds, mem_bytes, eval_key)`` tuple. This
|
|
6
|
+
process installs hard ``RLIMIT_CPU`` + ``RLIMIT_AS`` limits ON ITSELF, evaluates
|
|
7
|
+
the re-validated server-authored source against the reconstructed transcript,
|
|
8
|
+
validates + bounds the result, and writes a pickled ``("ok", result)`` /
|
|
9
|
+
``("err", type_name, message)`` outcome to stdout.
|
|
10
|
+
|
|
11
|
+
This is a FRESH exec'd process — never a fork of the multi-threaded worker — so
|
|
12
|
+
there is no inherited-lock deadlock (forking a process that has an asyncio loop,
|
|
13
|
+
an executor pool and a writer daemon hangs the child). The parent enforces the
|
|
14
|
+
wall-clock bound and the output-size bound by reading only so far and killing
|
|
15
|
+
this process on timeout or overflow.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import pickle
|
|
21
|
+
import sys
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _main() -> int:
|
|
25
|
+
with open(sys.argv[1], "rb") as handle:
|
|
26
|
+
kind, source, session_wire, cpu_seconds, mem_bytes, eval_key = pickle.loads(
|
|
27
|
+
handle.read()
|
|
28
|
+
)
|
|
29
|
+
# Imported here, in the child, so the import cost is never on the worker's path.
|
|
30
|
+
from failproofai_sdk.evaluator.protocol import SessionTranscript
|
|
31
|
+
from failproofai_sdk.evaluator.source import (
|
|
32
|
+
SANDBOX_MAX_RESULT_BYTES,
|
|
33
|
+
_install_limits,
|
|
34
|
+
_raw_eval,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
session = SessionTranscript.from_wire(session_wire)
|
|
39
|
+
# Compile + re-validate BEFORE the limits so validation cost is not charged
|
|
40
|
+
# against the eval's CPU budget; the limits bind the eval itself.
|
|
41
|
+
run = _raw_eval(source, kind)
|
|
42
|
+
_install_limits(cpu_seconds, mem_bytes)
|
|
43
|
+
result = run(session)
|
|
44
|
+
# Bound the result INSIDE the sandbox before it crosses back: result_items
|
|
45
|
+
# enforces the 25-result limit + field validation, so a huge result
|
|
46
|
+
# (`metrics={str(x):1 for x in range(100000)}`) raises here instead of
|
|
47
|
+
# being serialized and shipped to the parent.
|
|
48
|
+
if kind == "evaluator":
|
|
49
|
+
result.result_items(eval_key or "result")
|
|
50
|
+
payload = pickle.dumps(("ok", result))
|
|
51
|
+
if len(payload) > SANDBOX_MAX_RESULT_BYTES:
|
|
52
|
+
payload = pickle.dumps(
|
|
53
|
+
("err", "ResultTooLarge", "evaluation result exceeds the size limit")
|
|
54
|
+
)
|
|
55
|
+
except BaseException as error: # noqa: BLE001 - relay type+msg, this process is the boundary
|
|
56
|
+
payload = pickle.dumps(("err", type(error).__name__, str(error)[:500]))
|
|
57
|
+
sys.stdout.buffer.write(payload)
|
|
58
|
+
sys.stdout.buffer.flush()
|
|
59
|
+
return 0
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
if __name__ == "__main__":
|
|
63
|
+
raise SystemExit(_main())
|