agent-learning-kit 0.1.0__py3-none-any.whl

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.
Files changed (642) hide show
  1. agent_learning_kit-0.1.0.dist-info/METADATA +381 -0
  2. agent_learning_kit-0.1.0.dist-info/RECORD +642 -0
  3. agent_learning_kit-0.1.0.dist-info/WHEEL +4 -0
  4. agent_learning_kit-0.1.0.dist-info/entry_points.txt +5 -0
  5. agent_learning_kit-0.1.0.dist-info/licenses/LICENSE +173 -0
  6. agent_learning_kit-0.1.0.dist-info/licenses/NOTICE +7 -0
  7. fi/__init__.py +5 -0
  8. fi/alk/__init__.py +57 -0
  9. fi/alk/_facade.py +31 -0
  10. fi/alk/_module_alias.py +68 -0
  11. fi/alk/_paths.py +14 -0
  12. fi/alk/_schema.py +522 -0
  13. fi/alk/actions.py +727 -0
  14. fi/alk/bench/__init__.py +517 -0
  15. fi/alk/bench/_codeexec.py +213 -0
  16. fi/alk/bench/_coding.py +215 -0
  17. fi/alk/bench/_docker.py +237 -0
  18. fi/alk/bench/_grader.py +286 -0
  19. fi/alk/bench/_pull.py +212 -0
  20. fi/alk/bench/_voice.py +147 -0
  21. fi/alk/capabilities.py +627 -0
  22. fi/alk/cli.py +6396 -0
  23. fi/alk/config.py +130 -0
  24. fi/alk/cua_loop.py +562 -0
  25. fi/alk/evals.py +2351 -0
  26. fi/alk/extensions.py +163 -0
  27. fi/alk/harness/ARCHITECTURE.md +231 -0
  28. fi/alk/harness/DESIGN.md +246 -0
  29. fi/alk/harness/ENVIRONMENT_CONFORMANCE.md +127 -0
  30. fi/alk/harness/HOW-IT-WORKS.md +297 -0
  31. fi/alk/harness/IMPLEMENTATION_AND_VALIDATION_STATUS.md +229 -0
  32. fi/alk/harness/README.md +417 -0
  33. fi/alk/harness/__init__.py +77 -0
  34. fi/alk/harness/__main__.py +3 -0
  35. fi/alk/harness/amend.py +312 -0
  36. fi/alk/harness/artifacts.py +319 -0
  37. fi/alk/harness/authoring_entrypoint.py +189 -0
  38. fi/alk/harness/authoring_runtime_validation.py +267 -0
  39. fi/alk/harness/backends/README.md +43 -0
  40. fi/alk/harness/backends/__init__.py +122 -0
  41. fi/alk/harness/backends/base.py +241 -0
  42. fi/alk/harness/backends/claude.py +211 -0
  43. fi/alk/harness/backends/files.py +182 -0
  44. fi/alk/harness/backends/vertex_gemini.py +457 -0
  45. fi/alk/harness/background_noise.py +95 -0
  46. fi/alk/harness/build.py +385 -0
  47. fi/alk/harness/bundle.py +593 -0
  48. fi/alk/harness/bundle_author_v2.py +1831 -0
  49. fi/alk/harness/bundle_v2.py +719 -0
  50. fi/alk/harness/call_runner.py +1440 -0
  51. fi/alk/harness/callback_http_adapter.py +111 -0
  52. fi/alk/harness/catalogue.py +287 -0
  53. fi/alk/harness/chat.py +428 -0
  54. fi/alk/harness/chat_call_runner.py +506 -0
  55. fi/alk/harness/checks.py +136 -0
  56. fi/alk/harness/cli.py +1354 -0
  57. fi/alk/harness/config.py +338 -0
  58. fi/alk/harness/contract.py +718 -0
  59. fi/alk/harness/credentials.py +674 -0
  60. fi/alk/harness/data/persona_vocabulary.json +111 -0
  61. fi/alk/harness/environment.py +99 -0
  62. fi/alk/harness/environment_plan.py +168 -0
  63. fi/alk/harness/events.py +125 -0
  64. fi/alk/harness/executor.py +304 -0
  65. fi/alk/harness/folder.py +234 -0
  66. fi/alk/harness/generated_runtime.py +815 -0
  67. fi/alk/harness/github.py +72 -0
  68. fi/alk/harness/hosted_authoring_entrypoint.py +183 -0
  69. fi/alk/harness/hosted_entrypoint.py +2402 -0
  70. fi/alk/harness/hosted_scheduler.py +2218 -0
  71. fi/alk/harness/job.py +426 -0
  72. fi/alk/harness/judge.py +184 -0
  73. fi/alk/harness/livekit_source.py +50 -0
  74. fi/alk/harness/livekit_tool_trace_bootstrap.py +71 -0
  75. fi/alk/harness/observability.py +208 -0
  76. fi/alk/harness/outbound.py +3252 -0
  77. fi/alk/harness/packaging.py +515 -0
  78. fi/alk/harness/persona_guides.py +157 -0
  79. fi/alk/harness/platform.py +692 -0
  80. fi/alk/harness/process_preflight.py +764 -0
  81. fi/alk/harness/process_runtime.py +5670 -0
  82. fi/alk/harness/prove.py +425 -0
  83. fi/alk/harness/provider_import.py +703 -0
  84. fi/alk/harness/provider_lifecycle.py +392 -0
  85. fi/alk/harness/provision.py +2896 -0
  86. fi/alk/harness/reception.py +147 -0
  87. fi/alk/harness/retell_chat_call_runner.py +373 -0
  88. fi/alk/harness/run/__init__.py +296 -0
  89. fi/alk/harness/run/alk.py +184 -0
  90. fi/alk/harness/run/call.py +162 -0
  91. fi/alk/harness/run/conversation.py +264 -0
  92. fi/alk/harness/run/data/voices_by_language_and_gender.json +693 -0
  93. fi/alk/harness/run/evidence.py +195 -0
  94. fi/alk/harness/run/grade.py +598 -0
  95. fi/alk/harness/run/live.py +297 -0
  96. fi/alk/harness/run/models.py +56 -0
  97. fi/alk/harness/run/platform_evals.py +227 -0
  98. fi/alk/harness/run/sdk_voice.py +130 -0
  99. fi/alk/harness/run/simulation.py +1209 -0
  100. fi/alk/harness/run/stage.py +91 -0
  101. fi/alk/harness/run/targets.py +508 -0
  102. fi/alk/harness/run/tools.py +601 -0
  103. fi/alk/harness/run/voice.py +340 -0
  104. fi/alk/harness/runtime.py +172 -0
  105. fi/alk/harness/sandbox_server.py +2011 -0
  106. fi/alk/harness/sandbox_worker.py +44 -0
  107. fi/alk/harness/scenario.py +1048 -0
  108. fi/alk/harness/scenario_source.py +879 -0
  109. fi/alk/harness/scenario_tools.py +1143 -0
  110. fi/alk/harness/scenarios.py +915 -0
  111. fi/alk/harness/secrets.py +168 -0
  112. fi/alk/harness/service_catalog.py +97 -0
  113. fi/alk/harness/session.py +391 -0
  114. fi/alk/harness/sessions.py +372 -0
  115. fi/alk/harness/simulator.py +76 -0
  116. fi/alk/harness/simulator_voice.py +928 -0
  117. fi/alk/harness/skills/build-environment/SKILL.md +538 -0
  118. fi/alk/harness/skills/harness.md +131 -0
  119. fi/alk/harness/skills/kinds/chat.md +48 -0
  120. fi/alk/harness/skills/kinds/voice-voicemail.md +63 -0
  121. fi/alk/harness/skills/kinds/voice.md +59 -0
  122. fi/alk/harness/skills/plan-suite/SKILL.md +103 -0
  123. fi/alk/harness/skills/provision-environment/SKILL.md +136 -0
  124. fi/alk/harness/skills/run-scenarios/SKILL.md +112 -0
  125. fi/alk/harness/skills/understand-agent/SKILL.md +251 -0
  126. fi/alk/harness/skills/write-scenarios/SKILL.md +606 -0
  127. fi/alk/harness/skills/write-scenarios/references/refusals.md +28 -0
  128. fi/alk/harness/skills/write-scenarios/references/world-api.md +92 -0
  129. fi/alk/harness/source_data_invariants.py +444 -0
  130. fi/alk/harness/source_tool_evidence.py +79 -0
  131. fi/alk/harness/sources.py +253 -0
  132. fi/alk/harness/spend.py +140 -0
  133. fi/alk/harness/tool_trace_proxy.py +104 -0
  134. fi/alk/harness/tools.py +1018 -0
  135. fi/alk/harness/understand.py +169 -0
  136. fi/alk/harness/voicemail_audio.py +74 -0
  137. fi/alk/harness/world/__init__.py +33 -0
  138. fi/alk/harness/world/errors.py +68 -0
  139. fi/alk/harness/world/expectations.py +91 -0
  140. fi/alk/harness/world/handle.py +538 -0
  141. fi/alk/harness/world/kinds.py +196 -0
  142. fi/alk/harness/world/mutate.py +186 -0
  143. fi/alk/harness/world/probe.py +413 -0
  144. fi/alk/harness/world/provision.py +511 -0
  145. fi/alk/harness/world/provisioned.py +191 -0
  146. fi/alk/harness/world/runtime.py +616 -0
  147. fi/alk/harness/world/snapshot.py +288 -0
  148. fi/alk/harness/world/stores/__init__.py +305 -0
  149. fi/alk/harness/world/stores/container.py +215 -0
  150. fi/alk/harness/world/stores/inprocess.py +346 -0
  151. fi/alk/harness/world/stores/postgres.py +481 -0
  152. fi/alk/harness/world/stores/prove.py +202 -0
  153. fi/alk/harness/world/stores/sqlite.py +245 -0
  154. fi/alk/harness/world/stores/written.py +182 -0
  155. fi/alk/harness/world/tools.py +1516 -0
  156. fi/alk/harness/world/workspace.py +144 -0
  157. fi/alk/image_loop.py +453 -0
  158. fi/alk/image_perturb.py +241 -0
  159. fi/alk/improve.py +274 -0
  160. fi/alk/live/__init__.py +154 -0
  161. fi/alk/live/_attribution.py +184 -0
  162. fi/alk/live/_capture.py +264 -0
  163. fi/alk/live/_codec.py +391 -0
  164. fi/alk/live/_contract.py +134 -0
  165. fi/alk/live/_loopback.py +316 -0
  166. fi/alk/live/_perturb.py +449 -0
  167. fi/alk/live/_runner.py +386 -0
  168. fi/alk/live/_stats.py +561 -0
  169. fi/alk/live/_transcript.py +240 -0
  170. fi/alk/live/_workers/__init__.py +9 -0
  171. fi/alk/live/_workers/a2a_worker.py +316 -0
  172. fi/alk/live/_workers/langgraph_worker.py +217 -0
  173. fi/alk/live/_workers/livekit_worker.py +207 -0
  174. fi/alk/live/_workers/mcp_loopback_server.py +46 -0
  175. fi/alk/live/_workers/mcp_worker.py +158 -0
  176. fi/alk/live/_workers/pipecat_worker.py +189 -0
  177. fi/alk/live/a2a_lane.py +138 -0
  178. fi/alk/live/langgraph_lane.py +339 -0
  179. fi/alk/live/livekit_lane.py +376 -0
  180. fi/alk/live/mcp_lane.py +172 -0
  181. fi/alk/live/pipecat_lane.py +341 -0
  182. fi/alk/live/voice_redteam.py +494 -0
  183. fi/alk/loss.py +306 -0
  184. fi/alk/optimize.py +36260 -0
  185. fi/alk/practice/__init__.py +51 -0
  186. fi/alk/practice/_assess.py +103 -0
  187. fi/alk/practice/_budget.py +81 -0
  188. fi/alk/practice/_calibrate.py +69 -0
  189. fi/alk/practice/_capstone.py +86 -0
  190. fi/alk/practice/_contract.py +91 -0
  191. fi/alk/practice/_diagnose.py +79 -0
  192. fi/alk/practice/_drill.py +196 -0
  193. fi/alk/practice/_experiment.py +720 -0
  194. fi/alk/practice/_schedule.py +102 -0
  195. fi/alk/practice/_store.py +194 -0
  196. fi/alk/practice/_trainer.py +245 -0
  197. fi/alk/practice/_update.py +125 -0
  198. fi/alk/redteam.py +2621 -0
  199. fi/alk/rewardhack.py +237 -0
  200. fi/alk/simulate.py +10351 -0
  201. fi/alk/studio/__init__.py +82 -0
  202. fi/alk/studio/_bias.py +314 -0
  203. fi/alk/studio/_calibration.py +522 -0
  204. fi/alk/studio/_coverage.py +262 -0
  205. fi/alk/studio/_download.py +665 -0
  206. fi/alk/studio/_fidelity_attack.py +114 -0
  207. fi/alk/studio/_generate.py +652 -0
  208. fi/alk/studio/_library.py +370 -0
  209. fi/alk/studio/_scan.py +134 -0
  210. fi/alk/studio/_upgrade.py +42 -0
  211. fi/alk/studio/_vendor.py +172 -0
  212. fi/alk/suite.py +4200 -0
  213. fi/alk/tasks.py +828 -0
  214. fi/alk/telemetry/__init__.py +149 -0
  215. fi/alk/telemetry/_contract.py +141 -0
  216. fi/alk/telemetry/_emit.py +182 -0
  217. fi/alk/telemetry/_ledger.py +296 -0
  218. fi/alk/telemetry/_queue.py +127 -0
  219. fi/alk/telemetry/_row.py +294 -0
  220. fi/alk/telemetry/_run.py +233 -0
  221. fi/alk/telemetry/_sync.py +193 -0
  222. fi/alk/telemetry/_url.py +119 -0
  223. fi/alk/trinity.py +49397 -0
  224. fi/alk/voice_loop.py +174 -0
  225. fi/api/__init__.py +1 -0
  226. fi/api/auth.py +137 -0
  227. fi/api/types.py +29 -0
  228. fi/cli/__init__.py +9 -0
  229. fi/cli/assertions/__init__.py +25 -0
  230. fi/cli/assertions/conditions.py +76 -0
  231. fi/cli/assertions/evaluator.py +286 -0
  232. fi/cli/assertions/exit_codes.py +20 -0
  233. fi/cli/assertions/parser.py +131 -0
  234. fi/cli/assertions/reporter.py +194 -0
  235. fi/cli/commands/__init__.py +9 -0
  236. fi/cli/commands/config.py +165 -0
  237. fi/cli/commands/export.py +208 -0
  238. fi/cli/commands/init.py +112 -0
  239. fi/cli/commands/list_cmd.py +213 -0
  240. fi/cli/commands/run.py +486 -0
  241. fi/cli/commands/validate.py +173 -0
  242. fi/cli/commands/view.py +424 -0
  243. fi/cli/config/__init__.py +6 -0
  244. fi/cli/config/defaults.py +206 -0
  245. fi/cli/config/loader.py +155 -0
  246. fi/cli/config/schema.py +174 -0
  247. fi/cli/main.py +78 -0
  248. fi/cli/output/__init__.py +6 -0
  249. fi/cli/output/formatters.py +106 -0
  250. fi/cli/output/reporters.py +46 -0
  251. fi/cli/storage/__init__.py +5 -0
  252. fi/cli/storage/run_history.py +249 -0
  253. fi/cli/utils/__init__.py +5 -0
  254. fi/cli/utils/console.py +44 -0
  255. fi/evals/__init__.py +131 -0
  256. fi/evals/autoeval/__init__.py +137 -0
  257. fi/evals/autoeval/analyzer.py +211 -0
  258. fi/evals/autoeval/config.py +244 -0
  259. fi/evals/autoeval/export.py +213 -0
  260. fi/evals/autoeval/interactive.py +283 -0
  261. fi/evals/autoeval/pipeline.py +625 -0
  262. fi/evals/autoeval/prompts.py +139 -0
  263. fi/evals/autoeval/recommender.py +242 -0
  264. fi/evals/autoeval/rules.py +589 -0
  265. fi/evals/autoeval/templates.py +299 -0
  266. fi/evals/autoeval/types.py +232 -0
  267. fi/evals/core/__init__.py +16 -0
  268. fi/evals/core/cloud_registry.py +184 -0
  269. fi/evals/core/engines.py +368 -0
  270. fi/evals/core/evaluate.py +319 -0
  271. fi/evals/core/judge_prompt.py +90 -0
  272. fi/evals/core/prompt_generator.py +83 -0
  273. fi/evals/core/registry.py +57 -0
  274. fi/evals/core/result.py +55 -0
  275. fi/evals/evaluator.py +721 -0
  276. fi/evals/execution.py +168 -0
  277. fi/evals/feedback/__init__.py +32 -0
  278. fi/evals/feedback/calibrator.py +160 -0
  279. fi/evals/feedback/collector.py +214 -0
  280. fi/evals/feedback/hooks.py +81 -0
  281. fi/evals/feedback/retriever.py +128 -0
  282. fi/evals/feedback/store.py +272 -0
  283. fi/evals/feedback/types.py +99 -0
  284. fi/evals/framework/README.md +79 -0
  285. fi/evals/framework/__init__.py +267 -0
  286. fi/evals/framework/backends/Dockerfile.eval-runner +33 -0
  287. fi/evals/framework/backends/__init__.py +99 -0
  288. fi/evals/framework/backends/_container.py +141 -0
  289. fi/evals/framework/backends/_utils.py +145 -0
  290. fi/evals/framework/backends/base.py +223 -0
  291. fi/evals/framework/backends/celery_backend.py +417 -0
  292. fi/evals/framework/backends/celery_worker.py +78 -0
  293. fi/evals/framework/backends/kubernetes_backend.py +665 -0
  294. fi/evals/framework/backends/ray_backend.py +521 -0
  295. fi/evals/framework/backends/temporal.py +350 -0
  296. fi/evals/framework/backends/temporal_worker.py +126 -0
  297. fi/evals/framework/backends/thread_pool.py +286 -0
  298. fi/evals/framework/context.py +258 -0
  299. fi/evals/framework/enrichment.py +306 -0
  300. fi/evals/framework/evals/__init__.py +68 -0
  301. fi/evals/framework/evals/agentic.py +399 -0
  302. fi/evals/framework/evals/builder.py +609 -0
  303. fi/evals/framework/evals/semantic.py +142 -0
  304. fi/evals/framework/evaluator.py +647 -0
  305. fi/evals/framework/evaluators/__init__.py +22 -0
  306. fi/evals/framework/evaluators/blocking.py +347 -0
  307. fi/evals/framework/evaluators/non_blocking.py +577 -0
  308. fi/evals/framework/propagation.py +421 -0
  309. fi/evals/framework/protocols.py +385 -0
  310. fi/evals/framework/registry.py +370 -0
  311. fi/evals/framework/resilience/__init__.py +150 -0
  312. fi/evals/framework/resilience/circuit_breaker.py +309 -0
  313. fi/evals/framework/resilience/degradation.py +355 -0
  314. fi/evals/framework/resilience/health.py +505 -0
  315. fi/evals/framework/resilience/rate_limiter.py +228 -0
  316. fi/evals/framework/resilience/retry.py +274 -0
  317. fi/evals/framework/resilience/types.py +288 -0
  318. fi/evals/framework/resilience/wrapper.py +433 -0
  319. fi/evals/framework/types.py +218 -0
  320. fi/evals/guardrails/README.md +915 -0
  321. fi/evals/guardrails/__init__.py +96 -0
  322. fi/evals/guardrails/backends/__init__.py +43 -0
  323. fi/evals/guardrails/backends/azure.py +361 -0
  324. fi/evals/guardrails/backends/base.py +88 -0
  325. fi/evals/guardrails/backends/generic_llm.py +163 -0
  326. fi/evals/guardrails/backends/granite.py +216 -0
  327. fi/evals/guardrails/backends/llamaguard.py +221 -0
  328. fi/evals/guardrails/backends/local_base.py +479 -0
  329. fi/evals/guardrails/backends/openai.py +365 -0
  330. fi/evals/guardrails/backends/qwen.py +170 -0
  331. fi/evals/guardrails/backends/shieldgemma.py +154 -0
  332. fi/evals/guardrails/backends/turing.py +235 -0
  333. fi/evals/guardrails/backends/vllm_client.py +321 -0
  334. fi/evals/guardrails/backends/wildguard.py +188 -0
  335. fi/evals/guardrails/base.py +888 -0
  336. fi/evals/guardrails/config.py +221 -0
  337. fi/evals/guardrails/discovery.py +243 -0
  338. fi/evals/guardrails/gateway.py +437 -0
  339. fi/evals/guardrails/registry.py +231 -0
  340. fi/evals/guardrails/scanners/__init__.py +127 -0
  341. fi/evals/guardrails/scanners/base.py +191 -0
  342. fi/evals/guardrails/scanners/code_injection.py +243 -0
  343. fi/evals/guardrails/scanners/eval_delegate.py +574 -0
  344. fi/evals/guardrails/scanners/invisible_chars.py +351 -0
  345. fi/evals/guardrails/scanners/jailbreak.py +412 -0
  346. fi/evals/guardrails/scanners/language.py +288 -0
  347. fi/evals/guardrails/scanners/pipeline.py +260 -0
  348. fi/evals/guardrails/scanners/regex.py +311 -0
  349. fi/evals/guardrails/scanners/secrets.py +274 -0
  350. fi/evals/guardrails/scanners/topics.py +649 -0
  351. fi/evals/guardrails/scanners/urls.py +341 -0
  352. fi/evals/guardrails/types.py +96 -0
  353. fi/evals/llm/__init__.py +3 -0
  354. fi/evals/llm/base_llm_provider.py +35 -0
  355. fi/evals/llm/providers/litellm.py +70 -0
  356. fi/evals/local/__init__.py +90 -0
  357. fi/evals/local/evaluator.py +690 -0
  358. fi/evals/local/execution_mode.py +121 -0
  359. fi/evals/local/llm.py +489 -0
  360. fi/evals/local/metrics/__init__.py +19 -0
  361. fi/evals/local/registry.py +360 -0
  362. fi/evals/manager.py +1018 -0
  363. fi/evals/manager_types.py +362 -0
  364. fi/evals/metrics/__init__.py +185 -0
  365. fi/evals/metrics/agents/__init__.py +74 -0
  366. fi/evals/metrics/agents/metrics.py +693 -0
  367. fi/evals/metrics/agents/report.py +36463 -0
  368. fi/evals/metrics/agents/types.py +160 -0
  369. fi/evals/metrics/base_llm_metric.py +111 -0
  370. fi/evals/metrics/base_metric.py +138 -0
  371. fi/evals/metrics/code_security/__init__.py +305 -0
  372. fi/evals/metrics/code_security/analyzer.py +985 -0
  373. fi/evals/metrics/code_security/benchmarks/__init__.py +73 -0
  374. fi/evals/metrics/code_security/benchmarks/builtin.py +750 -0
  375. fi/evals/metrics/code_security/benchmarks/loader.py +580 -0
  376. fi/evals/metrics/code_security/benchmarks/types.py +308 -0
  377. fi/evals/metrics/code_security/detectors/__init__.py +186 -0
  378. fi/evals/metrics/code_security/detectors/base.py +394 -0
  379. fi/evals/metrics/code_security/detectors/cryptography.py +345 -0
  380. fi/evals/metrics/code_security/detectors/injection.py +744 -0
  381. fi/evals/metrics/code_security/detectors/secrets.py +287 -0
  382. fi/evals/metrics/code_security/detectors/serialization.py +192 -0
  383. fi/evals/metrics/code_security/joint_metrics.py +588 -0
  384. fi/evals/metrics/code_security/judges/__init__.py +83 -0
  385. fi/evals/metrics/code_security/judges/base.py +238 -0
  386. fi/evals/metrics/code_security/judges/dual_judge.py +534 -0
  387. fi/evals/metrics/code_security/judges/llm_judge.py +301 -0
  388. fi/evals/metrics/code_security/judges/pattern_judge.py +515 -0
  389. fi/evals/metrics/code_security/metrics.py +388 -0
  390. fi/evals/metrics/code_security/modes/__init__.py +63 -0
  391. fi/evals/metrics/code_security/modes/adversarial.py +284 -0
  392. fi/evals/metrics/code_security/modes/autocomplete.py +198 -0
  393. fi/evals/metrics/code_security/modes/base.py +283 -0
  394. fi/evals/metrics/code_security/modes/instruct.py +253 -0
  395. fi/evals/metrics/code_security/modes/repair.py +230 -0
  396. fi/evals/metrics/code_security/reports/__init__.py +57 -0
  397. fi/evals/metrics/code_security/reports/generator.py +404 -0
  398. fi/evals/metrics/code_security/reports/leaderboard.py +509 -0
  399. fi/evals/metrics/code_security/types.py +534 -0
  400. fi/evals/metrics/function_calling/__init__.py +34 -0
  401. fi/evals/metrics/function_calling/metrics.py +573 -0
  402. fi/evals/metrics/function_calling/types.py +87 -0
  403. fi/evals/metrics/hallucination/__init__.py +54 -0
  404. fi/evals/metrics/hallucination/detector.py +149 -0
  405. fi/evals/metrics/hallucination/metrics.py +390 -0
  406. fi/evals/metrics/hallucination/nli.py +253 -0
  407. fi/evals/metrics/hallucination/sentinel.py +106 -0
  408. fi/evals/metrics/hallucination/types.py +132 -0
  409. fi/evals/metrics/heuristics/aggregation_metrics.py +85 -0
  410. fi/evals/metrics/heuristics/json_metrics.py +87 -0
  411. fi/evals/metrics/heuristics/similarity_metrics.py +375 -0
  412. fi/evals/metrics/heuristics/string_metrics.py +391 -0
  413. fi/evals/metrics/llm_as_judges/__init__.py +17 -0
  414. fi/evals/metrics/llm_as_judges/custom_judge/metric.py +112 -0
  415. fi/evals/metrics/llm_as_judges/custom_judge/prompts.py +26 -0
  416. fi/evals/metrics/llm_as_judges/types.py +48 -0
  417. fi/evals/metrics/rag/__init__.py +111 -0
  418. fi/evals/metrics/rag/advanced/__init__.py +14 -0
  419. fi/evals/metrics/rag/advanced/multi_hop.py +283 -0
  420. fi/evals/metrics/rag/advanced/source_attribution.py +344 -0
  421. fi/evals/metrics/rag/generation/__init__.py +17 -0
  422. fi/evals/metrics/rag/generation/answer_relevancy.py +176 -0
  423. fi/evals/metrics/rag/generation/context_utilization.py +245 -0
  424. fi/evals/metrics/rag/generation/faithfulness.py +241 -0
  425. fi/evals/metrics/rag/generation/groundedness.py +131 -0
  426. fi/evals/metrics/rag/rag_score.py +277 -0
  427. fi/evals/metrics/rag/retrieval/__init__.py +20 -0
  428. fi/evals/metrics/rag/retrieval/context_entity_recall.py +124 -0
  429. fi/evals/metrics/rag/retrieval/context_precision.py +158 -0
  430. fi/evals/metrics/rag/retrieval/context_recall.py +106 -0
  431. fi/evals/metrics/rag/retrieval/noise_sensitivity.py +163 -0
  432. fi/evals/metrics/rag/retrieval/ranking.py +261 -0
  433. fi/evals/metrics/rag/types.py +100 -0
  434. fi/evals/metrics/rag/utils/__init__.py +62 -0
  435. fi/evals/metrics/rag/utils/claims.py +189 -0
  436. fi/evals/metrics/rag/utils/entities.py +244 -0
  437. fi/evals/metrics/rag/utils/nli.py +92 -0
  438. fi/evals/metrics/rag/utils/similarity.py +345 -0
  439. fi/evals/metrics/structured/__init__.py +114 -0
  440. fi/evals/metrics/structured/field_completeness.py +313 -0
  441. fi/evals/metrics/structured/hierarchy_score.py +366 -0
  442. fi/evals/metrics/structured/json_validation.py +190 -0
  443. fi/evals/metrics/structured/schema_compliance.py +280 -0
  444. fi/evals/metrics/structured/structured_output_score.py +298 -0
  445. fi/evals/metrics/structured/types.py +108 -0
  446. fi/evals/metrics/structured/validators/__init__.py +30 -0
  447. fi/evals/metrics/structured/validators/base.py +189 -0
  448. fi/evals/metrics/structured/validators/json_validator.py +196 -0
  449. fi/evals/metrics/structured/validators/pydantic_validator.py +178 -0
  450. fi/evals/metrics/structured/validators/yaml_validator.py +248 -0
  451. fi/evals/otel/__init__.py +266 -0
  452. fi/evals/otel/config.py +400 -0
  453. fi/evals/otel/conventions.py +463 -0
  454. fi/evals/otel/enrichment.py +371 -0
  455. fi/evals/otel/instrumentors/__init__.py +140 -0
  456. fi/evals/otel/instrumentors/anthropic.py +517 -0
  457. fi/evals/otel/instrumentors/base.py +382 -0
  458. fi/evals/otel/instrumentors/openai.py +673 -0
  459. fi/evals/otel/processors/__init__.py +36 -0
  460. fi/evals/otel/processors/base.py +473 -0
  461. fi/evals/otel/processors/cost.py +445 -0
  462. fi/evals/otel/processors/evaluation.py +559 -0
  463. fi/evals/otel/processors/llm.py +462 -0
  464. fi/evals/otel/tracer.py +506 -0
  465. fi/evals/otel/types.py +232 -0
  466. fi/evals/otel_utils.py +23 -0
  467. fi/evals/protect.py +671 -0
  468. fi/evals/protect_input_adapter.py +154 -0
  469. fi/evals/streaming/__init__.py +88 -0
  470. fi/evals/streaming/buffer.py +213 -0
  471. fi/evals/streaming/evaluator.py +551 -0
  472. fi/evals/streaming/policy.py +307 -0
  473. fi/evals/streaming/scorers.py +368 -0
  474. fi/evals/streaming/types.py +238 -0
  475. fi/evals/templates.py +472 -0
  476. fi/evals/types.py +156 -0
  477. fi/opt/__init__.py +221 -0
  478. fi/opt/_objective_scoring.py +85 -0
  479. fi/opt/base/__init__.py +11 -0
  480. fi/opt/base/base_generator.py +33 -0
  481. fi/opt/base/base_mapper.py +26 -0
  482. fi/opt/base/base_optimizer.py +45 -0
  483. fi/opt/base/evaluator.py +211 -0
  484. fi/opt/components.py +3095 -0
  485. fi/opt/datamappers/__init__.py +3 -0
  486. fi/opt/datamappers/basic_mapper.py +40 -0
  487. fi/opt/deployment.py +1021 -0
  488. fi/opt/evidence.py +4332 -0
  489. fi/opt/generators/__init__.py +3 -0
  490. fi/opt/generators/litellm.py +66 -0
  491. fi/opt/integrations/__init__.py +23 -0
  492. fi/opt/integrations/generative_suite.py +410 -0
  493. fi/opt/integrations/simulate.py +1313 -0
  494. fi/opt/mutations.py +771 -0
  495. fi/opt/observability.py +4639 -0
  496. fi/opt/optimizer_trace.py +889 -0
  497. fi/opt/optimizers/__init__.py +80 -0
  498. fi/opt/optimizers/agent.py +331 -0
  499. fi/opt/optimizers/agent_bandit.py +392 -0
  500. fi/opt/optimizers/agent_curriculum.py +635 -0
  501. fi/opt/optimizers/agent_evolution.py +894 -0
  502. fi/opt/optimizers/agent_feedback.py +1863 -0
  503. fi/opt/optimizers/agent_pareto.py +547 -0
  504. fi/opt/optimizers/agent_social_memory.py +1113 -0
  505. fi/opt/optimizers/agent_tpe.py +321 -0
  506. fi/opt/optimizers/bayesian_search.py +449 -0
  507. fi/opt/optimizers/council.py +2075 -0
  508. fi/opt/optimizers/futureagi_replay.py +799 -0
  509. fi/opt/optimizers/gepa.py +322 -0
  510. fi/opt/optimizers/metaprompt.py +243 -0
  511. fi/opt/optimizers/promptwizard.py +417 -0
  512. fi/opt/optimizers/protegi.py +329 -0
  513. fi/opt/optimizers/random_search.py +224 -0
  514. fi/opt/research.py +518 -0
  515. fi/opt/simulation.py +260 -0
  516. fi/opt/targets.py +232 -0
  517. fi/opt/types.py +66 -0
  518. fi/opt/utils/__init__.py +4 -0
  519. fi/opt/utils/early_stopping.py +266 -0
  520. fi/opt/utils/setup_logging.py +82 -0
  521. fi/simulate/__init__.py +540 -0
  522. fi/simulate/_hashing.py +35 -0
  523. fi/simulate/_logging.py +10 -0
  524. fi/simulate/adapters.py +87 -0
  525. fi/simulate/agent/__init__.py +120 -0
  526. fi/simulate/agent/browser.py +658 -0
  527. fi/simulate/agent/definition.py +587 -0
  528. fi/simulate/agent/frameworks.py +3528 -0
  529. fi/simulate/agent/generic.py +8286 -0
  530. fi/simulate/agent/import_probe.py +227 -0
  531. fi/simulate/agent/memory.py +905 -0
  532. fi/simulate/agent/mocks.py +101 -0
  533. fi/simulate/agent/multi_agent.py +361 -0
  534. fi/simulate/agent/orchestration.py +903 -0
  535. fi/simulate/agent/realtime.py +665 -0
  536. fi/simulate/agent/wrapper.py +99 -0
  537. fi/simulate/agent/wrappers/__init__.py +18 -0
  538. fi/simulate/agent/wrappers/anthropic.py +62 -0
  539. fi/simulate/agent/wrappers/gemini.py +65 -0
  540. fi/simulate/agent/wrappers/http.py +404 -0
  541. fi/simulate/agent/wrappers/langchain.py +80 -0
  542. fi/simulate/agent/wrappers/openai.py +75 -0
  543. fi/simulate/agent/wrappers/websocket.py +326 -0
  544. fi/simulate/artifacts/__init__.py +11 -0
  545. fi/simulate/artifacts/manifest.py +62 -0
  546. fi/simulate/cli.py +20560 -0
  547. fi/simulate/endpoints/__init__.py +45 -0
  548. fi/simulate/endpoints/_http_actor.py +73 -0
  549. fi/simulate/endpoints/actor_sources.py +243 -0
  550. fi/simulate/endpoints/base.py +107 -0
  551. fi/simulate/endpoints/builtins.py +10 -0
  552. fi/simulate/endpoints/callable.py +95 -0
  553. fi/simulate/endpoints/http.py +76 -0
  554. fi/simulate/endpoints/livekit.py +138 -0
  555. fi/simulate/endpoints/originators.py +132 -0
  556. fi/simulate/endpoints/profiles.py +348 -0
  557. fi/simulate/endpoints/retell.py +633 -0
  558. fi/simulate/endpoints/vapi.py +205 -0
  559. fi/simulate/endpoints/websocket.py +76 -0
  560. fi/simulate/environment.py +33026 -0
  561. fi/simulate/environments/__init__.py +11 -0
  562. fi/simulate/environments/base.py +73 -0
  563. fi/simulate/environments/chat.py +697 -0
  564. fi/simulate/environments/voice.py +212 -0
  565. fi/simulate/evaluation/__init__.py +4 -0
  566. fi/simulate/evaluation/ai_eval.py +227 -0
  567. fi/simulate/evidence/__init__.py +35 -0
  568. fi/simulate/evidence/base.py +59 -0
  569. fi/simulate/evidence/caller_observed.py +50 -0
  570. fi/simulate/evidence/livekit_instrumentation.py +51 -0
  571. fi/simulate/evidence/livekit_room.py +50 -0
  572. fi/simulate/evidence/otel.py +49 -0
  573. fi/simulate/evidence/providers/__init__.py +24 -0
  574. fi/simulate/evidence/providers/base.py +61 -0
  575. fi/simulate/evidence/providers/retell.py +376 -0
  576. fi/simulate/evidence/providers/vapi.py +426 -0
  577. fi/simulate/hosted/__init__.py +32 -0
  578. fi/simulate/hosted/child_entrypoint.py +306 -0
  579. fi/simulate/hosted/job.py +150 -0
  580. fi/simulate/hosted/targets.py +53 -0
  581. fi/simulate/instrumentation/__init__.py +5 -0
  582. fi/simulate/instrumentation/livekit/__init__.py +122 -0
  583. fi/simulate/manifest.py +1033 -0
  584. fi/simulate/matrix_cli.py +165 -0
  585. fi/simulate/realtime/__init__.py +40 -0
  586. fi/simulate/realtime/events.py +107 -0
  587. fi/simulate/realtime/media.py +61 -0
  588. fi/simulate/realtime/session.py +91 -0
  589. fi/simulate/recording/__init__.py +5 -0
  590. fi/simulate/recording/room_recorder.py +326 -0
  591. fi/simulate/registry.py +185 -0
  592. fi/simulate/results/__init__.py +9 -0
  593. fi/simulate/results/base.py +18 -0
  594. fi/simulate/results/filesystem.py +71 -0
  595. fi/simulate/results/futureagi.py +1340 -0
  596. fi/simulate/runtime/__init__.py +85 -0
  597. fi/simulate/runtime/capabilities.py +40 -0
  598. fi/simulate/runtime/events.py +63 -0
  599. fi/simulate/runtime/failures.py +25 -0
  600. fi/simulate/runtime/ids.py +34 -0
  601. fi/simulate/runtime/plan.py +70 -0
  602. fi/simulate/runtime/planner.py +102 -0
  603. fi/simulate/runtime/report.py +174 -0
  604. fi/simulate/runtime/run.py +75 -0
  605. fi/simulate/runtime/runner.py +333 -0
  606. fi/simulate/runtime/spec.py +186 -0
  607. fi/simulate/simulation/__init__.py +30 -0
  608. fi/simulate/simulation/behavior_policy.py +425 -0
  609. fi/simulate/simulation/bridge/__init__.py +9 -0
  610. fi/simulate/simulation/bridge/audio.py +29 -0
  611. fi/simulate/simulation/bridge/connector.py +46 -0
  612. fi/simulate/simulation/bridge/livekit.py +252 -0
  613. fi/simulate/simulation/bridge/retell.py +188 -0
  614. fi/simulate/simulation/bridge/vapi.py +177 -0
  615. fi/simulate/simulation/contract.py +419 -0
  616. fi/simulate/simulation/engines/__init__.py +12 -0
  617. fi/simulate/simulation/engines/base.py +21 -0
  618. fi/simulate/simulation/engines/cloud.py +517 -0
  619. fi/simulate/simulation/engines/livekit.py +4167 -0
  620. fi/simulate/simulation/engines/local_text.py +89 -0
  621. fi/simulate/simulation/fidelity.py +374 -0
  622. fi/simulate/simulation/gemini_tts_stream.py +110 -0
  623. fi/simulate/simulation/generator.py +91 -0
  624. fi/simulate/simulation/goal_machine.py +185 -0
  625. fi/simulate/simulation/livekit_models.py +467 -0
  626. fi/simulate/simulation/matrix.py +170 -0
  627. fi/simulate/simulation/models.py +279 -0
  628. fi/simulate/simulation/runner.py +153 -0
  629. fi/simulate/simulation/synthetic.py +880 -0
  630. fi/simulate/simulation/voice_prompt.py +502 -0
  631. fi/simulate/simulator/__init__.py +55 -0
  632. fi/simulate/simulator/builtins.py +53 -0
  633. fi/simulate/suite.py +1288 -0
  634. fi/simulate/utils/routes.py +164 -0
  635. fi/simulate/voice.py +225 -0
  636. fi/simulate/voice_cli.py +182 -0
  637. fi/utils/__init__.py +1 -0
  638. fi/utils/constants.py +14 -0
  639. fi/utils/errors.py +200 -0
  640. fi/utils/executor.py +26 -0
  641. fi/utils/routes.py +119 -0
  642. fi/utils/utils.py +17 -0
@@ -0,0 +1,96 @@
1
+ """
2
+ Guardrails — content screening for AI applications.
3
+
4
+ Screen user input, LLM output, and RAG chunks for safety threats
5
+ using scanners (fast, local, no API keys) and model backends
6
+ (Turing, OpenAI, Azure, or local models via VLLM/HuggingFace).
7
+
8
+ Quick Start — Scanners Only (no API keys needed):
9
+ from fi.evals.guardrails.scanners import (
10
+ ScannerPipeline, JailbreakScanner, CodeInjectionScanner, SecretsScanner,
11
+ )
12
+
13
+ pipeline = ScannerPipeline([
14
+ JailbreakScanner(),
15
+ CodeInjectionScanner(),
16
+ SecretsScanner(),
17
+ ])
18
+ result = pipeline.scan("user input here")
19
+ if not result.passed:
20
+ print(f"Blocked: {result.blocked_by}")
21
+
22
+ Full Guardrails (with model backend):
23
+ from fi.evals.guardrails import Guardrails, GuardrailsConfig, GuardrailModel
24
+
25
+ guardrails = Guardrails(
26
+ config=GuardrailsConfig(models=[GuardrailModel.OPENAI_MODERATION])
27
+ )
28
+ result = guardrails.screen_input("user message")
29
+
30
+ Ensemble with Weighted Voting:
31
+ from fi.evals.guardrails import (
32
+ Guardrails, GuardrailsConfig, GuardrailModel, AggregationStrategy,
33
+ )
34
+
35
+ config = GuardrailsConfig(
36
+ models=[GuardrailModel.TURING_FLASH, GuardrailModel.OPENAI_MODERATION],
37
+ aggregation=AggregationStrategy.WEIGHTED,
38
+ model_weights={"turing_flash": 2.0, "openai-moderation": 1.0},
39
+ )
40
+ guardrails = Guardrails(config=config)
41
+ """
42
+
43
+ # Config classes (always available — no external dependencies)
44
+ from fi.evals.guardrails.config import (
45
+ GuardrailModel,
46
+ RailType,
47
+ AggregationStrategy,
48
+ SafetyCategory,
49
+ GuardrailsConfig,
50
+ ScannerConfig,
51
+ TopicConfig,
52
+ LanguageConfig,
53
+ RegexPatternConfig,
54
+ )
55
+ from fi.evals.guardrails.types import (
56
+ GuardrailResult,
57
+ GuardrailsResponse,
58
+ )
59
+
60
+ # Optional imports that depend on fi.api (backends, etc.)
61
+ _full_api_available = False
62
+ try:
63
+ from fi.evals.guardrails.base import Guardrails
64
+ from fi.evals.guardrails.gateway import (
65
+ GuardrailsGateway,
66
+ ScreeningSession,
67
+ AsyncScreeningSession,
68
+ )
69
+ _full_api_available = True
70
+ except (ImportError, ModuleNotFoundError):
71
+ Guardrails = None
72
+ GuardrailsGateway = None
73
+ ScreeningSession = None
74
+ AsyncScreeningSession = None
75
+
76
+ __all__ = [
77
+ # Main class
78
+ "Guardrails",
79
+ # Configuration
80
+ "GuardrailsConfig",
81
+ "GuardrailModel",
82
+ "RailType",
83
+ "AggregationStrategy",
84
+ "SafetyCategory",
85
+ "ScannerConfig",
86
+ "TopicConfig",
87
+ "LanguageConfig",
88
+ "RegexPatternConfig",
89
+ # Response types
90
+ "GuardrailResult",
91
+ "GuardrailsResponse",
92
+ # Gateway
93
+ "GuardrailsGateway",
94
+ "ScreeningSession",
95
+ "AsyncScreeningSession",
96
+ ]
@@ -0,0 +1,43 @@
1
+ """
2
+ Guardrails Backends — model-based content screening.
3
+
4
+ Users normally don't import backends directly. Instead, configure via
5
+ GuardrailModel enum in GuardrailsConfig and let the registry handle
6
+ instantiation.
7
+
8
+ For custom backends, subclass BaseBackend or LocalModelBackend.
9
+ """
10
+
11
+ from fi.evals.guardrails.backends.base import BaseBackend
12
+ from fi.evals.guardrails.backends.turing import TuringBackend
13
+
14
+ # API backends
15
+ from fi.evals.guardrails.backends.openai import OpenAIBackend
16
+ from fi.evals.guardrails.backends.azure import AzureBackend
17
+
18
+ # Local model base (for custom backends)
19
+ from fi.evals.guardrails.backends.local_base import LocalModelBackend
20
+
21
+ # Local model backends
22
+ from fi.evals.guardrails.backends.wildguard import WildGuardBackend
23
+ from fi.evals.guardrails.backends.llamaguard import LlamaGuardBackend
24
+ from fi.evals.guardrails.backends.granite import GraniteGuardianBackend
25
+ from fi.evals.guardrails.backends.qwen import Qwen3GuardBackend
26
+ from fi.evals.guardrails.backends.shieldgemma import ShieldGemmaBackend
27
+ from fi.evals.guardrails.backends.generic_llm import GenericLLMGuardBackend
28
+
29
+ __all__ = [
30
+ # Base classes (for extension)
31
+ "BaseBackend",
32
+ "LocalModelBackend",
33
+ # Backends
34
+ "TuringBackend",
35
+ "OpenAIBackend",
36
+ "AzureBackend",
37
+ "WildGuardBackend",
38
+ "LlamaGuardBackend",
39
+ "GraniteGuardianBackend",
40
+ "Qwen3GuardBackend",
41
+ "ShieldGemmaBackend",
42
+ "GenericLLMGuardBackend",
43
+ ]
@@ -0,0 +1,361 @@
1
+ """
2
+ Azure Content Safety Backend for Guardrails.
3
+
4
+ Uses Azure AI Content Safety API for content screening.
5
+ Supports 4 categories with severity levels 0-7.
6
+
7
+ Docs: https://learn.microsoft.com/en-us/azure/ai-services/content-safety/
8
+ """
9
+
10
+ import os
11
+ import time
12
+ from typing import Any, Dict, List, Optional
13
+
14
+ from fi.evals.guardrails.backends.base import BaseBackend
15
+ from fi.evals.guardrails.config import GuardrailModel, RailType
16
+ from fi.evals.guardrails.types import GuardrailResult
17
+
18
+
19
+ # Category mapping from Azure to our standard categories
20
+ AZURE_CATEGORY_MAP = {
21
+ "Hate": "hate_speech",
22
+ "SelfHarm": "self_harm",
23
+ "Sexual": "sexual_content",
24
+ "Violence": "violence",
25
+ }
26
+
27
+ # Severity level to score mapping (0-7 to 0-1)
28
+ SEVERITY_TO_SCORE = {
29
+ 0: 0.0,
30
+ 1: 0.14,
31
+ 2: 0.29,
32
+ 3: 0.43,
33
+ 4: 0.57,
34
+ 5: 0.71,
35
+ 6: 0.86,
36
+ 7: 1.0,
37
+ }
38
+
39
+
40
+ class AzureBackend(BaseBackend):
41
+ """
42
+ Azure Content Safety API backend.
43
+
44
+ Uses Azure AI Content Safety for content moderation.
45
+ Supports 4 categories: Hate, SelfHarm, Sexual, Violence.
46
+ Each category has severity levels from 0 (safe) to 7 (severe).
47
+
48
+ Usage:
49
+ backend = AzureBackend(
50
+ model=GuardrailModel.AZURE_CONTENT_SAFETY,
51
+ endpoint="https://your-resource.cognitiveservices.azure.com/",
52
+ api_key="your-key" # or set AZURE_CONTENT_SAFETY_KEY env var
53
+ )
54
+ results = backend.classify("some content", RailType.INPUT)
55
+
56
+ Environment Variables:
57
+ AZURE_CONTENT_SAFETY_ENDPOINT: Azure endpoint URL
58
+ AZURE_CONTENT_SAFETY_KEY: Azure API key
59
+ """
60
+
61
+ def __init__(
62
+ self,
63
+ model: GuardrailModel,
64
+ endpoint: Optional[str] = None,
65
+ api_key: Optional[str] = None,
66
+ severity_threshold: int = 2,
67
+ ):
68
+ """
69
+ Initialize Azure Content Safety backend.
70
+
71
+ Args:
72
+ model: The guardrail model enum value
73
+ endpoint: Azure Content Safety endpoint URL
74
+ api_key: Azure API key
75
+ severity_threshold: Minimum severity level to flag (0-7, default: 2)
76
+ """
77
+ super().__init__(model)
78
+
79
+ self._endpoint = endpoint or os.environ.get("AZURE_CONTENT_SAFETY_ENDPOINT")
80
+ self._api_key = api_key or os.environ.get("AZURE_CONTENT_SAFETY_KEY")
81
+
82
+ if not self._endpoint:
83
+ raise ValueError(
84
+ "Azure endpoint required. Set AZURE_CONTENT_SAFETY_ENDPOINT environment variable "
85
+ "or pass endpoint parameter."
86
+ )
87
+
88
+ if not self._api_key:
89
+ raise ValueError(
90
+ "Azure API key required. Set AZURE_CONTENT_SAFETY_KEY environment variable "
91
+ "or pass api_key parameter."
92
+ )
93
+
94
+ self._severity_threshold = severity_threshold
95
+ self._client = None
96
+
97
+ def _get_client(self):
98
+ """Lazy-load the Azure Content Safety client."""
99
+ if self._client is None:
100
+ try:
101
+ from azure.ai.contentsafety import ContentSafetyClient
102
+ from azure.core.credentials import AzureKeyCredential
103
+ except ImportError:
104
+ raise ImportError(
105
+ "azure-ai-contentsafety package required for Azure backend. "
106
+ "Install with: pip install azure-ai-contentsafety"
107
+ )
108
+
109
+ self._client = ContentSafetyClient(
110
+ endpoint=self._endpoint,
111
+ credential=AzureKeyCredential(self._api_key),
112
+ )
113
+ return self._client
114
+
115
+ def classify(
116
+ self,
117
+ content: str,
118
+ rail_type: RailType,
119
+ context: Optional[str] = None,
120
+ metadata: Optional[Dict[str, Any]] = None,
121
+ ) -> List[GuardrailResult]:
122
+ """
123
+ Classify content using Azure Content Safety API.
124
+
125
+ Args:
126
+ content: Content to classify
127
+ rail_type: Type of rail (input, output, retrieval)
128
+ context: Optional context (not used by Azure)
129
+ metadata: Optional metadata (not used by Azure)
130
+
131
+ Returns:
132
+ List of GuardrailResult objects for flagged categories
133
+ """
134
+ start_time = time.time()
135
+ results = []
136
+
137
+ # Handle empty content
138
+ if not content or not content.strip():
139
+ return [
140
+ GuardrailResult(
141
+ passed=True,
142
+ category="empty",
143
+ score=0.0,
144
+ model=self.model_name,
145
+ reason="Empty or whitespace-only content",
146
+ action="pass",
147
+ latency_ms=(time.time() - start_time) * 1000,
148
+ )
149
+ ]
150
+
151
+ try:
152
+ from azure.ai.contentsafety.models import AnalyzeTextOptions, TextCategory
153
+
154
+ client = self._get_client()
155
+
156
+ # Truncate content if too long (Azure limit is 10,000 characters)
157
+ truncated_content = content[:10000] if len(content) > 10000 else content
158
+
159
+ # Create the analysis request
160
+ request = AnalyzeTextOptions(
161
+ text=truncated_content,
162
+ categories=[
163
+ TextCategory.HATE,
164
+ TextCategory.SELF_HARM,
165
+ TextCategory.SEXUAL,
166
+ TextCategory.VIOLENCE,
167
+ ],
168
+ )
169
+
170
+ # Call Azure Content Safety API
171
+ response = client.analyze_text(request)
172
+
173
+ elapsed_ms = (time.time() - start_time) * 1000
174
+
175
+ # Check if any category exceeds threshold
176
+ flagged = False
177
+ for category_result in response.categories_analysis:
178
+ category_name = category_result.category
179
+ severity = category_result.severity
180
+
181
+ if severity >= self._severity_threshold:
182
+ flagged = True
183
+ our_category = AZURE_CATEGORY_MAP.get(
184
+ category_name, category_name.lower()
185
+ )
186
+ score = SEVERITY_TO_SCORE.get(severity, severity / 7.0)
187
+
188
+ results.append(
189
+ GuardrailResult(
190
+ passed=False,
191
+ category=our_category,
192
+ score=score,
193
+ model=self.model_name,
194
+ reason=f"Content flagged for {category_name} (severity: {severity})",
195
+ action="block",
196
+ latency_ms=elapsed_ms,
197
+ )
198
+ )
199
+
200
+ if not flagged:
201
+ return [
202
+ GuardrailResult(
203
+ passed=True,
204
+ category="safe",
205
+ score=0.0,
206
+ model=self.model_name,
207
+ reason="Content passed all Azure safety checks",
208
+ action="pass",
209
+ latency_ms=elapsed_ms,
210
+ )
211
+ ]
212
+
213
+ except ImportError as e:
214
+ elapsed_ms = (time.time() - start_time) * 1000
215
+ results.append(
216
+ GuardrailResult(
217
+ passed=False,
218
+ category="error",
219
+ score=0.0,
220
+ model=self.model_name,
221
+ reason=str(e),
222
+ action="block",
223
+ latency_ms=elapsed_ms,
224
+ )
225
+ )
226
+
227
+ except Exception as e:
228
+ elapsed_ms = (time.time() - start_time) * 1000
229
+ results.append(
230
+ GuardrailResult(
231
+ passed=False,
232
+ category="error",
233
+ score=0.0,
234
+ model=self.model_name,
235
+ reason=f"Azure API error: {str(e)}",
236
+ action="block",
237
+ latency_ms=elapsed_ms,
238
+ )
239
+ )
240
+
241
+ return results
242
+
243
+ async def classify_async(
244
+ self,
245
+ content: str,
246
+ rail_type: RailType,
247
+ context: Optional[str] = None,
248
+ metadata: Optional[Dict[str, Any]] = None,
249
+ ) -> List[GuardrailResult]:
250
+ """
251
+ Async version using Azure's async client.
252
+
253
+ Args:
254
+ content: Content to classify
255
+ rail_type: Type of rail
256
+ context: Optional context
257
+ metadata: Optional metadata
258
+
259
+ Returns:
260
+ List of GuardrailResult objects
261
+ """
262
+ start_time = time.time()
263
+
264
+ # Handle empty content
265
+ if not content or not content.strip():
266
+ return [
267
+ GuardrailResult(
268
+ passed=True,
269
+ category="empty",
270
+ score=0.0,
271
+ model=self.model_name,
272
+ reason="Empty or whitespace-only content",
273
+ action="pass",
274
+ latency_ms=(time.time() - start_time) * 1000,
275
+ )
276
+ ]
277
+
278
+ try:
279
+ from azure.ai.contentsafety.aio import ContentSafetyClient as AsyncContentSafetyClient
280
+ from azure.ai.contentsafety.models import AnalyzeTextOptions, TextCategory
281
+ from azure.core.credentials import AzureKeyCredential
282
+ except ImportError:
283
+ # Fall back to sync implementation
284
+ return await super().classify_async(content, rail_type, context, metadata)
285
+
286
+ try:
287
+ async with AsyncContentSafetyClient(
288
+ endpoint=self._endpoint,
289
+ credential=AzureKeyCredential(self._api_key),
290
+ ) as async_client:
291
+
292
+ truncated_content = content[:10000] if len(content) > 10000 else content
293
+
294
+ request = AnalyzeTextOptions(
295
+ text=truncated_content,
296
+ categories=[
297
+ TextCategory.HATE,
298
+ TextCategory.SELF_HARM,
299
+ TextCategory.SEXUAL,
300
+ TextCategory.VIOLENCE,
301
+ ],
302
+ )
303
+
304
+ response = await async_client.analyze_text(request)
305
+
306
+ elapsed_ms = (time.time() - start_time) * 1000
307
+
308
+ results = []
309
+ flagged = False
310
+
311
+ for category_result in response.categories_analysis:
312
+ category_name = category_result.category
313
+ severity = category_result.severity
314
+
315
+ if severity >= self._severity_threshold:
316
+ flagged = True
317
+ our_category = AZURE_CATEGORY_MAP.get(
318
+ category_name, category_name.lower()
319
+ )
320
+ score = SEVERITY_TO_SCORE.get(severity, severity / 7.0)
321
+
322
+ results.append(
323
+ GuardrailResult(
324
+ passed=False,
325
+ category=our_category,
326
+ score=score,
327
+ model=self.model_name,
328
+ reason=f"Content flagged for {category_name} (severity: {severity})",
329
+ action="block",
330
+ latency_ms=elapsed_ms,
331
+ )
332
+ )
333
+
334
+ if not flagged:
335
+ return [
336
+ GuardrailResult(
337
+ passed=True,
338
+ category="safe",
339
+ score=0.0,
340
+ model=self.model_name,
341
+ reason="Content passed all Azure safety checks",
342
+ action="pass",
343
+ latency_ms=elapsed_ms,
344
+ )
345
+ ]
346
+
347
+ return results
348
+
349
+ except Exception as e:
350
+ elapsed_ms = (time.time() - start_time) * 1000
351
+ return [
352
+ GuardrailResult(
353
+ passed=False,
354
+ category="error",
355
+ score=0.0,
356
+ model=self.model_name,
357
+ reason=f"Azure API error: {str(e)}",
358
+ action="block",
359
+ latency_ms=elapsed_ms,
360
+ )
361
+ ]
@@ -0,0 +1,88 @@
1
+ """
2
+ Base Backend Interface for Guardrails.
3
+
4
+ Defines the abstract interface that all guardrail backends must implement.
5
+ """
6
+
7
+ from abc import ABC, abstractmethod
8
+ from typing import Dict, List, Optional, Any
9
+ import asyncio
10
+
11
+ from fi.evals.guardrails.config import RailType, GuardrailModel
12
+ from fi.evals.guardrails.types import GuardrailResult
13
+
14
+
15
+ class BaseBackend(ABC):
16
+ """
17
+ Abstract base class for guardrail backends.
18
+
19
+ All backend implementations must inherit from this class and implement
20
+ the classify and classify_async methods.
21
+ """
22
+
23
+ def __init__(self, model: GuardrailModel):
24
+ """
25
+ Initialize the backend.
26
+
27
+ Args:
28
+ model: The model this backend represents
29
+ """
30
+ self.model = model
31
+
32
+ @abstractmethod
33
+ def classify(
34
+ self,
35
+ content: str,
36
+ rail_type: RailType,
37
+ context: Optional[str] = None,
38
+ metadata: Optional[Dict[str, Any]] = None,
39
+ ) -> List[GuardrailResult]:
40
+ """
41
+ Classify content synchronously.
42
+
43
+ Args:
44
+ content: The content to classify
45
+ rail_type: Type of rail (input, output, retrieval)
46
+ context: Optional context for the classification
47
+ metadata: Optional metadata
48
+
49
+ Returns:
50
+ List of GuardrailResult objects for each category detected
51
+ """
52
+ pass
53
+
54
+ async def classify_async(
55
+ self,
56
+ content: str,
57
+ rail_type: RailType,
58
+ context: Optional[str] = None,
59
+ metadata: Optional[Dict[str, Any]] = None,
60
+ ) -> List[GuardrailResult]:
61
+ """
62
+ Classify content asynchronously.
63
+
64
+ Default implementation wraps the sync method.
65
+ Backends can override for true async support.
66
+
67
+ Args:
68
+ content: The content to classify
69
+ rail_type: Type of rail (input, output, retrieval)
70
+ context: Optional context for the classification
71
+ metadata: Optional metadata
72
+
73
+ Returns:
74
+ List of GuardrailResult objects for each category detected
75
+ """
76
+ loop = asyncio.get_event_loop()
77
+ return await loop.run_in_executor(
78
+ None,
79
+ lambda: self.classify(content, rail_type, context, metadata)
80
+ )
81
+
82
+ @property
83
+ def model_name(self) -> str:
84
+ """Get the model name."""
85
+ return self.model.value
86
+
87
+ def __repr__(self) -> str:
88
+ return f"{self.__class__.__name__}(model={self.model.value})"