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.
- agent_learning_kit-0.1.0.dist-info/METADATA +381 -0
- agent_learning_kit-0.1.0.dist-info/RECORD +642 -0
- agent_learning_kit-0.1.0.dist-info/WHEEL +4 -0
- agent_learning_kit-0.1.0.dist-info/entry_points.txt +5 -0
- agent_learning_kit-0.1.0.dist-info/licenses/LICENSE +173 -0
- agent_learning_kit-0.1.0.dist-info/licenses/NOTICE +7 -0
- fi/__init__.py +5 -0
- fi/alk/__init__.py +57 -0
- fi/alk/_facade.py +31 -0
- fi/alk/_module_alias.py +68 -0
- fi/alk/_paths.py +14 -0
- fi/alk/_schema.py +522 -0
- fi/alk/actions.py +727 -0
- fi/alk/bench/__init__.py +517 -0
- fi/alk/bench/_codeexec.py +213 -0
- fi/alk/bench/_coding.py +215 -0
- fi/alk/bench/_docker.py +237 -0
- fi/alk/bench/_grader.py +286 -0
- fi/alk/bench/_pull.py +212 -0
- fi/alk/bench/_voice.py +147 -0
- fi/alk/capabilities.py +627 -0
- fi/alk/cli.py +6396 -0
- fi/alk/config.py +130 -0
- fi/alk/cua_loop.py +562 -0
- fi/alk/evals.py +2351 -0
- fi/alk/extensions.py +163 -0
- fi/alk/harness/ARCHITECTURE.md +231 -0
- fi/alk/harness/DESIGN.md +246 -0
- fi/alk/harness/ENVIRONMENT_CONFORMANCE.md +127 -0
- fi/alk/harness/HOW-IT-WORKS.md +297 -0
- fi/alk/harness/IMPLEMENTATION_AND_VALIDATION_STATUS.md +229 -0
- fi/alk/harness/README.md +417 -0
- fi/alk/harness/__init__.py +77 -0
- fi/alk/harness/__main__.py +3 -0
- fi/alk/harness/amend.py +312 -0
- fi/alk/harness/artifacts.py +319 -0
- fi/alk/harness/authoring_entrypoint.py +189 -0
- fi/alk/harness/authoring_runtime_validation.py +267 -0
- fi/alk/harness/backends/README.md +43 -0
- fi/alk/harness/backends/__init__.py +122 -0
- fi/alk/harness/backends/base.py +241 -0
- fi/alk/harness/backends/claude.py +211 -0
- fi/alk/harness/backends/files.py +182 -0
- fi/alk/harness/backends/vertex_gemini.py +457 -0
- fi/alk/harness/background_noise.py +95 -0
- fi/alk/harness/build.py +385 -0
- fi/alk/harness/bundle.py +593 -0
- fi/alk/harness/bundle_author_v2.py +1831 -0
- fi/alk/harness/bundle_v2.py +719 -0
- fi/alk/harness/call_runner.py +1440 -0
- fi/alk/harness/callback_http_adapter.py +111 -0
- fi/alk/harness/catalogue.py +287 -0
- fi/alk/harness/chat.py +428 -0
- fi/alk/harness/chat_call_runner.py +506 -0
- fi/alk/harness/checks.py +136 -0
- fi/alk/harness/cli.py +1354 -0
- fi/alk/harness/config.py +338 -0
- fi/alk/harness/contract.py +718 -0
- fi/alk/harness/credentials.py +674 -0
- fi/alk/harness/data/persona_vocabulary.json +111 -0
- fi/alk/harness/environment.py +99 -0
- fi/alk/harness/environment_plan.py +168 -0
- fi/alk/harness/events.py +125 -0
- fi/alk/harness/executor.py +304 -0
- fi/alk/harness/folder.py +234 -0
- fi/alk/harness/generated_runtime.py +815 -0
- fi/alk/harness/github.py +72 -0
- fi/alk/harness/hosted_authoring_entrypoint.py +183 -0
- fi/alk/harness/hosted_entrypoint.py +2402 -0
- fi/alk/harness/hosted_scheduler.py +2218 -0
- fi/alk/harness/job.py +426 -0
- fi/alk/harness/judge.py +184 -0
- fi/alk/harness/livekit_source.py +50 -0
- fi/alk/harness/livekit_tool_trace_bootstrap.py +71 -0
- fi/alk/harness/observability.py +208 -0
- fi/alk/harness/outbound.py +3252 -0
- fi/alk/harness/packaging.py +515 -0
- fi/alk/harness/persona_guides.py +157 -0
- fi/alk/harness/platform.py +692 -0
- fi/alk/harness/process_preflight.py +764 -0
- fi/alk/harness/process_runtime.py +5670 -0
- fi/alk/harness/prove.py +425 -0
- fi/alk/harness/provider_import.py +703 -0
- fi/alk/harness/provider_lifecycle.py +392 -0
- fi/alk/harness/provision.py +2896 -0
- fi/alk/harness/reception.py +147 -0
- fi/alk/harness/retell_chat_call_runner.py +373 -0
- fi/alk/harness/run/__init__.py +296 -0
- fi/alk/harness/run/alk.py +184 -0
- fi/alk/harness/run/call.py +162 -0
- fi/alk/harness/run/conversation.py +264 -0
- fi/alk/harness/run/data/voices_by_language_and_gender.json +693 -0
- fi/alk/harness/run/evidence.py +195 -0
- fi/alk/harness/run/grade.py +598 -0
- fi/alk/harness/run/live.py +297 -0
- fi/alk/harness/run/models.py +56 -0
- fi/alk/harness/run/platform_evals.py +227 -0
- fi/alk/harness/run/sdk_voice.py +130 -0
- fi/alk/harness/run/simulation.py +1209 -0
- fi/alk/harness/run/stage.py +91 -0
- fi/alk/harness/run/targets.py +508 -0
- fi/alk/harness/run/tools.py +601 -0
- fi/alk/harness/run/voice.py +340 -0
- fi/alk/harness/runtime.py +172 -0
- fi/alk/harness/sandbox_server.py +2011 -0
- fi/alk/harness/sandbox_worker.py +44 -0
- fi/alk/harness/scenario.py +1048 -0
- fi/alk/harness/scenario_source.py +879 -0
- fi/alk/harness/scenario_tools.py +1143 -0
- fi/alk/harness/scenarios.py +915 -0
- fi/alk/harness/secrets.py +168 -0
- fi/alk/harness/service_catalog.py +97 -0
- fi/alk/harness/session.py +391 -0
- fi/alk/harness/sessions.py +372 -0
- fi/alk/harness/simulator.py +76 -0
- fi/alk/harness/simulator_voice.py +928 -0
- fi/alk/harness/skills/build-environment/SKILL.md +538 -0
- fi/alk/harness/skills/harness.md +131 -0
- fi/alk/harness/skills/kinds/chat.md +48 -0
- fi/alk/harness/skills/kinds/voice-voicemail.md +63 -0
- fi/alk/harness/skills/kinds/voice.md +59 -0
- fi/alk/harness/skills/plan-suite/SKILL.md +103 -0
- fi/alk/harness/skills/provision-environment/SKILL.md +136 -0
- fi/alk/harness/skills/run-scenarios/SKILL.md +112 -0
- fi/alk/harness/skills/understand-agent/SKILL.md +251 -0
- fi/alk/harness/skills/write-scenarios/SKILL.md +606 -0
- fi/alk/harness/skills/write-scenarios/references/refusals.md +28 -0
- fi/alk/harness/skills/write-scenarios/references/world-api.md +92 -0
- fi/alk/harness/source_data_invariants.py +444 -0
- fi/alk/harness/source_tool_evidence.py +79 -0
- fi/alk/harness/sources.py +253 -0
- fi/alk/harness/spend.py +140 -0
- fi/alk/harness/tool_trace_proxy.py +104 -0
- fi/alk/harness/tools.py +1018 -0
- fi/alk/harness/understand.py +169 -0
- fi/alk/harness/voicemail_audio.py +74 -0
- fi/alk/harness/world/__init__.py +33 -0
- fi/alk/harness/world/errors.py +68 -0
- fi/alk/harness/world/expectations.py +91 -0
- fi/alk/harness/world/handle.py +538 -0
- fi/alk/harness/world/kinds.py +196 -0
- fi/alk/harness/world/mutate.py +186 -0
- fi/alk/harness/world/probe.py +413 -0
- fi/alk/harness/world/provision.py +511 -0
- fi/alk/harness/world/provisioned.py +191 -0
- fi/alk/harness/world/runtime.py +616 -0
- fi/alk/harness/world/snapshot.py +288 -0
- fi/alk/harness/world/stores/__init__.py +305 -0
- fi/alk/harness/world/stores/container.py +215 -0
- fi/alk/harness/world/stores/inprocess.py +346 -0
- fi/alk/harness/world/stores/postgres.py +481 -0
- fi/alk/harness/world/stores/prove.py +202 -0
- fi/alk/harness/world/stores/sqlite.py +245 -0
- fi/alk/harness/world/stores/written.py +182 -0
- fi/alk/harness/world/tools.py +1516 -0
- fi/alk/harness/world/workspace.py +144 -0
- fi/alk/image_loop.py +453 -0
- fi/alk/image_perturb.py +241 -0
- fi/alk/improve.py +274 -0
- fi/alk/live/__init__.py +154 -0
- fi/alk/live/_attribution.py +184 -0
- fi/alk/live/_capture.py +264 -0
- fi/alk/live/_codec.py +391 -0
- fi/alk/live/_contract.py +134 -0
- fi/alk/live/_loopback.py +316 -0
- fi/alk/live/_perturb.py +449 -0
- fi/alk/live/_runner.py +386 -0
- fi/alk/live/_stats.py +561 -0
- fi/alk/live/_transcript.py +240 -0
- fi/alk/live/_workers/__init__.py +9 -0
- fi/alk/live/_workers/a2a_worker.py +316 -0
- fi/alk/live/_workers/langgraph_worker.py +217 -0
- fi/alk/live/_workers/livekit_worker.py +207 -0
- fi/alk/live/_workers/mcp_loopback_server.py +46 -0
- fi/alk/live/_workers/mcp_worker.py +158 -0
- fi/alk/live/_workers/pipecat_worker.py +189 -0
- fi/alk/live/a2a_lane.py +138 -0
- fi/alk/live/langgraph_lane.py +339 -0
- fi/alk/live/livekit_lane.py +376 -0
- fi/alk/live/mcp_lane.py +172 -0
- fi/alk/live/pipecat_lane.py +341 -0
- fi/alk/live/voice_redteam.py +494 -0
- fi/alk/loss.py +306 -0
- fi/alk/optimize.py +36260 -0
- fi/alk/practice/__init__.py +51 -0
- fi/alk/practice/_assess.py +103 -0
- fi/alk/practice/_budget.py +81 -0
- fi/alk/practice/_calibrate.py +69 -0
- fi/alk/practice/_capstone.py +86 -0
- fi/alk/practice/_contract.py +91 -0
- fi/alk/practice/_diagnose.py +79 -0
- fi/alk/practice/_drill.py +196 -0
- fi/alk/practice/_experiment.py +720 -0
- fi/alk/practice/_schedule.py +102 -0
- fi/alk/practice/_store.py +194 -0
- fi/alk/practice/_trainer.py +245 -0
- fi/alk/practice/_update.py +125 -0
- fi/alk/redteam.py +2621 -0
- fi/alk/rewardhack.py +237 -0
- fi/alk/simulate.py +10351 -0
- fi/alk/studio/__init__.py +82 -0
- fi/alk/studio/_bias.py +314 -0
- fi/alk/studio/_calibration.py +522 -0
- fi/alk/studio/_coverage.py +262 -0
- fi/alk/studio/_download.py +665 -0
- fi/alk/studio/_fidelity_attack.py +114 -0
- fi/alk/studio/_generate.py +652 -0
- fi/alk/studio/_library.py +370 -0
- fi/alk/studio/_scan.py +134 -0
- fi/alk/studio/_upgrade.py +42 -0
- fi/alk/studio/_vendor.py +172 -0
- fi/alk/suite.py +4200 -0
- fi/alk/tasks.py +828 -0
- fi/alk/telemetry/__init__.py +149 -0
- fi/alk/telemetry/_contract.py +141 -0
- fi/alk/telemetry/_emit.py +182 -0
- fi/alk/telemetry/_ledger.py +296 -0
- fi/alk/telemetry/_queue.py +127 -0
- fi/alk/telemetry/_row.py +294 -0
- fi/alk/telemetry/_run.py +233 -0
- fi/alk/telemetry/_sync.py +193 -0
- fi/alk/telemetry/_url.py +119 -0
- fi/alk/trinity.py +49397 -0
- fi/alk/voice_loop.py +174 -0
- fi/api/__init__.py +1 -0
- fi/api/auth.py +137 -0
- fi/api/types.py +29 -0
- fi/cli/__init__.py +9 -0
- fi/cli/assertions/__init__.py +25 -0
- fi/cli/assertions/conditions.py +76 -0
- fi/cli/assertions/evaluator.py +286 -0
- fi/cli/assertions/exit_codes.py +20 -0
- fi/cli/assertions/parser.py +131 -0
- fi/cli/assertions/reporter.py +194 -0
- fi/cli/commands/__init__.py +9 -0
- fi/cli/commands/config.py +165 -0
- fi/cli/commands/export.py +208 -0
- fi/cli/commands/init.py +112 -0
- fi/cli/commands/list_cmd.py +213 -0
- fi/cli/commands/run.py +486 -0
- fi/cli/commands/validate.py +173 -0
- fi/cli/commands/view.py +424 -0
- fi/cli/config/__init__.py +6 -0
- fi/cli/config/defaults.py +206 -0
- fi/cli/config/loader.py +155 -0
- fi/cli/config/schema.py +174 -0
- fi/cli/main.py +78 -0
- fi/cli/output/__init__.py +6 -0
- fi/cli/output/formatters.py +106 -0
- fi/cli/output/reporters.py +46 -0
- fi/cli/storage/__init__.py +5 -0
- fi/cli/storage/run_history.py +249 -0
- fi/cli/utils/__init__.py +5 -0
- fi/cli/utils/console.py +44 -0
- fi/evals/__init__.py +131 -0
- fi/evals/autoeval/__init__.py +137 -0
- fi/evals/autoeval/analyzer.py +211 -0
- fi/evals/autoeval/config.py +244 -0
- fi/evals/autoeval/export.py +213 -0
- fi/evals/autoeval/interactive.py +283 -0
- fi/evals/autoeval/pipeline.py +625 -0
- fi/evals/autoeval/prompts.py +139 -0
- fi/evals/autoeval/recommender.py +242 -0
- fi/evals/autoeval/rules.py +589 -0
- fi/evals/autoeval/templates.py +299 -0
- fi/evals/autoeval/types.py +232 -0
- fi/evals/core/__init__.py +16 -0
- fi/evals/core/cloud_registry.py +184 -0
- fi/evals/core/engines.py +368 -0
- fi/evals/core/evaluate.py +319 -0
- fi/evals/core/judge_prompt.py +90 -0
- fi/evals/core/prompt_generator.py +83 -0
- fi/evals/core/registry.py +57 -0
- fi/evals/core/result.py +55 -0
- fi/evals/evaluator.py +721 -0
- fi/evals/execution.py +168 -0
- fi/evals/feedback/__init__.py +32 -0
- fi/evals/feedback/calibrator.py +160 -0
- fi/evals/feedback/collector.py +214 -0
- fi/evals/feedback/hooks.py +81 -0
- fi/evals/feedback/retriever.py +128 -0
- fi/evals/feedback/store.py +272 -0
- fi/evals/feedback/types.py +99 -0
- fi/evals/framework/README.md +79 -0
- fi/evals/framework/__init__.py +267 -0
- fi/evals/framework/backends/Dockerfile.eval-runner +33 -0
- fi/evals/framework/backends/__init__.py +99 -0
- fi/evals/framework/backends/_container.py +141 -0
- fi/evals/framework/backends/_utils.py +145 -0
- fi/evals/framework/backends/base.py +223 -0
- fi/evals/framework/backends/celery_backend.py +417 -0
- fi/evals/framework/backends/celery_worker.py +78 -0
- fi/evals/framework/backends/kubernetes_backend.py +665 -0
- fi/evals/framework/backends/ray_backend.py +521 -0
- fi/evals/framework/backends/temporal.py +350 -0
- fi/evals/framework/backends/temporal_worker.py +126 -0
- fi/evals/framework/backends/thread_pool.py +286 -0
- fi/evals/framework/context.py +258 -0
- fi/evals/framework/enrichment.py +306 -0
- fi/evals/framework/evals/__init__.py +68 -0
- fi/evals/framework/evals/agentic.py +399 -0
- fi/evals/framework/evals/builder.py +609 -0
- fi/evals/framework/evals/semantic.py +142 -0
- fi/evals/framework/evaluator.py +647 -0
- fi/evals/framework/evaluators/__init__.py +22 -0
- fi/evals/framework/evaluators/blocking.py +347 -0
- fi/evals/framework/evaluators/non_blocking.py +577 -0
- fi/evals/framework/propagation.py +421 -0
- fi/evals/framework/protocols.py +385 -0
- fi/evals/framework/registry.py +370 -0
- fi/evals/framework/resilience/__init__.py +150 -0
- fi/evals/framework/resilience/circuit_breaker.py +309 -0
- fi/evals/framework/resilience/degradation.py +355 -0
- fi/evals/framework/resilience/health.py +505 -0
- fi/evals/framework/resilience/rate_limiter.py +228 -0
- fi/evals/framework/resilience/retry.py +274 -0
- fi/evals/framework/resilience/types.py +288 -0
- fi/evals/framework/resilience/wrapper.py +433 -0
- fi/evals/framework/types.py +218 -0
- fi/evals/guardrails/README.md +915 -0
- fi/evals/guardrails/__init__.py +96 -0
- fi/evals/guardrails/backends/__init__.py +43 -0
- fi/evals/guardrails/backends/azure.py +361 -0
- fi/evals/guardrails/backends/base.py +88 -0
- fi/evals/guardrails/backends/generic_llm.py +163 -0
- fi/evals/guardrails/backends/granite.py +216 -0
- fi/evals/guardrails/backends/llamaguard.py +221 -0
- fi/evals/guardrails/backends/local_base.py +479 -0
- fi/evals/guardrails/backends/openai.py +365 -0
- fi/evals/guardrails/backends/qwen.py +170 -0
- fi/evals/guardrails/backends/shieldgemma.py +154 -0
- fi/evals/guardrails/backends/turing.py +235 -0
- fi/evals/guardrails/backends/vllm_client.py +321 -0
- fi/evals/guardrails/backends/wildguard.py +188 -0
- fi/evals/guardrails/base.py +888 -0
- fi/evals/guardrails/config.py +221 -0
- fi/evals/guardrails/discovery.py +243 -0
- fi/evals/guardrails/gateway.py +437 -0
- fi/evals/guardrails/registry.py +231 -0
- fi/evals/guardrails/scanners/__init__.py +127 -0
- fi/evals/guardrails/scanners/base.py +191 -0
- fi/evals/guardrails/scanners/code_injection.py +243 -0
- fi/evals/guardrails/scanners/eval_delegate.py +574 -0
- fi/evals/guardrails/scanners/invisible_chars.py +351 -0
- fi/evals/guardrails/scanners/jailbreak.py +412 -0
- fi/evals/guardrails/scanners/language.py +288 -0
- fi/evals/guardrails/scanners/pipeline.py +260 -0
- fi/evals/guardrails/scanners/regex.py +311 -0
- fi/evals/guardrails/scanners/secrets.py +274 -0
- fi/evals/guardrails/scanners/topics.py +649 -0
- fi/evals/guardrails/scanners/urls.py +341 -0
- fi/evals/guardrails/types.py +96 -0
- fi/evals/llm/__init__.py +3 -0
- fi/evals/llm/base_llm_provider.py +35 -0
- fi/evals/llm/providers/litellm.py +70 -0
- fi/evals/local/__init__.py +90 -0
- fi/evals/local/evaluator.py +690 -0
- fi/evals/local/execution_mode.py +121 -0
- fi/evals/local/llm.py +489 -0
- fi/evals/local/metrics/__init__.py +19 -0
- fi/evals/local/registry.py +360 -0
- fi/evals/manager.py +1018 -0
- fi/evals/manager_types.py +362 -0
- fi/evals/metrics/__init__.py +185 -0
- fi/evals/metrics/agents/__init__.py +74 -0
- fi/evals/metrics/agents/metrics.py +693 -0
- fi/evals/metrics/agents/report.py +36463 -0
- fi/evals/metrics/agents/types.py +160 -0
- fi/evals/metrics/base_llm_metric.py +111 -0
- fi/evals/metrics/base_metric.py +138 -0
- fi/evals/metrics/code_security/__init__.py +305 -0
- fi/evals/metrics/code_security/analyzer.py +985 -0
- fi/evals/metrics/code_security/benchmarks/__init__.py +73 -0
- fi/evals/metrics/code_security/benchmarks/builtin.py +750 -0
- fi/evals/metrics/code_security/benchmarks/loader.py +580 -0
- fi/evals/metrics/code_security/benchmarks/types.py +308 -0
- fi/evals/metrics/code_security/detectors/__init__.py +186 -0
- fi/evals/metrics/code_security/detectors/base.py +394 -0
- fi/evals/metrics/code_security/detectors/cryptography.py +345 -0
- fi/evals/metrics/code_security/detectors/injection.py +744 -0
- fi/evals/metrics/code_security/detectors/secrets.py +287 -0
- fi/evals/metrics/code_security/detectors/serialization.py +192 -0
- fi/evals/metrics/code_security/joint_metrics.py +588 -0
- fi/evals/metrics/code_security/judges/__init__.py +83 -0
- fi/evals/metrics/code_security/judges/base.py +238 -0
- fi/evals/metrics/code_security/judges/dual_judge.py +534 -0
- fi/evals/metrics/code_security/judges/llm_judge.py +301 -0
- fi/evals/metrics/code_security/judges/pattern_judge.py +515 -0
- fi/evals/metrics/code_security/metrics.py +388 -0
- fi/evals/metrics/code_security/modes/__init__.py +63 -0
- fi/evals/metrics/code_security/modes/adversarial.py +284 -0
- fi/evals/metrics/code_security/modes/autocomplete.py +198 -0
- fi/evals/metrics/code_security/modes/base.py +283 -0
- fi/evals/metrics/code_security/modes/instruct.py +253 -0
- fi/evals/metrics/code_security/modes/repair.py +230 -0
- fi/evals/metrics/code_security/reports/__init__.py +57 -0
- fi/evals/metrics/code_security/reports/generator.py +404 -0
- fi/evals/metrics/code_security/reports/leaderboard.py +509 -0
- fi/evals/metrics/code_security/types.py +534 -0
- fi/evals/metrics/function_calling/__init__.py +34 -0
- fi/evals/metrics/function_calling/metrics.py +573 -0
- fi/evals/metrics/function_calling/types.py +87 -0
- fi/evals/metrics/hallucination/__init__.py +54 -0
- fi/evals/metrics/hallucination/detector.py +149 -0
- fi/evals/metrics/hallucination/metrics.py +390 -0
- fi/evals/metrics/hallucination/nli.py +253 -0
- fi/evals/metrics/hallucination/sentinel.py +106 -0
- fi/evals/metrics/hallucination/types.py +132 -0
- fi/evals/metrics/heuristics/aggregation_metrics.py +85 -0
- fi/evals/metrics/heuristics/json_metrics.py +87 -0
- fi/evals/metrics/heuristics/similarity_metrics.py +375 -0
- fi/evals/metrics/heuristics/string_metrics.py +391 -0
- fi/evals/metrics/llm_as_judges/__init__.py +17 -0
- fi/evals/metrics/llm_as_judges/custom_judge/metric.py +112 -0
- fi/evals/metrics/llm_as_judges/custom_judge/prompts.py +26 -0
- fi/evals/metrics/llm_as_judges/types.py +48 -0
- fi/evals/metrics/rag/__init__.py +111 -0
- fi/evals/metrics/rag/advanced/__init__.py +14 -0
- fi/evals/metrics/rag/advanced/multi_hop.py +283 -0
- fi/evals/metrics/rag/advanced/source_attribution.py +344 -0
- fi/evals/metrics/rag/generation/__init__.py +17 -0
- fi/evals/metrics/rag/generation/answer_relevancy.py +176 -0
- fi/evals/metrics/rag/generation/context_utilization.py +245 -0
- fi/evals/metrics/rag/generation/faithfulness.py +241 -0
- fi/evals/metrics/rag/generation/groundedness.py +131 -0
- fi/evals/metrics/rag/rag_score.py +277 -0
- fi/evals/metrics/rag/retrieval/__init__.py +20 -0
- fi/evals/metrics/rag/retrieval/context_entity_recall.py +124 -0
- fi/evals/metrics/rag/retrieval/context_precision.py +158 -0
- fi/evals/metrics/rag/retrieval/context_recall.py +106 -0
- fi/evals/metrics/rag/retrieval/noise_sensitivity.py +163 -0
- fi/evals/metrics/rag/retrieval/ranking.py +261 -0
- fi/evals/metrics/rag/types.py +100 -0
- fi/evals/metrics/rag/utils/__init__.py +62 -0
- fi/evals/metrics/rag/utils/claims.py +189 -0
- fi/evals/metrics/rag/utils/entities.py +244 -0
- fi/evals/metrics/rag/utils/nli.py +92 -0
- fi/evals/metrics/rag/utils/similarity.py +345 -0
- fi/evals/metrics/structured/__init__.py +114 -0
- fi/evals/metrics/structured/field_completeness.py +313 -0
- fi/evals/metrics/structured/hierarchy_score.py +366 -0
- fi/evals/metrics/structured/json_validation.py +190 -0
- fi/evals/metrics/structured/schema_compliance.py +280 -0
- fi/evals/metrics/structured/structured_output_score.py +298 -0
- fi/evals/metrics/structured/types.py +108 -0
- fi/evals/metrics/structured/validators/__init__.py +30 -0
- fi/evals/metrics/structured/validators/base.py +189 -0
- fi/evals/metrics/structured/validators/json_validator.py +196 -0
- fi/evals/metrics/structured/validators/pydantic_validator.py +178 -0
- fi/evals/metrics/structured/validators/yaml_validator.py +248 -0
- fi/evals/otel/__init__.py +266 -0
- fi/evals/otel/config.py +400 -0
- fi/evals/otel/conventions.py +463 -0
- fi/evals/otel/enrichment.py +371 -0
- fi/evals/otel/instrumentors/__init__.py +140 -0
- fi/evals/otel/instrumentors/anthropic.py +517 -0
- fi/evals/otel/instrumentors/base.py +382 -0
- fi/evals/otel/instrumentors/openai.py +673 -0
- fi/evals/otel/processors/__init__.py +36 -0
- fi/evals/otel/processors/base.py +473 -0
- fi/evals/otel/processors/cost.py +445 -0
- fi/evals/otel/processors/evaluation.py +559 -0
- fi/evals/otel/processors/llm.py +462 -0
- fi/evals/otel/tracer.py +506 -0
- fi/evals/otel/types.py +232 -0
- fi/evals/otel_utils.py +23 -0
- fi/evals/protect.py +671 -0
- fi/evals/protect_input_adapter.py +154 -0
- fi/evals/streaming/__init__.py +88 -0
- fi/evals/streaming/buffer.py +213 -0
- fi/evals/streaming/evaluator.py +551 -0
- fi/evals/streaming/policy.py +307 -0
- fi/evals/streaming/scorers.py +368 -0
- fi/evals/streaming/types.py +238 -0
- fi/evals/templates.py +472 -0
- fi/evals/types.py +156 -0
- fi/opt/__init__.py +221 -0
- fi/opt/_objective_scoring.py +85 -0
- fi/opt/base/__init__.py +11 -0
- fi/opt/base/base_generator.py +33 -0
- fi/opt/base/base_mapper.py +26 -0
- fi/opt/base/base_optimizer.py +45 -0
- fi/opt/base/evaluator.py +211 -0
- fi/opt/components.py +3095 -0
- fi/opt/datamappers/__init__.py +3 -0
- fi/opt/datamappers/basic_mapper.py +40 -0
- fi/opt/deployment.py +1021 -0
- fi/opt/evidence.py +4332 -0
- fi/opt/generators/__init__.py +3 -0
- fi/opt/generators/litellm.py +66 -0
- fi/opt/integrations/__init__.py +23 -0
- fi/opt/integrations/generative_suite.py +410 -0
- fi/opt/integrations/simulate.py +1313 -0
- fi/opt/mutations.py +771 -0
- fi/opt/observability.py +4639 -0
- fi/opt/optimizer_trace.py +889 -0
- fi/opt/optimizers/__init__.py +80 -0
- fi/opt/optimizers/agent.py +331 -0
- fi/opt/optimizers/agent_bandit.py +392 -0
- fi/opt/optimizers/agent_curriculum.py +635 -0
- fi/opt/optimizers/agent_evolution.py +894 -0
- fi/opt/optimizers/agent_feedback.py +1863 -0
- fi/opt/optimizers/agent_pareto.py +547 -0
- fi/opt/optimizers/agent_social_memory.py +1113 -0
- fi/opt/optimizers/agent_tpe.py +321 -0
- fi/opt/optimizers/bayesian_search.py +449 -0
- fi/opt/optimizers/council.py +2075 -0
- fi/opt/optimizers/futureagi_replay.py +799 -0
- fi/opt/optimizers/gepa.py +322 -0
- fi/opt/optimizers/metaprompt.py +243 -0
- fi/opt/optimizers/promptwizard.py +417 -0
- fi/opt/optimizers/protegi.py +329 -0
- fi/opt/optimizers/random_search.py +224 -0
- fi/opt/research.py +518 -0
- fi/opt/simulation.py +260 -0
- fi/opt/targets.py +232 -0
- fi/opt/types.py +66 -0
- fi/opt/utils/__init__.py +4 -0
- fi/opt/utils/early_stopping.py +266 -0
- fi/opt/utils/setup_logging.py +82 -0
- fi/simulate/__init__.py +540 -0
- fi/simulate/_hashing.py +35 -0
- fi/simulate/_logging.py +10 -0
- fi/simulate/adapters.py +87 -0
- fi/simulate/agent/__init__.py +120 -0
- fi/simulate/agent/browser.py +658 -0
- fi/simulate/agent/definition.py +587 -0
- fi/simulate/agent/frameworks.py +3528 -0
- fi/simulate/agent/generic.py +8286 -0
- fi/simulate/agent/import_probe.py +227 -0
- fi/simulate/agent/memory.py +905 -0
- fi/simulate/agent/mocks.py +101 -0
- fi/simulate/agent/multi_agent.py +361 -0
- fi/simulate/agent/orchestration.py +903 -0
- fi/simulate/agent/realtime.py +665 -0
- fi/simulate/agent/wrapper.py +99 -0
- fi/simulate/agent/wrappers/__init__.py +18 -0
- fi/simulate/agent/wrappers/anthropic.py +62 -0
- fi/simulate/agent/wrappers/gemini.py +65 -0
- fi/simulate/agent/wrappers/http.py +404 -0
- fi/simulate/agent/wrappers/langchain.py +80 -0
- fi/simulate/agent/wrappers/openai.py +75 -0
- fi/simulate/agent/wrappers/websocket.py +326 -0
- fi/simulate/artifacts/__init__.py +11 -0
- fi/simulate/artifacts/manifest.py +62 -0
- fi/simulate/cli.py +20560 -0
- fi/simulate/endpoints/__init__.py +45 -0
- fi/simulate/endpoints/_http_actor.py +73 -0
- fi/simulate/endpoints/actor_sources.py +243 -0
- fi/simulate/endpoints/base.py +107 -0
- fi/simulate/endpoints/builtins.py +10 -0
- fi/simulate/endpoints/callable.py +95 -0
- fi/simulate/endpoints/http.py +76 -0
- fi/simulate/endpoints/livekit.py +138 -0
- fi/simulate/endpoints/originators.py +132 -0
- fi/simulate/endpoints/profiles.py +348 -0
- fi/simulate/endpoints/retell.py +633 -0
- fi/simulate/endpoints/vapi.py +205 -0
- fi/simulate/endpoints/websocket.py +76 -0
- fi/simulate/environment.py +33026 -0
- fi/simulate/environments/__init__.py +11 -0
- fi/simulate/environments/base.py +73 -0
- fi/simulate/environments/chat.py +697 -0
- fi/simulate/environments/voice.py +212 -0
- fi/simulate/evaluation/__init__.py +4 -0
- fi/simulate/evaluation/ai_eval.py +227 -0
- fi/simulate/evidence/__init__.py +35 -0
- fi/simulate/evidence/base.py +59 -0
- fi/simulate/evidence/caller_observed.py +50 -0
- fi/simulate/evidence/livekit_instrumentation.py +51 -0
- fi/simulate/evidence/livekit_room.py +50 -0
- fi/simulate/evidence/otel.py +49 -0
- fi/simulate/evidence/providers/__init__.py +24 -0
- fi/simulate/evidence/providers/base.py +61 -0
- fi/simulate/evidence/providers/retell.py +376 -0
- fi/simulate/evidence/providers/vapi.py +426 -0
- fi/simulate/hosted/__init__.py +32 -0
- fi/simulate/hosted/child_entrypoint.py +306 -0
- fi/simulate/hosted/job.py +150 -0
- fi/simulate/hosted/targets.py +53 -0
- fi/simulate/instrumentation/__init__.py +5 -0
- fi/simulate/instrumentation/livekit/__init__.py +122 -0
- fi/simulate/manifest.py +1033 -0
- fi/simulate/matrix_cli.py +165 -0
- fi/simulate/realtime/__init__.py +40 -0
- fi/simulate/realtime/events.py +107 -0
- fi/simulate/realtime/media.py +61 -0
- fi/simulate/realtime/session.py +91 -0
- fi/simulate/recording/__init__.py +5 -0
- fi/simulate/recording/room_recorder.py +326 -0
- fi/simulate/registry.py +185 -0
- fi/simulate/results/__init__.py +9 -0
- fi/simulate/results/base.py +18 -0
- fi/simulate/results/filesystem.py +71 -0
- fi/simulate/results/futureagi.py +1340 -0
- fi/simulate/runtime/__init__.py +85 -0
- fi/simulate/runtime/capabilities.py +40 -0
- fi/simulate/runtime/events.py +63 -0
- fi/simulate/runtime/failures.py +25 -0
- fi/simulate/runtime/ids.py +34 -0
- fi/simulate/runtime/plan.py +70 -0
- fi/simulate/runtime/planner.py +102 -0
- fi/simulate/runtime/report.py +174 -0
- fi/simulate/runtime/run.py +75 -0
- fi/simulate/runtime/runner.py +333 -0
- fi/simulate/runtime/spec.py +186 -0
- fi/simulate/simulation/__init__.py +30 -0
- fi/simulate/simulation/behavior_policy.py +425 -0
- fi/simulate/simulation/bridge/__init__.py +9 -0
- fi/simulate/simulation/bridge/audio.py +29 -0
- fi/simulate/simulation/bridge/connector.py +46 -0
- fi/simulate/simulation/bridge/livekit.py +252 -0
- fi/simulate/simulation/bridge/retell.py +188 -0
- fi/simulate/simulation/bridge/vapi.py +177 -0
- fi/simulate/simulation/contract.py +419 -0
- fi/simulate/simulation/engines/__init__.py +12 -0
- fi/simulate/simulation/engines/base.py +21 -0
- fi/simulate/simulation/engines/cloud.py +517 -0
- fi/simulate/simulation/engines/livekit.py +4167 -0
- fi/simulate/simulation/engines/local_text.py +89 -0
- fi/simulate/simulation/fidelity.py +374 -0
- fi/simulate/simulation/gemini_tts_stream.py +110 -0
- fi/simulate/simulation/generator.py +91 -0
- fi/simulate/simulation/goal_machine.py +185 -0
- fi/simulate/simulation/livekit_models.py +467 -0
- fi/simulate/simulation/matrix.py +170 -0
- fi/simulate/simulation/models.py +279 -0
- fi/simulate/simulation/runner.py +153 -0
- fi/simulate/simulation/synthetic.py +880 -0
- fi/simulate/simulation/voice_prompt.py +502 -0
- fi/simulate/simulator/__init__.py +55 -0
- fi/simulate/simulator/builtins.py +53 -0
- fi/simulate/suite.py +1288 -0
- fi/simulate/utils/routes.py +164 -0
- fi/simulate/voice.py +225 -0
- fi/simulate/voice_cli.py +182 -0
- fi/utils/__init__.py +1 -0
- fi/utils/constants.py +14 -0
- fi/utils/errors.py +200 -0
- fi/utils/executor.py +26 -0
- fi/utils/routes.py +119 -0
- fi/utils/utils.py +17 -0
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Base class for Local Model Backends.
|
|
3
|
+
|
|
4
|
+
Provides common functionality for running HuggingFace models locally,
|
|
5
|
+
either via VLLM server or direct transformers loading.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
import time
|
|
10
|
+
from abc import abstractmethod
|
|
11
|
+
from typing import Any, Dict, List, Optional
|
|
12
|
+
|
|
13
|
+
from fi.evals.guardrails.backends.base import BaseBackend
|
|
14
|
+
from fi.evals.guardrails.backends.vllm_client import VLLMClient, get_vllm_url
|
|
15
|
+
from fi.evals.guardrails.config import GuardrailModel, RailType
|
|
16
|
+
from fi.evals.guardrails.types import GuardrailResult
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class LocalModelBackend(BaseBackend):
|
|
20
|
+
"""
|
|
21
|
+
Base class for local HuggingFace model backends.
|
|
22
|
+
|
|
23
|
+
Supports two modes:
|
|
24
|
+
1. VLLM Server Mode: Use external VLLM server for inference
|
|
25
|
+
2. Direct Mode: Load model directly using transformers
|
|
26
|
+
|
|
27
|
+
Subclasses must implement:
|
|
28
|
+
- _format_prompt(): Model-specific prompt formatting
|
|
29
|
+
- _parse_response(): Model-specific response parsing
|
|
30
|
+
- HF_MODEL_NAME: HuggingFace model identifier
|
|
31
|
+
|
|
32
|
+
Usage:
|
|
33
|
+
class WildGuardBackend(LocalModelBackend):
|
|
34
|
+
HF_MODEL_NAME = "allenai/wildguard"
|
|
35
|
+
|
|
36
|
+
def _format_prompt(self, content, context=None):
|
|
37
|
+
return f"Human user:\\n{content}\\n..."
|
|
38
|
+
|
|
39
|
+
def _parse_response(self, response):
|
|
40
|
+
# Parse "harmful_request: yes/no" format
|
|
41
|
+
...
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
# Subclasses should override these
|
|
45
|
+
HF_MODEL_NAME: str = ""
|
|
46
|
+
MAX_NEW_TOKENS: int = 128
|
|
47
|
+
TEMPERATURE: float = 0.1
|
|
48
|
+
|
|
49
|
+
def __init__(
|
|
50
|
+
self,
|
|
51
|
+
model: GuardrailModel,
|
|
52
|
+
vllm_url: Optional[str] = None,
|
|
53
|
+
device: str = "auto",
|
|
54
|
+
hf_token: Optional[str] = None,
|
|
55
|
+
load_in_8bit: bool = False,
|
|
56
|
+
load_in_4bit: bool = False,
|
|
57
|
+
):
|
|
58
|
+
"""
|
|
59
|
+
Initialize local model backend.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
model: The guardrail model enum value
|
|
63
|
+
vllm_url: VLLM server URL (auto-detected from env if not provided)
|
|
64
|
+
device: Device to use ("auto", "cuda", "mps", "cpu")
|
|
65
|
+
hf_token: HuggingFace token for gated models
|
|
66
|
+
load_in_8bit: Use 8-bit quantization (reduces memory)
|
|
67
|
+
load_in_4bit: Use 4-bit quantization (reduces memory further)
|
|
68
|
+
"""
|
|
69
|
+
super().__init__(model)
|
|
70
|
+
|
|
71
|
+
self._vllm_url = vllm_url or get_vllm_url(model.value)
|
|
72
|
+
self._device = device
|
|
73
|
+
self._hf_token = hf_token or os.environ.get("HF_TOKEN") or os.environ.get("HUGGING_FACE_HUB_TOKEN")
|
|
74
|
+
self._load_in_8bit = load_in_8bit
|
|
75
|
+
self._load_in_4bit = load_in_4bit
|
|
76
|
+
|
|
77
|
+
# Lazy-loaded resources
|
|
78
|
+
self._vllm_client: Optional[VLLMClient] = None
|
|
79
|
+
self._transformers_model = None
|
|
80
|
+
self._tokenizer = None
|
|
81
|
+
|
|
82
|
+
# Check what's available
|
|
83
|
+
self._use_vllm = False
|
|
84
|
+
if self._vllm_url:
|
|
85
|
+
client = VLLMClient(self._vllm_url)
|
|
86
|
+
if client.health_check():
|
|
87
|
+
self._use_vllm = True
|
|
88
|
+
self._vllm_client = client
|
|
89
|
+
# Resolve which model on the server matches this backend
|
|
90
|
+
self._resolve_server_model()
|
|
91
|
+
|
|
92
|
+
def _resolve_server_model(self):
|
|
93
|
+
"""Match this backend's model to an available model on the VLLM/ollama server."""
|
|
94
|
+
try:
|
|
95
|
+
available = self._vllm_client.get_models()
|
|
96
|
+
except Exception:
|
|
97
|
+
return
|
|
98
|
+
|
|
99
|
+
if not available:
|
|
100
|
+
return
|
|
101
|
+
|
|
102
|
+
# Our enum value e.g. "llamaguard-3-1b", "qwen3guard-0.6b"
|
|
103
|
+
our_key = self.model.value.lower()
|
|
104
|
+
# Normalize: strip hyphens/underscores/dots for fuzzy matching
|
|
105
|
+
our_norm = our_key.replace("-", "").replace("_", "").replace(".", "")
|
|
106
|
+
# Also get the HF model name for matching
|
|
107
|
+
hf_name = self._get_hf_model_name().lower()
|
|
108
|
+
|
|
109
|
+
for server_model in available:
|
|
110
|
+
sm = server_model.lower()
|
|
111
|
+
sm_norm = sm.replace("-", "").replace("_", "").replace(".", "").replace("/", "").replace(":", "")
|
|
112
|
+
|
|
113
|
+
# Exact match on enum value
|
|
114
|
+
if our_key in sm or sm.startswith(our_key):
|
|
115
|
+
self._vllm_client.model = server_model
|
|
116
|
+
return
|
|
117
|
+
|
|
118
|
+
# Normalized fuzzy match (e.g. "llamaguard31b" in "llamaguard31b")
|
|
119
|
+
if our_norm in sm_norm or sm_norm in our_norm:
|
|
120
|
+
self._vllm_client.model = server_model
|
|
121
|
+
return
|
|
122
|
+
|
|
123
|
+
# HF name match
|
|
124
|
+
if hf_name and (hf_name in sm or sm in hf_name):
|
|
125
|
+
self._vllm_client.model = server_model
|
|
126
|
+
return
|
|
127
|
+
|
|
128
|
+
# No match found — VLLMClient will fall back to server default
|
|
129
|
+
|
|
130
|
+
def _get_hf_model_name(self) -> str:
|
|
131
|
+
"""Get the HuggingFace model name. Override in subclasses if needed."""
|
|
132
|
+
return self.HF_MODEL_NAME
|
|
133
|
+
|
|
134
|
+
def _load_transformers_model(self):
|
|
135
|
+
"""Load the model using transformers library."""
|
|
136
|
+
if self._transformers_model is not None:
|
|
137
|
+
return
|
|
138
|
+
|
|
139
|
+
try:
|
|
140
|
+
import torch
|
|
141
|
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
|
142
|
+
except ImportError:
|
|
143
|
+
raise ImportError(
|
|
144
|
+
"transformers and torch packages required for local model backends. "
|
|
145
|
+
"Install with: pip install torch transformers accelerate"
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
model_name = self._get_hf_model_name()
|
|
149
|
+
|
|
150
|
+
# Determine device
|
|
151
|
+
if self._device == "auto":
|
|
152
|
+
if torch.cuda.is_available():
|
|
153
|
+
device = "cuda"
|
|
154
|
+
elif hasattr(torch.backends, "mps") and torch.backends.mps.is_available():
|
|
155
|
+
device = "mps"
|
|
156
|
+
else:
|
|
157
|
+
device = "cpu"
|
|
158
|
+
else:
|
|
159
|
+
device = self._device
|
|
160
|
+
|
|
161
|
+
# Load tokenizer
|
|
162
|
+
self._tokenizer = AutoTokenizer.from_pretrained(
|
|
163
|
+
model_name,
|
|
164
|
+
token=self._hf_token,
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
# Determine dtype and load kwargs
|
|
168
|
+
if device in ("cuda", "mps"):
|
|
169
|
+
dtype = torch.float16
|
|
170
|
+
else:
|
|
171
|
+
dtype = torch.float32
|
|
172
|
+
|
|
173
|
+
load_kwargs = {
|
|
174
|
+
"torch_dtype": dtype,
|
|
175
|
+
"token": self._hf_token,
|
|
176
|
+
"low_cpu_mem_usage": True,
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if self._load_in_8bit:
|
|
180
|
+
load_kwargs["load_in_8bit"] = True
|
|
181
|
+
elif self._load_in_4bit:
|
|
182
|
+
load_kwargs["load_in_4bit"] = True
|
|
183
|
+
|
|
184
|
+
# Load model
|
|
185
|
+
self._transformers_model = AutoModelForCausalLM.from_pretrained(
|
|
186
|
+
model_name,
|
|
187
|
+
**load_kwargs,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
if not (self._load_in_8bit or self._load_in_4bit):
|
|
191
|
+
self._transformers_model.to(device)
|
|
192
|
+
|
|
193
|
+
self._transformers_model.eval()
|
|
194
|
+
self._transformers_device = device
|
|
195
|
+
|
|
196
|
+
def _generate_with_transformers(
|
|
197
|
+
self,
|
|
198
|
+
prompt: str,
|
|
199
|
+
max_new_tokens: Optional[int] = None,
|
|
200
|
+
temperature: Optional[float] = None,
|
|
201
|
+
) -> str:
|
|
202
|
+
"""
|
|
203
|
+
Generate text using local transformers model.
|
|
204
|
+
|
|
205
|
+
Args:
|
|
206
|
+
prompt: Input prompt
|
|
207
|
+
max_new_tokens: Max tokens to generate
|
|
208
|
+
temperature: Sampling temperature
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
Generated text (response only, not including prompt)
|
|
212
|
+
"""
|
|
213
|
+
import torch
|
|
214
|
+
|
|
215
|
+
self._load_transformers_model()
|
|
216
|
+
|
|
217
|
+
max_tokens = max_new_tokens or self.MAX_NEW_TOKENS
|
|
218
|
+
temp = temperature or self.TEMPERATURE
|
|
219
|
+
|
|
220
|
+
inputs = self._tokenizer(prompt, return_tensors="pt").to(self._transformers_device)
|
|
221
|
+
prompt_length = inputs.input_ids.shape[1]
|
|
222
|
+
|
|
223
|
+
with torch.no_grad():
|
|
224
|
+
outputs = self._transformers_model.generate(
|
|
225
|
+
**inputs,
|
|
226
|
+
max_new_tokens=max_tokens,
|
|
227
|
+
temperature=max(temp, 0.01),
|
|
228
|
+
do_sample=temp > 0,
|
|
229
|
+
pad_token_id=self._tokenizer.eos_token_id,
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
# Decode only the generated tokens (excluding prompt)
|
|
233
|
+
generated_tokens = outputs[0][prompt_length:]
|
|
234
|
+
response = self._tokenizer.decode(generated_tokens, skip_special_tokens=True)
|
|
235
|
+
|
|
236
|
+
return response
|
|
237
|
+
|
|
238
|
+
@abstractmethod
|
|
239
|
+
def _format_prompt(
|
|
240
|
+
self,
|
|
241
|
+
content: str,
|
|
242
|
+
rail_type: RailType,
|
|
243
|
+
context: Optional[str] = None,
|
|
244
|
+
) -> str:
|
|
245
|
+
"""
|
|
246
|
+
Format content into model-specific prompt.
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
content: Content to classify
|
|
250
|
+
rail_type: Type of rail (input, output, retrieval)
|
|
251
|
+
context: Optional context (e.g., for output rail)
|
|
252
|
+
|
|
253
|
+
Returns:
|
|
254
|
+
Formatted prompt string
|
|
255
|
+
"""
|
|
256
|
+
pass
|
|
257
|
+
|
|
258
|
+
@abstractmethod
|
|
259
|
+
def _parse_response(
|
|
260
|
+
self,
|
|
261
|
+
response: str,
|
|
262
|
+
content: str,
|
|
263
|
+
rail_type: RailType,
|
|
264
|
+
) -> List[GuardrailResult]:
|
|
265
|
+
"""
|
|
266
|
+
Parse model response into GuardrailResult objects.
|
|
267
|
+
|
|
268
|
+
Args:
|
|
269
|
+
response: Raw model response text
|
|
270
|
+
content: Original content that was classified
|
|
271
|
+
rail_type: Type of rail
|
|
272
|
+
|
|
273
|
+
Returns:
|
|
274
|
+
List of GuardrailResult objects
|
|
275
|
+
"""
|
|
276
|
+
pass
|
|
277
|
+
|
|
278
|
+
def classify(
|
|
279
|
+
self,
|
|
280
|
+
content: str,
|
|
281
|
+
rail_type: RailType,
|
|
282
|
+
context: Optional[str] = None,
|
|
283
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
284
|
+
) -> List[GuardrailResult]:
|
|
285
|
+
"""
|
|
286
|
+
Classify content using local model.
|
|
287
|
+
|
|
288
|
+
Args:
|
|
289
|
+
content: Content to classify
|
|
290
|
+
rail_type: Type of rail
|
|
291
|
+
context: Optional context
|
|
292
|
+
metadata: Optional metadata
|
|
293
|
+
|
|
294
|
+
Returns:
|
|
295
|
+
List of GuardrailResult objects
|
|
296
|
+
"""
|
|
297
|
+
start_time = time.time()
|
|
298
|
+
|
|
299
|
+
# Handle empty content
|
|
300
|
+
if not content or not content.strip():
|
|
301
|
+
return [
|
|
302
|
+
GuardrailResult(
|
|
303
|
+
passed=True,
|
|
304
|
+
category="empty",
|
|
305
|
+
score=0.0,
|
|
306
|
+
model=self.model_name,
|
|
307
|
+
reason="Empty or whitespace-only content",
|
|
308
|
+
action="pass",
|
|
309
|
+
latency_ms=(time.time() - start_time) * 1000,
|
|
310
|
+
)
|
|
311
|
+
]
|
|
312
|
+
|
|
313
|
+
try:
|
|
314
|
+
# Format prompt
|
|
315
|
+
prompt = self._format_prompt(content, rail_type, context)
|
|
316
|
+
|
|
317
|
+
# Generate response
|
|
318
|
+
if self._use_vllm and self._vllm_client:
|
|
319
|
+
# Use chat endpoint — lets the server apply its own chat
|
|
320
|
+
# template (required for ollama, also works with VLLM).
|
|
321
|
+
# Send raw content so safety models use their built-in training
|
|
322
|
+
# rather than getting confused by our prompt template.
|
|
323
|
+
vllm_response = self._vllm_client.chat(
|
|
324
|
+
messages=[{"role": "user", "content": content}],
|
|
325
|
+
max_tokens=self.MAX_NEW_TOKENS,
|
|
326
|
+
temperature=self.TEMPERATURE,
|
|
327
|
+
)
|
|
328
|
+
response_text = vllm_response.text
|
|
329
|
+
else:
|
|
330
|
+
response_text = self._generate_with_transformers(prompt)
|
|
331
|
+
|
|
332
|
+
elapsed_ms = (time.time() - start_time) * 1000
|
|
333
|
+
|
|
334
|
+
# Parse response
|
|
335
|
+
results = self._parse_response(response_text, content, rail_type)
|
|
336
|
+
|
|
337
|
+
# Update latency in results
|
|
338
|
+
for result in results:
|
|
339
|
+
result.latency_ms = elapsed_ms
|
|
340
|
+
|
|
341
|
+
return results
|
|
342
|
+
|
|
343
|
+
except Exception as e:
|
|
344
|
+
elapsed_ms = (time.time() - start_time) * 1000
|
|
345
|
+
return [
|
|
346
|
+
GuardrailResult(
|
|
347
|
+
passed=False,
|
|
348
|
+
category="error",
|
|
349
|
+
score=0.0,
|
|
350
|
+
model=self.model_name,
|
|
351
|
+
reason=f"Local model error: {str(e)}",
|
|
352
|
+
action="block",
|
|
353
|
+
latency_ms=elapsed_ms,
|
|
354
|
+
)
|
|
355
|
+
]
|
|
356
|
+
|
|
357
|
+
async def classify_async(
|
|
358
|
+
self,
|
|
359
|
+
content: str,
|
|
360
|
+
rail_type: RailType,
|
|
361
|
+
context: Optional[str] = None,
|
|
362
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
363
|
+
) -> List[GuardrailResult]:
|
|
364
|
+
"""
|
|
365
|
+
Async version of classify.
|
|
366
|
+
|
|
367
|
+
Uses VLLM async client if available, otherwise falls back to sync.
|
|
368
|
+
|
|
369
|
+
Args:
|
|
370
|
+
content: Content to classify
|
|
371
|
+
rail_type: Type of rail
|
|
372
|
+
context: Optional context
|
|
373
|
+
metadata: Optional metadata
|
|
374
|
+
|
|
375
|
+
Returns:
|
|
376
|
+
List of GuardrailResult objects
|
|
377
|
+
"""
|
|
378
|
+
start_time = time.time()
|
|
379
|
+
|
|
380
|
+
# Handle empty content
|
|
381
|
+
if not content or not content.strip():
|
|
382
|
+
return [
|
|
383
|
+
GuardrailResult(
|
|
384
|
+
passed=True,
|
|
385
|
+
category="empty",
|
|
386
|
+
score=0.0,
|
|
387
|
+
model=self.model_name,
|
|
388
|
+
reason="Empty or whitespace-only content",
|
|
389
|
+
action="pass",
|
|
390
|
+
latency_ms=(time.time() - start_time) * 1000,
|
|
391
|
+
)
|
|
392
|
+
]
|
|
393
|
+
|
|
394
|
+
try:
|
|
395
|
+
# Format prompt
|
|
396
|
+
prompt = self._format_prompt(content, rail_type, context)
|
|
397
|
+
|
|
398
|
+
# Generate response
|
|
399
|
+
if self._use_vllm and self._vllm_client:
|
|
400
|
+
vllm_response = await self._vllm_client.chat_async(
|
|
401
|
+
messages=[{"role": "user", "content": content}],
|
|
402
|
+
max_tokens=self.MAX_NEW_TOKENS,
|
|
403
|
+
temperature=self.TEMPERATURE,
|
|
404
|
+
)
|
|
405
|
+
response_text = vllm_response.text
|
|
406
|
+
else:
|
|
407
|
+
# Fall back to sync for transformers
|
|
408
|
+
import asyncio
|
|
409
|
+
response_text = await asyncio.get_event_loop().run_in_executor(
|
|
410
|
+
None,
|
|
411
|
+
lambda: self._generate_with_transformers(prompt)
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
elapsed_ms = (time.time() - start_time) * 1000
|
|
415
|
+
|
|
416
|
+
# Parse response
|
|
417
|
+
results = self._parse_response(response_text, content, rail_type)
|
|
418
|
+
|
|
419
|
+
# Update latency in results
|
|
420
|
+
for result in results:
|
|
421
|
+
result.latency_ms = elapsed_ms
|
|
422
|
+
|
|
423
|
+
return results
|
|
424
|
+
|
|
425
|
+
except Exception as e:
|
|
426
|
+
elapsed_ms = (time.time() - start_time) * 1000
|
|
427
|
+
return [
|
|
428
|
+
GuardrailResult(
|
|
429
|
+
passed=False,
|
|
430
|
+
category="error",
|
|
431
|
+
score=0.0,
|
|
432
|
+
model=self.model_name,
|
|
433
|
+
reason=f"Local model error: {str(e)}",
|
|
434
|
+
action="block",
|
|
435
|
+
latency_ms=elapsed_ms,
|
|
436
|
+
)
|
|
437
|
+
]
|
|
438
|
+
|
|
439
|
+
# Shared keyword-based category inference for local models that
|
|
440
|
+
# return binary safe/unsafe without fine-grained categories.
|
|
441
|
+
_CATEGORY_KEYWORDS = {
|
|
442
|
+
"violence": ["violence", "violent", "kill", "murder", "attack", "weapon", "harm", "bomb", "gun", "hurt"],
|
|
443
|
+
"self_harm": ["suicide", "self-harm", "self harm", "cut myself", "end my life", "kill myself"],
|
|
444
|
+
"hate_speech": ["hate", "racist", "sexist", "discrimination", "discriminate", "slur"],
|
|
445
|
+
"sexual_content": ["sexual", "explicit", "nude", "porn"],
|
|
446
|
+
"harassment": ["harass", "bully", "threaten", "intimidate"],
|
|
447
|
+
"illegal_activity": ["illegal", "drug", "hack", "steal", "fraud", "crime", "counterfeit"],
|
|
448
|
+
"jailbreak": ["jailbreak", "ignore", "bypass", "pretend", "roleplay", "dan"],
|
|
449
|
+
"prompt_injection": ["ignore previous", "new instructions", "system prompt", "override", "injection"],
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
def _infer_categories(self, content: str, response: str) -> List[str]:
|
|
453
|
+
"""Infer safety categories from content + response via keyword matching."""
|
|
454
|
+
combined = (content + " " + response).lower()
|
|
455
|
+
categories = [
|
|
456
|
+
cat for cat, keywords in self._CATEGORY_KEYWORDS.items()
|
|
457
|
+
if any(kw in combined for kw in keywords)
|
|
458
|
+
]
|
|
459
|
+
return categories if categories else ["harmful_content"]
|
|
460
|
+
|
|
461
|
+
def is_available(self) -> bool:
|
|
462
|
+
"""
|
|
463
|
+
Check if this backend is available.
|
|
464
|
+
|
|
465
|
+
Returns:
|
|
466
|
+
True if VLLM server is up or transformers can load the model
|
|
467
|
+
"""
|
|
468
|
+
if self._use_vllm:
|
|
469
|
+
return True
|
|
470
|
+
|
|
471
|
+
# Check if we can load via transformers
|
|
472
|
+
try:
|
|
473
|
+
import torch
|
|
474
|
+
has_gpu = torch.cuda.is_available() or (
|
|
475
|
+
hasattr(torch.backends, "mps") and torch.backends.mps.is_available()
|
|
476
|
+
)
|
|
477
|
+
return has_gpu or self._device == "cpu"
|
|
478
|
+
except ImportError:
|
|
479
|
+
return False
|