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,211 @@
|
|
|
1
|
+
"""Application analyzer for AutoEval.
|
|
2
|
+
|
|
3
|
+
Analyzes application descriptions to understand evaluation needs.
|
|
4
|
+
Supports both LLM-powered and rule-based analysis.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
import logging
|
|
9
|
+
from typing import Optional, Any, Protocol, runtime_checkable
|
|
10
|
+
|
|
11
|
+
from .types import (
|
|
12
|
+
AppAnalysis,
|
|
13
|
+
AppCategory,
|
|
14
|
+
RiskLevel,
|
|
15
|
+
DomainSensitivity,
|
|
16
|
+
AppRequirement,
|
|
17
|
+
)
|
|
18
|
+
from .rules import RuleBasedAnalyzer
|
|
19
|
+
from .prompts import ANALYSIS_SYSTEM_PROMPT, ANALYSIS_USER_PROMPT
|
|
20
|
+
|
|
21
|
+
logger = logging.getLogger(__name__)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@runtime_checkable
|
|
25
|
+
class LLMProvider(Protocol):
|
|
26
|
+
"""Protocol for LLM providers."""
|
|
27
|
+
|
|
28
|
+
def complete(
|
|
29
|
+
self,
|
|
30
|
+
prompt: str,
|
|
31
|
+
system_prompt: Optional[str] = None,
|
|
32
|
+
**kwargs: Any,
|
|
33
|
+
) -> str:
|
|
34
|
+
"""Generate a completion for the given prompt."""
|
|
35
|
+
...
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class AppAnalyzer:
|
|
39
|
+
"""
|
|
40
|
+
Analyzes application descriptions to understand evaluation needs.
|
|
41
|
+
|
|
42
|
+
Supports both LLM-powered and rule-based analysis. When LLM analysis
|
|
43
|
+
fails, automatically falls back to rule-based analysis.
|
|
44
|
+
|
|
45
|
+
Example:
|
|
46
|
+
# With LLM provider
|
|
47
|
+
from fi.evals.llm import LiteLLMProvider
|
|
48
|
+
analyzer = AppAnalyzer(llm_provider=LiteLLMProvider())
|
|
49
|
+
analysis = analyzer.analyze(
|
|
50
|
+
"A customer support chatbot for a healthcare company. "
|
|
51
|
+
"It retrieves patient information and answers questions."
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# Without LLM (rule-based only)
|
|
55
|
+
analyzer = AppAnalyzer(use_llm=False)
|
|
56
|
+
analysis = analyzer.analyze("A RAG-based document Q&A system.")
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
def __init__(
|
|
60
|
+
self,
|
|
61
|
+
llm_provider: Optional[Any] = None,
|
|
62
|
+
model: str = "gpt-4o-mini",
|
|
63
|
+
use_llm: bool = True,
|
|
64
|
+
temperature: float = 0.1,
|
|
65
|
+
):
|
|
66
|
+
"""
|
|
67
|
+
Initialize the analyzer.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
llm_provider: LLM provider for intelligent analysis (optional)
|
|
71
|
+
model: Model to use for LLM analysis
|
|
72
|
+
use_llm: If False, always use rule-based fallback
|
|
73
|
+
temperature: Temperature for LLM generation (lower = more deterministic)
|
|
74
|
+
"""
|
|
75
|
+
self.llm_provider = llm_provider
|
|
76
|
+
self.model = model
|
|
77
|
+
self.use_llm = use_llm and llm_provider is not None
|
|
78
|
+
self.temperature = temperature
|
|
79
|
+
self.rule_analyzer = RuleBasedAnalyzer()
|
|
80
|
+
|
|
81
|
+
def analyze(self, description: str) -> AppAnalysis:
|
|
82
|
+
"""
|
|
83
|
+
Analyze an application description.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
description: Natural language description of the application
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
AppAnalysis with detected requirements and recommendations
|
|
90
|
+
"""
|
|
91
|
+
if not description or not description.strip():
|
|
92
|
+
return AppAnalysis(
|
|
93
|
+
category=AppCategory.UNKNOWN,
|
|
94
|
+
risk_level=RiskLevel.MEDIUM,
|
|
95
|
+
domain_sensitivity=DomainSensitivity.GENERAL,
|
|
96
|
+
requirements=[],
|
|
97
|
+
detected_features=[],
|
|
98
|
+
confidence=0.0,
|
|
99
|
+
explanation="Empty description provided.",
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
if self.use_llm:
|
|
103
|
+
try:
|
|
104
|
+
return self._analyze_with_llm(description)
|
|
105
|
+
except Exception as e:
|
|
106
|
+
logger.warning(f"LLM analysis failed, falling back to rules: {e}")
|
|
107
|
+
return self._analyze_with_rules(description)
|
|
108
|
+
else:
|
|
109
|
+
return self._analyze_with_rules(description)
|
|
110
|
+
|
|
111
|
+
def _analyze_with_llm(self, description: str) -> AppAnalysis:
|
|
112
|
+
"""Use LLM to analyze the description."""
|
|
113
|
+
if not self.llm_provider:
|
|
114
|
+
raise ValueError("LLM provider not configured")
|
|
115
|
+
|
|
116
|
+
prompt = ANALYSIS_USER_PROMPT.format(description=description)
|
|
117
|
+
|
|
118
|
+
# Try different ways to call the LLM provider
|
|
119
|
+
try:
|
|
120
|
+
if hasattr(self.llm_provider, "complete"):
|
|
121
|
+
response = self.llm_provider.complete(
|
|
122
|
+
prompt=prompt,
|
|
123
|
+
system_prompt=ANALYSIS_SYSTEM_PROMPT,
|
|
124
|
+
model=self.model,
|
|
125
|
+
temperature=self.temperature,
|
|
126
|
+
)
|
|
127
|
+
elif hasattr(self.llm_provider, "generate"):
|
|
128
|
+
response = self.llm_provider.generate(
|
|
129
|
+
prompt=prompt,
|
|
130
|
+
system_prompt=ANALYSIS_SYSTEM_PROMPT,
|
|
131
|
+
model=self.model,
|
|
132
|
+
temperature=self.temperature,
|
|
133
|
+
)
|
|
134
|
+
elif callable(self.llm_provider):
|
|
135
|
+
response = self.llm_provider(
|
|
136
|
+
prompt=prompt,
|
|
137
|
+
system_prompt=ANALYSIS_SYSTEM_PROMPT,
|
|
138
|
+
)
|
|
139
|
+
else:
|
|
140
|
+
raise ValueError(f"Unknown LLM provider type: {type(self.llm_provider)}")
|
|
141
|
+
except TypeError as e:
|
|
142
|
+
# Only retry with simpler args if it's a signature mismatch
|
|
143
|
+
if "unexpected keyword argument" in str(e) or "positional argument" in str(e):
|
|
144
|
+
if hasattr(self.llm_provider, "complete"):
|
|
145
|
+
response = self.llm_provider.complete(prompt)
|
|
146
|
+
else:
|
|
147
|
+
raise
|
|
148
|
+
else:
|
|
149
|
+
raise
|
|
150
|
+
|
|
151
|
+
# Parse JSON response
|
|
152
|
+
return self._parse_llm_response(response, description)
|
|
153
|
+
|
|
154
|
+
def _parse_llm_response(self, response: str, description: str) -> AppAnalysis:
|
|
155
|
+
"""Parse LLM response into AppAnalysis."""
|
|
156
|
+
# Clean up response - remove markdown code blocks if present
|
|
157
|
+
response = response.strip()
|
|
158
|
+
if response.startswith("```"):
|
|
159
|
+
lines = response.split("\n")
|
|
160
|
+
response = "\n".join(lines[1:-1] if lines[-1] == "```" else lines[1:])
|
|
161
|
+
|
|
162
|
+
try:
|
|
163
|
+
data = json.loads(response)
|
|
164
|
+
except json.JSONDecodeError as e:
|
|
165
|
+
logger.warning(f"Failed to parse LLM response as JSON: {e}")
|
|
166
|
+
# Fall back to rule-based
|
|
167
|
+
return self._analyze_with_rules(description)
|
|
168
|
+
|
|
169
|
+
# Parse with defaults
|
|
170
|
+
try:
|
|
171
|
+
category = AppCategory(data.get("category", "unknown"))
|
|
172
|
+
except ValueError:
|
|
173
|
+
category = AppCategory.UNKNOWN
|
|
174
|
+
|
|
175
|
+
try:
|
|
176
|
+
risk_level = RiskLevel(data.get("risk_level", "medium"))
|
|
177
|
+
except ValueError:
|
|
178
|
+
risk_level = RiskLevel.MEDIUM
|
|
179
|
+
|
|
180
|
+
try:
|
|
181
|
+
domain_sensitivity = DomainSensitivity(
|
|
182
|
+
data.get("domain_sensitivity", "general")
|
|
183
|
+
)
|
|
184
|
+
except ValueError:
|
|
185
|
+
domain_sensitivity = DomainSensitivity.GENERAL
|
|
186
|
+
|
|
187
|
+
requirements = []
|
|
188
|
+
for req_data in data.get("requirements", []):
|
|
189
|
+
requirements.append(
|
|
190
|
+
AppRequirement(
|
|
191
|
+
category=req_data.get("category", ""),
|
|
192
|
+
importance=req_data.get("importance", "recommended"),
|
|
193
|
+
reason=req_data.get("reason", ""),
|
|
194
|
+
suggested_evals=req_data.get("suggested_evals", []),
|
|
195
|
+
suggested_scanners=req_data.get("suggested_scanners", []),
|
|
196
|
+
)
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
return AppAnalysis(
|
|
200
|
+
category=category,
|
|
201
|
+
risk_level=risk_level,
|
|
202
|
+
domain_sensitivity=domain_sensitivity,
|
|
203
|
+
requirements=requirements,
|
|
204
|
+
detected_features=data.get("detected_features", []),
|
|
205
|
+
confidence=0.85, # LLM analysis has higher confidence
|
|
206
|
+
explanation=data.get("explanation", "Analysis performed by LLM."),
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
def _analyze_with_rules(self, description: str) -> AppAnalysis:
|
|
210
|
+
"""Use rule-based analysis."""
|
|
211
|
+
return self.rule_analyzer.analyze(description)
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
"""Configuration classes for AutoEval."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import List, Dict, Any, Optional
|
|
5
|
+
from copy import deepcopy
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class EvalConfig:
|
|
10
|
+
"""Configuration for a single evaluation."""
|
|
11
|
+
|
|
12
|
+
name: str
|
|
13
|
+
enabled: bool = True
|
|
14
|
+
threshold: float = 0.7
|
|
15
|
+
weight: float = 1.0
|
|
16
|
+
params: Dict[str, Any] = field(default_factory=dict)
|
|
17
|
+
model: Optional[str] = None # LLM model for augmented metrics
|
|
18
|
+
augment: bool = False # Enable local→LLM augmentation
|
|
19
|
+
|
|
20
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
21
|
+
"""Convert to dictionary."""
|
|
22
|
+
result = {
|
|
23
|
+
"name": self.name,
|
|
24
|
+
"enabled": self.enabled,
|
|
25
|
+
"threshold": self.threshold,
|
|
26
|
+
"weight": self.weight,
|
|
27
|
+
}
|
|
28
|
+
if self.params:
|
|
29
|
+
result["params"] = self.params
|
|
30
|
+
if self.model:
|
|
31
|
+
result["model"] = self.model
|
|
32
|
+
if self.augment:
|
|
33
|
+
result["augment"] = self.augment
|
|
34
|
+
return result
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def from_dict(cls, data: Dict[str, Any]) -> "EvalConfig":
|
|
38
|
+
"""Create from dictionary."""
|
|
39
|
+
return cls(
|
|
40
|
+
name=data["name"],
|
|
41
|
+
enabled=data.get("enabled", True),
|
|
42
|
+
threshold=data.get("threshold", 0.7),
|
|
43
|
+
weight=data.get("weight", 1.0),
|
|
44
|
+
params=data.get("params", {}),
|
|
45
|
+
model=data.get("model"),
|
|
46
|
+
augment=data.get("augment", False),
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
def copy(self) -> "EvalConfig":
|
|
50
|
+
"""Create a deep copy."""
|
|
51
|
+
return EvalConfig(
|
|
52
|
+
name=self.name,
|
|
53
|
+
enabled=self.enabled,
|
|
54
|
+
threshold=self.threshold,
|
|
55
|
+
weight=self.weight,
|
|
56
|
+
params=deepcopy(self.params),
|
|
57
|
+
model=self.model,
|
|
58
|
+
augment=self.augment,
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@dataclass
|
|
63
|
+
class ScannerConfig:
|
|
64
|
+
"""Configuration for a single scanner."""
|
|
65
|
+
|
|
66
|
+
name: str
|
|
67
|
+
enabled: bool = True
|
|
68
|
+
threshold: float = 0.7
|
|
69
|
+
action: str = "block" # block, flag, warn, redact
|
|
70
|
+
params: Dict[str, Any] = field(default_factory=dict)
|
|
71
|
+
|
|
72
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
73
|
+
"""Convert to dictionary."""
|
|
74
|
+
result = {
|
|
75
|
+
"name": self.name,
|
|
76
|
+
"enabled": self.enabled,
|
|
77
|
+
"threshold": self.threshold,
|
|
78
|
+
"action": self.action,
|
|
79
|
+
}
|
|
80
|
+
if self.params:
|
|
81
|
+
result["params"] = self.params
|
|
82
|
+
return result
|
|
83
|
+
|
|
84
|
+
@classmethod
|
|
85
|
+
def from_dict(cls, data: Dict[str, Any]) -> "ScannerConfig":
|
|
86
|
+
"""Create from dictionary."""
|
|
87
|
+
return cls(
|
|
88
|
+
name=data["name"],
|
|
89
|
+
enabled=data.get("enabled", True),
|
|
90
|
+
threshold=data.get("threshold", 0.7),
|
|
91
|
+
action=data.get("action", "block"),
|
|
92
|
+
params=data.get("params", {}),
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
def copy(self) -> "ScannerConfig":
|
|
96
|
+
"""Create a deep copy."""
|
|
97
|
+
return ScannerConfig(
|
|
98
|
+
name=self.name,
|
|
99
|
+
enabled=self.enabled,
|
|
100
|
+
threshold=self.threshold,
|
|
101
|
+
action=self.action,
|
|
102
|
+
params=deepcopy(self.params),
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@dataclass
|
|
107
|
+
class AutoEvalConfig:
|
|
108
|
+
"""Complete configuration for an auto-generated evaluation pipeline."""
|
|
109
|
+
|
|
110
|
+
name: str
|
|
111
|
+
description: str = ""
|
|
112
|
+
version: str = "1.0.0"
|
|
113
|
+
|
|
114
|
+
# Analysis metadata
|
|
115
|
+
app_category: str = "unknown"
|
|
116
|
+
risk_level: str = "medium"
|
|
117
|
+
domain_sensitivity: str = "general"
|
|
118
|
+
|
|
119
|
+
# Evaluations
|
|
120
|
+
evaluations: List[EvalConfig] = field(default_factory=list)
|
|
121
|
+
|
|
122
|
+
# Scanners
|
|
123
|
+
scanners: List[ScannerConfig] = field(default_factory=list)
|
|
124
|
+
|
|
125
|
+
# Execution settings
|
|
126
|
+
execution_mode: str = "non_blocking" # blocking, non_blocking, distributed
|
|
127
|
+
parallel_workers: int = 4
|
|
128
|
+
timeout_seconds: int = 30
|
|
129
|
+
fail_fast: bool = False
|
|
130
|
+
|
|
131
|
+
# Thresholds
|
|
132
|
+
global_pass_rate: float = 0.8
|
|
133
|
+
|
|
134
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
135
|
+
"""Convert to dictionary for export."""
|
|
136
|
+
return {
|
|
137
|
+
"version": self.version,
|
|
138
|
+
"name": self.name,
|
|
139
|
+
"description": self.description,
|
|
140
|
+
"metadata": {
|
|
141
|
+
"app_category": self.app_category,
|
|
142
|
+
"risk_level": self.risk_level,
|
|
143
|
+
"domain_sensitivity": self.domain_sensitivity,
|
|
144
|
+
"generated_by": "autoeval",
|
|
145
|
+
},
|
|
146
|
+
"execution": {
|
|
147
|
+
"mode": self.execution_mode,
|
|
148
|
+
"parallel_workers": self.parallel_workers,
|
|
149
|
+
"timeout_seconds": self.timeout_seconds,
|
|
150
|
+
"fail_fast": self.fail_fast,
|
|
151
|
+
},
|
|
152
|
+
"thresholds": {
|
|
153
|
+
"global_pass_rate": self.global_pass_rate,
|
|
154
|
+
},
|
|
155
|
+
"evaluations": [e.to_dict() for e in self.evaluations],
|
|
156
|
+
"scanners": [s.to_dict() for s in self.scanners],
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
@classmethod
|
|
160
|
+
def from_dict(cls, data: Dict[str, Any]) -> "AutoEvalConfig":
|
|
161
|
+
"""Create from dictionary (YAML import)."""
|
|
162
|
+
metadata = data.get("metadata", {})
|
|
163
|
+
execution = data.get("execution", {})
|
|
164
|
+
thresholds = data.get("thresholds", {})
|
|
165
|
+
|
|
166
|
+
return cls(
|
|
167
|
+
name=data.get("name", "unnamed"),
|
|
168
|
+
description=data.get("description", ""),
|
|
169
|
+
version=data.get("version", "1.0.0"),
|
|
170
|
+
app_category=metadata.get("app_category", "unknown"),
|
|
171
|
+
risk_level=metadata.get("risk_level", "medium"),
|
|
172
|
+
domain_sensitivity=metadata.get("domain_sensitivity", "general"),
|
|
173
|
+
evaluations=[
|
|
174
|
+
EvalConfig.from_dict(e) for e in data.get("evaluations", [])
|
|
175
|
+
],
|
|
176
|
+
scanners=[
|
|
177
|
+
ScannerConfig.from_dict(s) for s in data.get("scanners", [])
|
|
178
|
+
],
|
|
179
|
+
execution_mode=execution.get("mode", "non_blocking"),
|
|
180
|
+
parallel_workers=execution.get("parallel_workers", 4),
|
|
181
|
+
timeout_seconds=execution.get("timeout_seconds", 30),
|
|
182
|
+
fail_fast=execution.get("fail_fast", False),
|
|
183
|
+
global_pass_rate=thresholds.get("global_pass_rate", 0.8),
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
def copy(self) -> "AutoEvalConfig":
|
|
187
|
+
"""Create a deep copy of the configuration."""
|
|
188
|
+
return AutoEvalConfig(
|
|
189
|
+
name=self.name,
|
|
190
|
+
description=self.description,
|
|
191
|
+
version=self.version,
|
|
192
|
+
app_category=self.app_category,
|
|
193
|
+
risk_level=self.risk_level,
|
|
194
|
+
domain_sensitivity=self.domain_sensitivity,
|
|
195
|
+
evaluations=[e.copy() for e in self.evaluations],
|
|
196
|
+
scanners=[s.copy() for s in self.scanners],
|
|
197
|
+
execution_mode=self.execution_mode,
|
|
198
|
+
parallel_workers=self.parallel_workers,
|
|
199
|
+
timeout_seconds=self.timeout_seconds,
|
|
200
|
+
fail_fast=self.fail_fast,
|
|
201
|
+
global_pass_rate=self.global_pass_rate,
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
def get_eval(self, name: str) -> Optional[EvalConfig]:
|
|
205
|
+
"""Get evaluation config by name."""
|
|
206
|
+
for e in self.evaluations:
|
|
207
|
+
if e.name == name:
|
|
208
|
+
return e
|
|
209
|
+
return None
|
|
210
|
+
|
|
211
|
+
def get_scanner(self, name: str) -> Optional[ScannerConfig]:
|
|
212
|
+
"""Get scanner config by name."""
|
|
213
|
+
for s in self.scanners:
|
|
214
|
+
if s.name == name:
|
|
215
|
+
return s
|
|
216
|
+
return None
|
|
217
|
+
|
|
218
|
+
def summary(self) -> str:
|
|
219
|
+
"""Get a summary of the configuration."""
|
|
220
|
+
lines = [
|
|
221
|
+
f"AutoEval Config: {self.name}",
|
|
222
|
+
f" Category: {self.app_category}",
|
|
223
|
+
f" Risk Level: {self.risk_level}",
|
|
224
|
+
f" Domain: {self.domain_sensitivity}",
|
|
225
|
+
"",
|
|
226
|
+
f"Evaluations ({len(self.evaluations)}):",
|
|
227
|
+
]
|
|
228
|
+
|
|
229
|
+
for e in self.evaluations:
|
|
230
|
+
status = "enabled" if e.enabled else "disabled"
|
|
231
|
+
lines.append(f" - {e.name} (threshold: {e.threshold}, {status})")
|
|
232
|
+
|
|
233
|
+
lines.append("")
|
|
234
|
+
lines.append(f"Scanners ({len(self.scanners)}):")
|
|
235
|
+
|
|
236
|
+
for s in self.scanners:
|
|
237
|
+
status = "enabled" if s.enabled else "disabled"
|
|
238
|
+
lines.append(f" - {s.name} (action: {s.action}, {status})")
|
|
239
|
+
|
|
240
|
+
lines.append("")
|
|
241
|
+
lines.append(f"Execution: {self.execution_mode}, workers: {self.parallel_workers}")
|
|
242
|
+
lines.append(f"Pass Rate Threshold: {self.global_pass_rate:.0%}")
|
|
243
|
+
|
|
244
|
+
return "\n".join(lines)
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"""Export and import functionality for AutoEval configurations.
|
|
2
|
+
|
|
3
|
+
Supports YAML and JSON formats for version-controlled configurations.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Union
|
|
9
|
+
|
|
10
|
+
from .config import AutoEvalConfig
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def export_yaml(config: AutoEvalConfig, path: Union[str, Path]) -> None:
|
|
14
|
+
"""
|
|
15
|
+
Export configuration to YAML file.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
config: AutoEvalConfig to export
|
|
19
|
+
path: Path to write YAML file
|
|
20
|
+
|
|
21
|
+
Example:
|
|
22
|
+
export_yaml(config, "eval_config.yaml")
|
|
23
|
+
"""
|
|
24
|
+
try:
|
|
25
|
+
import yaml
|
|
26
|
+
except ImportError:
|
|
27
|
+
raise ImportError("PyYAML is required for YAML export. Install with: pip install pyyaml")
|
|
28
|
+
|
|
29
|
+
data = config.to_dict()
|
|
30
|
+
path = Path(path)
|
|
31
|
+
|
|
32
|
+
with open(path, "w") as f:
|
|
33
|
+
yaml.dump(data, f, default_flow_style=False, sort_keys=False, allow_unicode=True)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def export_json(config: AutoEvalConfig, path: Union[str, Path], indent: int = 2) -> None:
|
|
37
|
+
"""
|
|
38
|
+
Export configuration to JSON file.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
config: AutoEvalConfig to export
|
|
42
|
+
path: Path to write JSON file
|
|
43
|
+
indent: Indentation level for pretty printing
|
|
44
|
+
|
|
45
|
+
Example:
|
|
46
|
+
export_json(config, "eval_config.json")
|
|
47
|
+
"""
|
|
48
|
+
data = config.to_dict()
|
|
49
|
+
path = Path(path)
|
|
50
|
+
|
|
51
|
+
with open(path, "w") as f:
|
|
52
|
+
json.dump(data, f, indent=indent)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def load_yaml(path: Union[str, Path]) -> AutoEvalConfig:
|
|
56
|
+
"""
|
|
57
|
+
Load configuration from YAML file.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
path: Path to YAML configuration file
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
AutoEvalConfig instance
|
|
64
|
+
|
|
65
|
+
Example:
|
|
66
|
+
config = load_yaml("eval_config.yaml")
|
|
67
|
+
"""
|
|
68
|
+
try:
|
|
69
|
+
import yaml
|
|
70
|
+
except ImportError:
|
|
71
|
+
raise ImportError("PyYAML is required for YAML import. Install with: pip install pyyaml")
|
|
72
|
+
|
|
73
|
+
path = Path(path)
|
|
74
|
+
|
|
75
|
+
with open(path, "r") as f:
|
|
76
|
+
data = yaml.safe_load(f)
|
|
77
|
+
|
|
78
|
+
return AutoEvalConfig.from_dict(data)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def load_json(path: Union[str, Path]) -> AutoEvalConfig:
|
|
82
|
+
"""
|
|
83
|
+
Load configuration from JSON file.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
path: Path to JSON configuration file
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
AutoEvalConfig instance
|
|
90
|
+
|
|
91
|
+
Example:
|
|
92
|
+
config = load_json("eval_config.json")
|
|
93
|
+
"""
|
|
94
|
+
path = Path(path)
|
|
95
|
+
|
|
96
|
+
with open(path, "r") as f:
|
|
97
|
+
data = json.load(f)
|
|
98
|
+
|
|
99
|
+
return AutoEvalConfig.from_dict(data)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def load_config(path: Union[str, Path]) -> AutoEvalConfig:
|
|
103
|
+
"""
|
|
104
|
+
Load configuration from file (auto-detect format).
|
|
105
|
+
|
|
106
|
+
Determines format from file extension (.yaml, .yml, .json).
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
path: Path to configuration file
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
AutoEvalConfig instance
|
|
113
|
+
|
|
114
|
+
Raises:
|
|
115
|
+
ValueError: If file extension not recognized
|
|
116
|
+
|
|
117
|
+
Example:
|
|
118
|
+
config = load_config("eval_config.yaml")
|
|
119
|
+
config = load_config("eval_config.json")
|
|
120
|
+
"""
|
|
121
|
+
path = Path(path)
|
|
122
|
+
suffix = path.suffix.lower()
|
|
123
|
+
|
|
124
|
+
if suffix in {".yaml", ".yml"}:
|
|
125
|
+
return load_yaml(path)
|
|
126
|
+
elif suffix == ".json":
|
|
127
|
+
return load_json(path)
|
|
128
|
+
else:
|
|
129
|
+
raise ValueError(
|
|
130
|
+
f"Unknown file format: {suffix}. "
|
|
131
|
+
"Supported formats: .yaml, .yml, .json"
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def to_yaml_string(config: AutoEvalConfig) -> str:
|
|
136
|
+
"""
|
|
137
|
+
Convert configuration to YAML string.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
config: AutoEvalConfig to convert
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
YAML string representation
|
|
144
|
+
|
|
145
|
+
Example:
|
|
146
|
+
yaml_str = to_yaml_string(config)
|
|
147
|
+
print(yaml_str)
|
|
148
|
+
"""
|
|
149
|
+
try:
|
|
150
|
+
import yaml
|
|
151
|
+
except ImportError:
|
|
152
|
+
raise ImportError("PyYAML is required. Install with: pip install pyyaml")
|
|
153
|
+
|
|
154
|
+
data = config.to_dict()
|
|
155
|
+
return yaml.dump(data, default_flow_style=False, sort_keys=False, allow_unicode=True)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def to_json_string(config: AutoEvalConfig, indent: int = 2) -> str:
|
|
159
|
+
"""
|
|
160
|
+
Convert configuration to JSON string.
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
config: AutoEvalConfig to convert
|
|
164
|
+
indent: Indentation level for pretty printing
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
JSON string representation
|
|
168
|
+
|
|
169
|
+
Example:
|
|
170
|
+
json_str = to_json_string(config)
|
|
171
|
+
print(json_str)
|
|
172
|
+
"""
|
|
173
|
+
data = config.to_dict()
|
|
174
|
+
return json.dumps(data, indent=indent)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def from_yaml_string(yaml_str: str) -> AutoEvalConfig:
|
|
178
|
+
"""
|
|
179
|
+
Load configuration from YAML string.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
yaml_str: YAML string to parse
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
AutoEvalConfig instance
|
|
186
|
+
|
|
187
|
+
Example:
|
|
188
|
+
config = from_yaml_string(yaml_content)
|
|
189
|
+
"""
|
|
190
|
+
try:
|
|
191
|
+
import yaml
|
|
192
|
+
except ImportError:
|
|
193
|
+
raise ImportError("PyYAML is required. Install with: pip install pyyaml")
|
|
194
|
+
|
|
195
|
+
data = yaml.safe_load(yaml_str)
|
|
196
|
+
return AutoEvalConfig.from_dict(data)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def from_json_string(json_str: str) -> AutoEvalConfig:
|
|
200
|
+
"""
|
|
201
|
+
Load configuration from JSON string.
|
|
202
|
+
|
|
203
|
+
Args:
|
|
204
|
+
json_str: JSON string to parse
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
AutoEvalConfig instance
|
|
208
|
+
|
|
209
|
+
Example:
|
|
210
|
+
config = from_json_string(json_content)
|
|
211
|
+
"""
|
|
212
|
+
data = json.loads(json_str)
|
|
213
|
+
return AutoEvalConfig.from_dict(data)
|