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,160 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Types for Agent Evaluation.
|
|
3
|
+
|
|
4
|
+
These types support trajectory-based evaluation of AI agent performance,
|
|
5
|
+
including multi-step analysis and tool usage tracking.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Any, Dict, List, Optional
|
|
9
|
+
from pydantic import BaseModel, Field
|
|
10
|
+
|
|
11
|
+
from ...types import BaseMetricInput
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ToolCall(BaseModel):
|
|
15
|
+
"""Represents a tool/function call made by an agent."""
|
|
16
|
+
|
|
17
|
+
name: str = Field(..., description="Name of the tool called")
|
|
18
|
+
arguments: Dict[str, Any] = Field(
|
|
19
|
+
default_factory=dict,
|
|
20
|
+
description="Arguments passed to the tool"
|
|
21
|
+
)
|
|
22
|
+
result: Optional[Any] = Field(
|
|
23
|
+
default=None,
|
|
24
|
+
description="Result returned from the tool"
|
|
25
|
+
)
|
|
26
|
+
success: bool = Field(
|
|
27
|
+
default=True,
|
|
28
|
+
description="Whether the tool call succeeded"
|
|
29
|
+
)
|
|
30
|
+
error: Optional[str] = Field(
|
|
31
|
+
default=None,
|
|
32
|
+
description="Error message if the call failed"
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class AgentStep(BaseModel):
|
|
37
|
+
"""Represents a single step in an agent's trajectory."""
|
|
38
|
+
|
|
39
|
+
step_number: int = Field(..., description="Step number in the trajectory (1-indexed)")
|
|
40
|
+
thought: Optional[str] = Field(
|
|
41
|
+
default=None,
|
|
42
|
+
description="Agent's reasoning/thought for this step"
|
|
43
|
+
)
|
|
44
|
+
action: Optional[str] = Field(
|
|
45
|
+
default=None,
|
|
46
|
+
description="Action taken by the agent"
|
|
47
|
+
)
|
|
48
|
+
tool_calls: List[ToolCall] = Field(
|
|
49
|
+
default_factory=list,
|
|
50
|
+
description="Tool calls made in this step"
|
|
51
|
+
)
|
|
52
|
+
observation: Optional[str] = Field(
|
|
53
|
+
default=None,
|
|
54
|
+
description="Observation from the environment after the action"
|
|
55
|
+
)
|
|
56
|
+
is_final: bool = Field(
|
|
57
|
+
default=False,
|
|
58
|
+
description="Whether this is the final step"
|
|
59
|
+
)
|
|
60
|
+
timestamp_ms: Optional[int] = Field(
|
|
61
|
+
default=None,
|
|
62
|
+
description="Timestamp of the step in milliseconds"
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class TaskDefinition(BaseModel):
|
|
67
|
+
"""Definition of the task the agent should accomplish."""
|
|
68
|
+
|
|
69
|
+
description: str = Field(..., description="Natural language description of the task")
|
|
70
|
+
expected_outcome: Optional[str] = Field(
|
|
71
|
+
default=None,
|
|
72
|
+
description="Expected outcome or result"
|
|
73
|
+
)
|
|
74
|
+
required_tools: Optional[List[str]] = Field(
|
|
75
|
+
default=None,
|
|
76
|
+
description="List of tools required to complete the task"
|
|
77
|
+
)
|
|
78
|
+
max_steps: Optional[int] = Field(
|
|
79
|
+
default=None,
|
|
80
|
+
description="Maximum allowed steps"
|
|
81
|
+
)
|
|
82
|
+
success_criteria: Optional[List[str]] = Field(
|
|
83
|
+
default=None,
|
|
84
|
+
description="Criteria for determining task success"
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class ExpectedStep(BaseModel):
|
|
89
|
+
"""Expected step in the optimal trajectory."""
|
|
90
|
+
|
|
91
|
+
description: str = Field(..., description="Description of the expected action")
|
|
92
|
+
required_tools: Optional[List[str]] = Field(
|
|
93
|
+
default=None,
|
|
94
|
+
description="Tools that should be used in this step"
|
|
95
|
+
)
|
|
96
|
+
key_arguments: Optional[Dict[str, Any]] = Field(
|
|
97
|
+
default=None,
|
|
98
|
+
description="Key arguments that should be present"
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class AgentTrajectoryInput(BaseMetricInput):
|
|
103
|
+
"""
|
|
104
|
+
Input for agent trajectory evaluation metrics.
|
|
105
|
+
|
|
106
|
+
Evaluates multi-step agent execution including:
|
|
107
|
+
- Task completion
|
|
108
|
+
- Step efficiency
|
|
109
|
+
- Tool usage accuracy
|
|
110
|
+
- Trajectory quality
|
|
111
|
+
"""
|
|
112
|
+
|
|
113
|
+
# The agent's execution trajectory
|
|
114
|
+
trajectory: List[AgentStep] = Field(
|
|
115
|
+
...,
|
|
116
|
+
description="List of steps taken by the agent"
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# The task definition
|
|
120
|
+
task: TaskDefinition = Field(
|
|
121
|
+
...,
|
|
122
|
+
description="Definition of the task to accomplish"
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
# Optional: expected trajectory for comparison
|
|
126
|
+
expected_trajectory: Optional[List[ExpectedStep]] = Field(
|
|
127
|
+
default=None,
|
|
128
|
+
description="Expected/optimal trajectory for comparison"
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# Optional: final result produced by the agent
|
|
132
|
+
final_result: Optional[Any] = Field(
|
|
133
|
+
default=None,
|
|
134
|
+
description="Final output/result from the agent"
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
# Optional: ground truth result for comparison
|
|
138
|
+
expected_result: Optional[Any] = Field(
|
|
139
|
+
default=None,
|
|
140
|
+
description="Expected/ground truth result"
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
# Available tools for the task
|
|
144
|
+
available_tools: Optional[List[str]] = Field(
|
|
145
|
+
default=None,
|
|
146
|
+
description="List of available tools the agent can use"
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class TrajectoryAnalysis(BaseModel):
|
|
151
|
+
"""Detailed analysis of an agent trajectory."""
|
|
152
|
+
|
|
153
|
+
total_steps: int = Field(..., description="Total number of steps taken")
|
|
154
|
+
successful_tool_calls: int = Field(..., description="Number of successful tool calls")
|
|
155
|
+
failed_tool_calls: int = Field(..., description="Number of failed tool calls")
|
|
156
|
+
unique_tools_used: List[str] = Field(default_factory=list, description="List of unique tools used")
|
|
157
|
+
unnecessary_steps: int = Field(default=0, description="Number of unnecessary/redundant steps")
|
|
158
|
+
backtracking_count: int = Field(default=0, description="Number of times agent backtracked")
|
|
159
|
+
task_completed: bool = Field(..., description="Whether the task was completed")
|
|
160
|
+
efficiency_score: float = Field(..., description="Efficiency score (0-1)")
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Any, Dict, List, Optional, Type, TypeVar
|
|
3
|
+
from pydantic import BaseModel, ValidationError
|
|
4
|
+
import re
|
|
5
|
+
import json
|
|
6
|
+
|
|
7
|
+
from .base_metric import BaseMetric
|
|
8
|
+
from .heuristics.json_metrics import ContainsJson
|
|
9
|
+
from ..types import TextMetricInput
|
|
10
|
+
from .llm_as_judges.types import BaseLLMJudgeInput
|
|
11
|
+
from ..llm.base_llm_provider import LLMProvider
|
|
12
|
+
from ..llm.providers.litellm import LiteLLMProvider
|
|
13
|
+
|
|
14
|
+
LLMJudgeInputType = TypeVar("LLMJudgeInputType", bound=BaseLLMJudgeInput)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class BaseLLMJudgeMetric(BaseMetric[LLMJudgeInputType], ABC):
|
|
18
|
+
"""
|
|
19
|
+
The definitive, Pydantic-driven base class for LLM-as-a-judge metrics.
|
|
20
|
+
It orchestrates prompt creation, calling a provider for a structured response,
|
|
21
|
+
and robustly parsing the output into a validated Pydantic model.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
provider: LLMProvider,
|
|
27
|
+
config: Optional[Dict[str, Any]] = None,
|
|
28
|
+
**litellm_kwargs,
|
|
29
|
+
):
|
|
30
|
+
super().__init__(config)
|
|
31
|
+
self.provider = provider
|
|
32
|
+
self.model = self.config.get("model", "gpt-4o")
|
|
33
|
+
self.provider_kwargs = {**litellm_kwargs}
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
@abstractmethod
|
|
37
|
+
def output_pydantic_model(self) -> Type[BaseModel]:
|
|
38
|
+
"""The Pydantic model defining the structure of the judge's output."""
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
@abstractmethod
|
|
42
|
+
def _create_prompt_messages(
|
|
43
|
+
self, inputs: LLMJudgeInputType
|
|
44
|
+
) -> List[Dict[str, Any]]:
|
|
45
|
+
"""Creates the full prompt message list for the API call."""
|
|
46
|
+
raise NotImplementedError
|
|
47
|
+
|
|
48
|
+
@abstractmethod
|
|
49
|
+
def _normalize_score(self, parsed_output: BaseModel) -> Dict[str, Any]:
|
|
50
|
+
"""
|
|
51
|
+
Takes the validated Pydantic output object and converts it into the
|
|
52
|
+
final metric result (a dict with 'output' and 'reason' keys).
|
|
53
|
+
"""
|
|
54
|
+
raise NotImplementedError
|
|
55
|
+
|
|
56
|
+
def _parse_response_with_fallback(self, response_text: str) -> BaseModel:
|
|
57
|
+
"""
|
|
58
|
+
Attempts to parse the LLM's response string into the target Pydantic model.
|
|
59
|
+
It first tries a direct parse, and if that fails, it uses a regex-based
|
|
60
|
+
fallback to extract a JSON object and tries again.
|
|
61
|
+
"""
|
|
62
|
+
try:
|
|
63
|
+
return self.output_pydantic_model.model_validate_json(response_text)
|
|
64
|
+
except (ValidationError, json.JSONDecodeError):
|
|
65
|
+
# Fallback attempt: extract JSON from messy text and retry
|
|
66
|
+
# use our metric to check if it contains json
|
|
67
|
+
if (
|
|
68
|
+
ContainsJson().compute_one(
|
|
69
|
+
inputs=TextMetricInput(response=response_text)
|
|
70
|
+
)["output"]
|
|
71
|
+
== 1.0
|
|
72
|
+
):
|
|
73
|
+
match = re.search(r"\{.*\}|\[.*\]", response_text, re.DOTALL)
|
|
74
|
+
cleaned_json_str = match.group(0)
|
|
75
|
+
try:
|
|
76
|
+
return self.output_pydantic_model.model_validate_json(
|
|
77
|
+
cleaned_json_str
|
|
78
|
+
)
|
|
79
|
+
except (ValidationError, json.JSONDecodeError) as final_e:
|
|
80
|
+
raise ValueError(
|
|
81
|
+
"Failed to validate the extracted JSON."
|
|
82
|
+
) from final_e
|
|
83
|
+
else:
|
|
84
|
+
raise ValueError("Failed to find JSON in the response.")
|
|
85
|
+
|
|
86
|
+
def compute_one(self, inputs: LLMJudgeInputType) -> Dict[str, Any]:
|
|
87
|
+
messages = self._create_prompt_messages(inputs)
|
|
88
|
+
|
|
89
|
+
response_format = self.output_pydantic_model
|
|
90
|
+
# response schema check
|
|
91
|
+
if isinstance(self.provider, LiteLLMProvider):
|
|
92
|
+
if not self.provider._supports_schema(self.model):
|
|
93
|
+
response_format = {"type": "json_object"}
|
|
94
|
+
try:
|
|
95
|
+
response_text = self.provider.get_completion(
|
|
96
|
+
model=self.model,
|
|
97
|
+
messages=messages,
|
|
98
|
+
response_format=response_format,
|
|
99
|
+
**self.provider_kwargs,
|
|
100
|
+
)
|
|
101
|
+
except Exception as e:
|
|
102
|
+
return {"output": 0.0, "reason": f"LLM provider failed: {e}"}
|
|
103
|
+
|
|
104
|
+
try:
|
|
105
|
+
parsed_output = self._parse_response_with_fallback(response_text)
|
|
106
|
+
return self._normalize_score(parsed_output)
|
|
107
|
+
except Exception as e:
|
|
108
|
+
return {
|
|
109
|
+
"output": 0.0,
|
|
110
|
+
"reason": f"Failed to parse or validate LLM response. Raw response: '{response_text}'. Error: {e}",
|
|
111
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import (
|
|
3
|
+
Any,
|
|
4
|
+
Dict,
|
|
5
|
+
Generic,
|
|
6
|
+
Iterator,
|
|
7
|
+
List,
|
|
8
|
+
Optional,
|
|
9
|
+
Type,
|
|
10
|
+
TypeVar,
|
|
11
|
+
Union,
|
|
12
|
+
get_args,
|
|
13
|
+
)
|
|
14
|
+
from pydantic import ValidationError
|
|
15
|
+
from typing_extensions import get_original_bases
|
|
16
|
+
import time
|
|
17
|
+
|
|
18
|
+
from ..types import BatchRunResult, EvalResult, BaseMetricInput
|
|
19
|
+
|
|
20
|
+
BaseMetricInputType = TypeVar("BaseMetricInputType", bound=BaseMetricInput)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class BaseMetric(Generic[BaseMetricInputType], ABC):
|
|
24
|
+
"""The abstract base class for all metric evaluations.
|
|
25
|
+
|
|
26
|
+
It provides a unified structure, centralizes batch processing,
|
|
27
|
+
and handles standardized error logging and timing. Subclasses are only
|
|
28
|
+
required to implement the logic for a single computation.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
supports_llm_judge: bool = False
|
|
32
|
+
judge_description: str = ""
|
|
33
|
+
|
|
34
|
+
def __init__(self, config: Optional[Dict[str, Any]] = None) -> None:
|
|
35
|
+
self.config = config or {}
|
|
36
|
+
|
|
37
|
+
# magic code to get the input metric basemodel to use for input validation.
|
|
38
|
+
# This traverses the MRO to find the generic BaseMetric specialization.
|
|
39
|
+
self.input_model: Type[BaseMetricInputType]
|
|
40
|
+
for cls in self.__class__.__mro__:
|
|
41
|
+
for base in get_original_bases(cls):
|
|
42
|
+
if hasattr(base, "__origin__") and base.__origin__ is BaseMetric:
|
|
43
|
+
type_args = get_args(base)
|
|
44
|
+
if type_args:
|
|
45
|
+
self.input_model = type_args[0]
|
|
46
|
+
break
|
|
47
|
+
if hasattr(self, "input_model"):
|
|
48
|
+
break
|
|
49
|
+
|
|
50
|
+
if not hasattr(self, "input_model"):
|
|
51
|
+
raise TypeError(
|
|
52
|
+
f"Could not determine input model for {self.__class__.__name__}. "
|
|
53
|
+
"Ensure it inherits from BaseMetric with a specific input type, "
|
|
54
|
+
"e.g., class MyMetric(BaseMetric[TextMetricInput]):"
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
@abstractmethod
|
|
59
|
+
def metric_name(self) -> str:
|
|
60
|
+
"""The official name of the metric"""
|
|
61
|
+
pass
|
|
62
|
+
|
|
63
|
+
def _validate_and_yield_inputs(
|
|
64
|
+
self,
|
|
65
|
+
inputs: List[Any],
|
|
66
|
+
) -> Iterator[Union[BaseMetricInputType, Exception]]:
|
|
67
|
+
"""
|
|
68
|
+
A generator that validates each item from an input list.
|
|
69
|
+
"""
|
|
70
|
+
for i, item in enumerate(inputs):
|
|
71
|
+
try:
|
|
72
|
+
if isinstance(item, dict):
|
|
73
|
+
# Validate and yield the dictionary as a Pydantic model
|
|
74
|
+
yield self.input_model.model_validate(item)
|
|
75
|
+
elif isinstance(item, self.input_model):
|
|
76
|
+
# The item is already a valid Pydantic model, yield it directly
|
|
77
|
+
yield item
|
|
78
|
+
else:
|
|
79
|
+
# The item is an unsupported type
|
|
80
|
+
raise TypeError(
|
|
81
|
+
f"Item at index {i} has an invalid type '{type(item).__name__}'. "
|
|
82
|
+
f"Expected a 'dict' or a '{self.input_model.__name__}' instance."
|
|
83
|
+
)
|
|
84
|
+
except (ValidationError, TypeError) as e:
|
|
85
|
+
# If validation fails for any reason, yield the exception
|
|
86
|
+
yield e
|
|
87
|
+
|
|
88
|
+
@abstractmethod
|
|
89
|
+
def compute_one(self, inputs: BaseMetricInputType) -> Dict[str, Any]:
|
|
90
|
+
"""
|
|
91
|
+
Computes the metric for a single, strongly-typed input.
|
|
92
|
+
Pydantic validates the data before this method is ever called.
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
A dictionary containing at least an 'output' key with the score.
|
|
96
|
+
Can optionally include a 'reason' key for more details.
|
|
97
|
+
"""
|
|
98
|
+
raise NotImplementedError
|
|
99
|
+
|
|
100
|
+
def evaluate(
|
|
101
|
+
self, inputs: Union[List[BaseMetricInputType], List[Dict[str, Any]]]
|
|
102
|
+
) -> BatchRunResult:
|
|
103
|
+
"""
|
|
104
|
+
Evaluates the metric over a batch of strongly-typed inputs.
|
|
105
|
+
"""
|
|
106
|
+
if not inputs:
|
|
107
|
+
return BatchRunResult(eval_results=[])
|
|
108
|
+
|
|
109
|
+
eval_results: List[Optional[EvalResult]] = []
|
|
110
|
+
|
|
111
|
+
# Use the generator to process each item one by one
|
|
112
|
+
for prepared_item in self._validate_and_yield_inputs(inputs):
|
|
113
|
+
start_time = time.perf_counter()
|
|
114
|
+
output = 0.0
|
|
115
|
+
reason = ""
|
|
116
|
+
|
|
117
|
+
# Check if the prepared_item is an exception from the validation step
|
|
118
|
+
if isinstance(prepared_item, Exception):
|
|
119
|
+
reason = f"Input validation failed: {prepared_item}"
|
|
120
|
+
else:
|
|
121
|
+
# If validation succeeded, run the actual metric computation
|
|
122
|
+
result_dict = self.compute_one(prepared_item)
|
|
123
|
+
output = result_dict.get("output")
|
|
124
|
+
reason = result_dict.get("reason")
|
|
125
|
+
|
|
126
|
+
end_time = time.perf_counter()
|
|
127
|
+
runtime_ms = int((end_time - start_time) * 1000)
|
|
128
|
+
|
|
129
|
+
eval_result = EvalResult(
|
|
130
|
+
name=self.metric_name,
|
|
131
|
+
output=output,
|
|
132
|
+
reason=reason,
|
|
133
|
+
runtime=runtime_ms,
|
|
134
|
+
output_type="score", # Default, can be customized if needed
|
|
135
|
+
)
|
|
136
|
+
eval_results.append(eval_result)
|
|
137
|
+
|
|
138
|
+
return BatchRunResult(eval_results=eval_results)
|