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,165 @@
|
|
|
1
|
+
"""Config command for managing CLI configuration."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
|
|
9
|
+
from fi.cli.config.defaults import BASIC_TEMPLATE
|
|
10
|
+
from fi.cli.utils.console import console, print_success, print_warning
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
config_app = typer.Typer(
|
|
14
|
+
name="config",
|
|
15
|
+
help="Manage CLI configuration",
|
|
16
|
+
no_args_is_help=True,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@config_app.command("show")
|
|
21
|
+
def show_config() -> None:
|
|
22
|
+
"""Display current configuration settings."""
|
|
23
|
+
config_items = {
|
|
24
|
+
"FI_API_KEY": _mask_key(os.environ.get("FI_API_KEY")),
|
|
25
|
+
"FI_SECRET_KEY": _mask_key(os.environ.get("FI_SECRET_KEY")),
|
|
26
|
+
"FI_BASE_URL": os.environ.get("FI_BASE_URL", "https://api.futureagi.com"),
|
|
27
|
+
"FI_DEFAULT_MODEL": os.environ.get("FI_DEFAULT_MODEL", "gpt-4o"),
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
console.print("[bold]Current Configuration:[/bold]\n")
|
|
31
|
+
for key, value in config_items.items():
|
|
32
|
+
if value:
|
|
33
|
+
console.print(f" [cyan]{key}[/cyan]: {value}")
|
|
34
|
+
else:
|
|
35
|
+
console.print(f" [cyan]{key}[/cyan]: [dim]not set[/dim]")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@config_app.command("get")
|
|
39
|
+
def get_config(
|
|
40
|
+
key: str = typer.Argument(..., help="Configuration key to get"),
|
|
41
|
+
) -> None:
|
|
42
|
+
"""Get a specific configuration value."""
|
|
43
|
+
value = os.environ.get(key)
|
|
44
|
+
if value:
|
|
45
|
+
# Mask sensitive keys
|
|
46
|
+
if "KEY" in key.upper() or "SECRET" in key.upper():
|
|
47
|
+
console.print(_mask_key(value))
|
|
48
|
+
else:
|
|
49
|
+
console.print(value)
|
|
50
|
+
else:
|
|
51
|
+
print_warning(f"Configuration key not set: {key}")
|
|
52
|
+
raise typer.Exit(1)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@config_app.command("set")
|
|
56
|
+
def set_config(
|
|
57
|
+
key: str = typer.Argument(..., help="Configuration key to set"),
|
|
58
|
+
value: str = typer.Argument(..., help="Value to set"),
|
|
59
|
+
save: bool = typer.Option(
|
|
60
|
+
False,
|
|
61
|
+
"--save", "-s",
|
|
62
|
+
help="Save to .env file in current directory",
|
|
63
|
+
),
|
|
64
|
+
) -> None:
|
|
65
|
+
"""
|
|
66
|
+
Set a configuration value.
|
|
67
|
+
|
|
68
|
+
Note: Without --save, the value is only set for the current session.
|
|
69
|
+
Use --save to persist the value to a .env file.
|
|
70
|
+
"""
|
|
71
|
+
os.environ[key] = value
|
|
72
|
+
|
|
73
|
+
if save:
|
|
74
|
+
_save_to_env_file(key, value)
|
|
75
|
+
print_success(f"Saved {key} to .env file")
|
|
76
|
+
else:
|
|
77
|
+
print_success(f"Set {key} for current session")
|
|
78
|
+
console.print("[dim]Use --save to persist to .env file[/dim]")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@config_app.command("init")
|
|
82
|
+
def init_config(
|
|
83
|
+
path: Path = typer.Argument(
|
|
84
|
+
Path("."),
|
|
85
|
+
help="Directory to create config file in",
|
|
86
|
+
),
|
|
87
|
+
force: bool = typer.Option(
|
|
88
|
+
False,
|
|
89
|
+
"--force", "-f",
|
|
90
|
+
help="Overwrite existing config file",
|
|
91
|
+
),
|
|
92
|
+
) -> None:
|
|
93
|
+
"""Create a default configuration file."""
|
|
94
|
+
config_path = path / "fi-evaluation.yaml"
|
|
95
|
+
|
|
96
|
+
if config_path.exists() and not force:
|
|
97
|
+
print_warning(
|
|
98
|
+
f"Configuration file already exists: {config_path}\n"
|
|
99
|
+
"Use --force to overwrite."
|
|
100
|
+
)
|
|
101
|
+
raise typer.Exit(1)
|
|
102
|
+
|
|
103
|
+
with open(config_path, "w") as f:
|
|
104
|
+
f.write(BASIC_TEMPLATE)
|
|
105
|
+
|
|
106
|
+
print_success(f"Created configuration file: {config_path}")
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@config_app.command("env")
|
|
110
|
+
def show_env_template() -> None:
|
|
111
|
+
"""Show environment variable template."""
|
|
112
|
+
template = """# Future AGI Evaluation Configuration
|
|
113
|
+
# Copy this to a .env file and fill in your values
|
|
114
|
+
|
|
115
|
+
# Required: API credentials
|
|
116
|
+
FI_API_KEY=your_api_key_here
|
|
117
|
+
FI_SECRET_KEY=your_secret_key_here
|
|
118
|
+
|
|
119
|
+
# Optional: Custom settings
|
|
120
|
+
# FI_BASE_URL=https://api.futureagi.com
|
|
121
|
+
# FI_DEFAULT_MODEL=gpt-4o
|
|
122
|
+
|
|
123
|
+
# Optional: Langfuse integration
|
|
124
|
+
# LANGFUSE_SECRET_KEY=your_langfuse_secret
|
|
125
|
+
# LANGFUSE_PUBLIC_KEY=your_langfuse_public
|
|
126
|
+
# LANGFUSE_HOST=https://cloud.langfuse.com
|
|
127
|
+
"""
|
|
128
|
+
console.print(template)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _mask_key(value: Optional[str]) -> Optional[str]:
|
|
132
|
+
"""Mask a sensitive key value."""
|
|
133
|
+
if not value:
|
|
134
|
+
return None
|
|
135
|
+
if len(value) <= 8:
|
|
136
|
+
return "*" * len(value)
|
|
137
|
+
return value[:4] + "*" * (len(value) - 8) + value[-4:]
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def _save_to_env_file(key: str, value: str) -> None:
|
|
141
|
+
"""Save a key-value pair to .env file."""
|
|
142
|
+
env_path = Path(".env")
|
|
143
|
+
|
|
144
|
+
# Read existing content
|
|
145
|
+
existing_lines = []
|
|
146
|
+
if env_path.exists():
|
|
147
|
+
with open(env_path, "r") as f:
|
|
148
|
+
existing_lines = f.readlines()
|
|
149
|
+
|
|
150
|
+
# Update or add the key
|
|
151
|
+
key_found = False
|
|
152
|
+
new_lines = []
|
|
153
|
+
for line in existing_lines:
|
|
154
|
+
if line.startswith(f"{key}="):
|
|
155
|
+
new_lines.append(f"{key}={value}\n")
|
|
156
|
+
key_found = True
|
|
157
|
+
else:
|
|
158
|
+
new_lines.append(line)
|
|
159
|
+
|
|
160
|
+
if not key_found:
|
|
161
|
+
new_lines.append(f"{key}={value}\n")
|
|
162
|
+
|
|
163
|
+
# Write back
|
|
164
|
+
with open(env_path, "w") as f:
|
|
165
|
+
f.writelines(new_lines)
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"""Export command for exporting evaluation results."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
|
|
9
|
+
from fi.cli.storage import RunHistory
|
|
10
|
+
from fi.cli.utils.console import print_error, print_success, print_warning
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def export(
|
|
14
|
+
run_id: Optional[str] = typer.Argument(
|
|
15
|
+
None,
|
|
16
|
+
help="Run ID to export (use 'fi view --list' to see available runs)",
|
|
17
|
+
),
|
|
18
|
+
output: Path = typer.Option(
|
|
19
|
+
...,
|
|
20
|
+
"--output", "-o",
|
|
21
|
+
help="Output file path",
|
|
22
|
+
),
|
|
23
|
+
format: str = typer.Option(
|
|
24
|
+
"json",
|
|
25
|
+
"--format", "-f",
|
|
26
|
+
help="Export format: json, csv, html, junit",
|
|
27
|
+
),
|
|
28
|
+
last: bool = typer.Option(
|
|
29
|
+
False,
|
|
30
|
+
"--last", "-l",
|
|
31
|
+
help="Export the most recent run",
|
|
32
|
+
),
|
|
33
|
+
) -> None:
|
|
34
|
+
"""
|
|
35
|
+
Export evaluation results to a file.
|
|
36
|
+
|
|
37
|
+
Supported formats:
|
|
38
|
+
- json: JSON format with full details
|
|
39
|
+
- csv: CSV spreadsheet format
|
|
40
|
+
- html: HTML report for viewing in browser
|
|
41
|
+
- junit: JUnit XML format for CI/CD integration
|
|
42
|
+
|
|
43
|
+
Examples:
|
|
44
|
+
fi export --last -o results.json
|
|
45
|
+
fi export --last -o report.html -f html
|
|
46
|
+
fi export --last -o results.xml -f junit
|
|
47
|
+
fi export 20260123-143022-abc -o export.csv -f csv
|
|
48
|
+
"""
|
|
49
|
+
history = RunHistory()
|
|
50
|
+
|
|
51
|
+
# Get the run to export
|
|
52
|
+
if last:
|
|
53
|
+
record = history.get_latest_run()
|
|
54
|
+
if record is None:
|
|
55
|
+
print_warning("No runs found. Run 'fi run' first to create evaluations.")
|
|
56
|
+
raise typer.Exit(1)
|
|
57
|
+
elif run_id:
|
|
58
|
+
record = history.get_run(run_id)
|
|
59
|
+
if record is None:
|
|
60
|
+
print_error(f"Run not found: {run_id}\nUse 'fi view --list' to see available runs.")
|
|
61
|
+
raise typer.Exit(1)
|
|
62
|
+
else:
|
|
63
|
+
print_error("Please specify a run ID or use --last to export the most recent run.")
|
|
64
|
+
raise typer.Exit(1)
|
|
65
|
+
|
|
66
|
+
# Load full results
|
|
67
|
+
results = history.load_results(record.run_id)
|
|
68
|
+
if results is None:
|
|
69
|
+
print_error(f"Results file not found for run: {record.run_id}")
|
|
70
|
+
raise typer.Exit(1)
|
|
71
|
+
|
|
72
|
+
# Export based on format
|
|
73
|
+
format = format.lower()
|
|
74
|
+
if format == "json":
|
|
75
|
+
_export_json(record, results, output)
|
|
76
|
+
elif format == "csv":
|
|
77
|
+
_export_csv(record, results, output)
|
|
78
|
+
elif format == "html":
|
|
79
|
+
_export_html(record, results, output)
|
|
80
|
+
elif format == "junit":
|
|
81
|
+
_export_junit(record, results, output)
|
|
82
|
+
else:
|
|
83
|
+
print_error(f"Unsupported format: {format}\nSupported: json, csv, html, junit")
|
|
84
|
+
raise typer.Exit(1)
|
|
85
|
+
|
|
86
|
+
print_success(f"Exported run {record.run_id} to {output}")
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _export_json(record, results: dict, output: Path) -> None:
|
|
90
|
+
"""Export results as JSON."""
|
|
91
|
+
export_data = {
|
|
92
|
+
"run_id": record.run_id,
|
|
93
|
+
"timestamp": record.timestamp,
|
|
94
|
+
"config_file": record.config_file,
|
|
95
|
+
"templates": record.templates,
|
|
96
|
+
"summary": {
|
|
97
|
+
"total": record.total_evaluations,
|
|
98
|
+
"successful": record.successful,
|
|
99
|
+
"failed": record.failed,
|
|
100
|
+
"pass_rate": record.pass_rate,
|
|
101
|
+
"avg_score": record.avg_score,
|
|
102
|
+
},
|
|
103
|
+
"eval_results": results.get("eval_results", []),
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
with open(output, "w") as f:
|
|
107
|
+
json.dump(export_data, f, indent=2)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _export_csv(record, results: dict, output: Path) -> None:
|
|
111
|
+
"""Export results as CSV."""
|
|
112
|
+
import csv
|
|
113
|
+
|
|
114
|
+
with open(output, "w", newline="") as f:
|
|
115
|
+
writer = csv.writer(f)
|
|
116
|
+
|
|
117
|
+
# Header
|
|
118
|
+
writer.writerow([
|
|
119
|
+
"run_id",
|
|
120
|
+
"timestamp",
|
|
121
|
+
"template",
|
|
122
|
+
"output",
|
|
123
|
+
"reason",
|
|
124
|
+
"runtime",
|
|
125
|
+
"output_type",
|
|
126
|
+
"eval_id",
|
|
127
|
+
])
|
|
128
|
+
|
|
129
|
+
# Data rows
|
|
130
|
+
for result in results.get("eval_results", []):
|
|
131
|
+
writer.writerow([
|
|
132
|
+
record.run_id,
|
|
133
|
+
record.timestamp,
|
|
134
|
+
result.get("name", ""),
|
|
135
|
+
result.get("output", ""),
|
|
136
|
+
result.get("reason", ""),
|
|
137
|
+
result.get("runtime", ""),
|
|
138
|
+
result.get("output_type", ""),
|
|
139
|
+
result.get("eval_id", ""),
|
|
140
|
+
])
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _export_html(record, results: dict, output: Path) -> None:
|
|
144
|
+
"""Export results as HTML."""
|
|
145
|
+
from fi.cli.commands.view import _generate_html_report
|
|
146
|
+
|
|
147
|
+
html_content = _generate_html_report(record, results)
|
|
148
|
+
|
|
149
|
+
with open(output, "w") as f:
|
|
150
|
+
f.write(html_content)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _export_junit(record, results: dict, output: Path) -> None:
|
|
154
|
+
"""Export results as JUnit XML for CI/CD integration."""
|
|
155
|
+
import xml.etree.ElementTree as ET
|
|
156
|
+
from xml.dom import minidom
|
|
157
|
+
|
|
158
|
+
# Create testsuites root
|
|
159
|
+
testsuites = ET.Element("testsuites")
|
|
160
|
+
testsuites.set("name", "AI Evaluation Results")
|
|
161
|
+
testsuites.set("tests", str(record.total_evaluations))
|
|
162
|
+
testsuites.set("failures", str(record.failed))
|
|
163
|
+
testsuites.set("time", "0")
|
|
164
|
+
|
|
165
|
+
# Create testsuite for this run
|
|
166
|
+
testsuite = ET.SubElement(testsuites, "testsuite")
|
|
167
|
+
testsuite.set("name", f"Run {record.run_id}")
|
|
168
|
+
testsuite.set("tests", str(record.total_evaluations))
|
|
169
|
+
testsuite.set("failures", str(record.failed))
|
|
170
|
+
testsuite.set("timestamp", record.timestamp)
|
|
171
|
+
|
|
172
|
+
# Add test cases
|
|
173
|
+
for result in results.get("eval_results", []):
|
|
174
|
+
testcase = ET.SubElement(testsuite, "testcase")
|
|
175
|
+
testcase.set("name", result.get("name", "Unknown"))
|
|
176
|
+
testcase.set("classname", "fi.evals")
|
|
177
|
+
|
|
178
|
+
runtime_ms = result.get("runtime", 0)
|
|
179
|
+
runtime_sec = runtime_ms / 1000 if runtime_ms else 0
|
|
180
|
+
testcase.set("time", f"{runtime_sec:.3f}")
|
|
181
|
+
|
|
182
|
+
result_output = result.get("output")
|
|
183
|
+
reason = result.get("reason", "")
|
|
184
|
+
|
|
185
|
+
# Check if this is a failure
|
|
186
|
+
is_failure = False
|
|
187
|
+
if isinstance(result_output, bool) and result_output is False:
|
|
188
|
+
is_failure = True
|
|
189
|
+
elif isinstance(result_output, (int, float)) and result_output < 0.5:
|
|
190
|
+
# Consider scores below 0.5 as failures for JUnit purposes
|
|
191
|
+
is_failure = True
|
|
192
|
+
|
|
193
|
+
if is_failure:
|
|
194
|
+
failure = ET.SubElement(testcase, "failure")
|
|
195
|
+
failure.set("message", f"Evaluation failed: {result_output}")
|
|
196
|
+
failure.text = reason
|
|
197
|
+
|
|
198
|
+
# Pretty print XML
|
|
199
|
+
xml_str = ET.tostring(testsuites, encoding="unicode")
|
|
200
|
+
dom = minidom.parseString(xml_str)
|
|
201
|
+
pretty_xml = dom.toprettyxml(indent=" ")
|
|
202
|
+
|
|
203
|
+
# Remove extra blank lines
|
|
204
|
+
lines = [line for line in pretty_xml.split("\n") if line.strip()]
|
|
205
|
+
pretty_xml = "\n".join(lines)
|
|
206
|
+
|
|
207
|
+
with open(output, "w") as f:
|
|
208
|
+
f.write(pretty_xml)
|
fi/cli/commands/init.py
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"""Init command for creating new evaluation projects."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
|
|
8
|
+
from fi.cli.config.defaults import TEMPLATES, SAMPLE_DATA
|
|
9
|
+
from fi.cli.utils.console import console, print_success, print_error, print_warning
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def init_project(
|
|
13
|
+
directory: Optional[Path] = typer.Argument(
|
|
14
|
+
None,
|
|
15
|
+
help="Directory to initialize (default: current directory)",
|
|
16
|
+
),
|
|
17
|
+
template: str = typer.Option(
|
|
18
|
+
"basic",
|
|
19
|
+
"--template", "-t",
|
|
20
|
+
help="Template to use: basic, rag, safety, agent",
|
|
21
|
+
),
|
|
22
|
+
force: bool = typer.Option(
|
|
23
|
+
False,
|
|
24
|
+
"--force", "-f",
|
|
25
|
+
help="Overwrite existing configuration file",
|
|
26
|
+
),
|
|
27
|
+
) -> None:
|
|
28
|
+
"""
|
|
29
|
+
Initialize a new AI evaluation project.
|
|
30
|
+
|
|
31
|
+
Creates a fi-evaluation.yaml configuration file and sample data files.
|
|
32
|
+
"""
|
|
33
|
+
# Determine target directory
|
|
34
|
+
if directory is None:
|
|
35
|
+
target_dir = Path.cwd()
|
|
36
|
+
else:
|
|
37
|
+
target_dir = Path(directory).resolve()
|
|
38
|
+
|
|
39
|
+
# Validate template
|
|
40
|
+
if template not in TEMPLATES:
|
|
41
|
+
print_error(
|
|
42
|
+
f"Unknown template: {template}\n"
|
|
43
|
+
f"Available templates: {', '.join(TEMPLATES.keys())}"
|
|
44
|
+
)
|
|
45
|
+
raise typer.Exit(1)
|
|
46
|
+
|
|
47
|
+
# Create directory if it doesn't exist
|
|
48
|
+
if not target_dir.exists():
|
|
49
|
+
target_dir.mkdir(parents=True)
|
|
50
|
+
console.print(f"[dim]Created directory: {target_dir}[/dim]")
|
|
51
|
+
|
|
52
|
+
# Check for existing config
|
|
53
|
+
config_path = target_dir / "fi-evaluation.yaml"
|
|
54
|
+
if config_path.exists() and not force:
|
|
55
|
+
print_warning(
|
|
56
|
+
f"Configuration file already exists: {config_path}\n"
|
|
57
|
+
"Use --force to overwrite."
|
|
58
|
+
)
|
|
59
|
+
raise typer.Exit(1)
|
|
60
|
+
|
|
61
|
+
# Create data directory
|
|
62
|
+
data_dir = target_dir / "data"
|
|
63
|
+
data_dir.mkdir(exist_ok=True)
|
|
64
|
+
|
|
65
|
+
# Create results directory
|
|
66
|
+
results_dir = target_dir / "results"
|
|
67
|
+
results_dir.mkdir(exist_ok=True)
|
|
68
|
+
|
|
69
|
+
# Write configuration file
|
|
70
|
+
config_content = TEMPLATES[template]
|
|
71
|
+
with open(config_path, "w") as f:
|
|
72
|
+
f.write(config_content)
|
|
73
|
+
console.print(f"[dim]Created: {config_path}[/dim]")
|
|
74
|
+
|
|
75
|
+
# Write sample data
|
|
76
|
+
sample_data = SAMPLE_DATA.get(template, SAMPLE_DATA["basic"])
|
|
77
|
+
data_filename = _get_data_filename(template)
|
|
78
|
+
data_path = data_dir / data_filename
|
|
79
|
+
with open(data_path, "w") as f:
|
|
80
|
+
f.write(sample_data)
|
|
81
|
+
console.print(f"[dim]Created: {data_path}[/dim]")
|
|
82
|
+
|
|
83
|
+
# Create .gitignore for results
|
|
84
|
+
gitignore_path = results_dir / ".gitignore"
|
|
85
|
+
with open(gitignore_path, "w") as f:
|
|
86
|
+
f.write("# Ignore evaluation results\n*\n!.gitignore\n")
|
|
87
|
+
|
|
88
|
+
# Success message
|
|
89
|
+
print_success(
|
|
90
|
+
f"Initialized evaluation project with '{template}' template!\n\n"
|
|
91
|
+
f"Project structure:\n"
|
|
92
|
+
f" {target_dir}/\n"
|
|
93
|
+
f" ├── fi-evaluation.yaml # Configuration file\n"
|
|
94
|
+
f" ├── data/\n"
|
|
95
|
+
f" │ └── {data_filename} # Sample test data\n"
|
|
96
|
+
f" └── results/ # Evaluation results\n\n"
|
|
97
|
+
f"Next steps:\n"
|
|
98
|
+
f" 1. Edit fi-evaluation.yaml to configure your evaluations\n"
|
|
99
|
+
f" 2. Add your test data to the data/ directory\n"
|
|
100
|
+
f" 3. Run 'fi run' to execute evaluations"
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _get_data_filename(template: str) -> str:
|
|
105
|
+
"""Get the appropriate data filename for the template."""
|
|
106
|
+
filenames = {
|
|
107
|
+
"basic": "test_cases.json",
|
|
108
|
+
"rag": "rag_test_cases.json",
|
|
109
|
+
"safety": "safety_test_cases.json",
|
|
110
|
+
"agent": "agent_test_cases.json",
|
|
111
|
+
}
|
|
112
|
+
return filenames.get(template, "test_cases.json")
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"""List command for displaying available resources."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
from rich.table import Table
|
|
8
|
+
|
|
9
|
+
from fi.cli.utils.console import console, print_error
|
|
10
|
+
from fi.evals.templates import EvalTemplate
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# Template categories for filtering
|
|
14
|
+
TEMPLATE_CATEGORIES = {
|
|
15
|
+
"conversation": [
|
|
16
|
+
"conversation_coherence",
|
|
17
|
+
"conversation_resolution",
|
|
18
|
+
],
|
|
19
|
+
"rag": [
|
|
20
|
+
"context_adherence",
|
|
21
|
+
"context_relevance",
|
|
22
|
+
"completeness",
|
|
23
|
+
"chunk_attribution",
|
|
24
|
+
"chunk_utilization",
|
|
25
|
+
"groundedness",
|
|
26
|
+
],
|
|
27
|
+
"safety": [
|
|
28
|
+
"content_moderation",
|
|
29
|
+
"pii",
|
|
30
|
+
"toxicity",
|
|
31
|
+
"prompt_injection",
|
|
32
|
+
"content_safety_violation",
|
|
33
|
+
"no_harmful_therapeutic_guidance",
|
|
34
|
+
"is_harmful_advice",
|
|
35
|
+
],
|
|
36
|
+
"bias": [
|
|
37
|
+
"no_racial_bias",
|
|
38
|
+
"no_gender_bias",
|
|
39
|
+
"no_age_bias",
|
|
40
|
+
"bias_detection",
|
|
41
|
+
"sexist",
|
|
42
|
+
],
|
|
43
|
+
"quality": [
|
|
44
|
+
"factual_accuracy",
|
|
45
|
+
"summary_quality",
|
|
46
|
+
"is_good_summary",
|
|
47
|
+
"is_factually_consistent",
|
|
48
|
+
"completeness",
|
|
49
|
+
],
|
|
50
|
+
"format": [
|
|
51
|
+
"is_json",
|
|
52
|
+
"is_csv",
|
|
53
|
+
"is_code",
|
|
54
|
+
"is_email",
|
|
55
|
+
"one_line",
|
|
56
|
+
"contains_valid_link",
|
|
57
|
+
"no_valid_links",
|
|
58
|
+
],
|
|
59
|
+
"tone": [
|
|
60
|
+
"tone",
|
|
61
|
+
"is_polite",
|
|
62
|
+
"is_concise",
|
|
63
|
+
"is_helpful",
|
|
64
|
+
"is_informal_tone",
|
|
65
|
+
"clinically_inappropriate_tone",
|
|
66
|
+
],
|
|
67
|
+
"translation": [
|
|
68
|
+
"translation_accuracy",
|
|
69
|
+
"cultural_sensitivity",
|
|
70
|
+
],
|
|
71
|
+
"audio": [
|
|
72
|
+
"audio_transcription",
|
|
73
|
+
"audio_quality",
|
|
74
|
+
],
|
|
75
|
+
"function_calling": [
|
|
76
|
+
"llm_function_calling",
|
|
77
|
+
"evaluate_function_calling",
|
|
78
|
+
],
|
|
79
|
+
"hallucination": [
|
|
80
|
+
"detect_hallucination_missing_info",
|
|
81
|
+
"caption_hallucination",
|
|
82
|
+
],
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def list_resources(
|
|
87
|
+
resource: str = typer.Argument(
|
|
88
|
+
"templates",
|
|
89
|
+
help="Resource to list: templates, categories",
|
|
90
|
+
),
|
|
91
|
+
format: str = typer.Option(
|
|
92
|
+
"table",
|
|
93
|
+
"--format", "-f",
|
|
94
|
+
help="Output format: table, json",
|
|
95
|
+
),
|
|
96
|
+
category: Optional[str] = typer.Option(
|
|
97
|
+
None,
|
|
98
|
+
"--category", "-c",
|
|
99
|
+
help="Filter templates by category",
|
|
100
|
+
),
|
|
101
|
+
) -> None:
|
|
102
|
+
"""
|
|
103
|
+
List available evaluation resources.
|
|
104
|
+
|
|
105
|
+
Resources:
|
|
106
|
+
templates - List all available evaluation templates
|
|
107
|
+
categories - List template categories
|
|
108
|
+
"""
|
|
109
|
+
if resource == "templates":
|
|
110
|
+
_list_templates(format, category)
|
|
111
|
+
elif resource == "categories":
|
|
112
|
+
_list_categories(format)
|
|
113
|
+
else:
|
|
114
|
+
print_error(f"Unknown resource: {resource}\nAvailable: templates, categories")
|
|
115
|
+
raise typer.Exit(1)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _list_templates(format: str, category: Optional[str] = None) -> None:
|
|
119
|
+
"""List all available evaluation templates."""
|
|
120
|
+
# Get all template classes from templates module
|
|
121
|
+
from fi.evals import templates as templates_module
|
|
122
|
+
|
|
123
|
+
template_list = []
|
|
124
|
+
for name in dir(templates_module):
|
|
125
|
+
obj = getattr(templates_module, name)
|
|
126
|
+
if (
|
|
127
|
+
isinstance(obj, type)
|
|
128
|
+
and issubclass(obj, EvalTemplate)
|
|
129
|
+
and obj is not EvalTemplate
|
|
130
|
+
and hasattr(obj, "eval_name")
|
|
131
|
+
):
|
|
132
|
+
eval_name = obj.eval_name
|
|
133
|
+
# Filter by category if specified
|
|
134
|
+
if category:
|
|
135
|
+
if category not in TEMPLATE_CATEGORIES:
|
|
136
|
+
print_error(
|
|
137
|
+
f"Unknown category: {category}\n"
|
|
138
|
+
f"Available: {', '.join(TEMPLATE_CATEGORIES.keys())}"
|
|
139
|
+
)
|
|
140
|
+
raise typer.Exit(1)
|
|
141
|
+
if eval_name not in TEMPLATE_CATEGORIES[category]:
|
|
142
|
+
continue
|
|
143
|
+
|
|
144
|
+
# Determine category for template
|
|
145
|
+
template_category = _get_template_category(eval_name)
|
|
146
|
+
|
|
147
|
+
template_list.append({
|
|
148
|
+
"name": eval_name,
|
|
149
|
+
"class": name,
|
|
150
|
+
"category": template_category,
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
# Sort by name
|
|
154
|
+
template_list.sort(key=lambda x: x["name"])
|
|
155
|
+
|
|
156
|
+
if format == "json":
|
|
157
|
+
console.print(json.dumps(template_list, indent=2))
|
|
158
|
+
else:
|
|
159
|
+
_print_templates_table(template_list)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _list_categories(format: str) -> None:
|
|
163
|
+
"""List all template categories."""
|
|
164
|
+
categories = [
|
|
165
|
+
{"name": cat, "count": len(templates)}
|
|
166
|
+
for cat, templates in TEMPLATE_CATEGORIES.items()
|
|
167
|
+
]
|
|
168
|
+
|
|
169
|
+
if format == "json":
|
|
170
|
+
console.print(json.dumps(categories, indent=2))
|
|
171
|
+
else:
|
|
172
|
+
table = Table(
|
|
173
|
+
title="Template Categories",
|
|
174
|
+
show_header=True,
|
|
175
|
+
header_style="bold cyan",
|
|
176
|
+
)
|
|
177
|
+
table.add_column("Category", style="green")
|
|
178
|
+
table.add_column("Templates", justify="right", style="blue")
|
|
179
|
+
|
|
180
|
+
for cat in categories:
|
|
181
|
+
table.add_row(cat["name"], str(cat["count"]))
|
|
182
|
+
|
|
183
|
+
console.print(table)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def _print_templates_table(templates: list) -> None:
|
|
187
|
+
"""Print templates as a Rich table."""
|
|
188
|
+
table = Table(
|
|
189
|
+
title=f"Available Evaluation Templates ({len(templates)} total)",
|
|
190
|
+
show_header=True,
|
|
191
|
+
header_style="bold cyan",
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
table.add_column("Template Name", style="green")
|
|
195
|
+
table.add_column("Category", style="blue")
|
|
196
|
+
table.add_column("Class", style="dim")
|
|
197
|
+
|
|
198
|
+
for template in templates:
|
|
199
|
+
table.add_row(
|
|
200
|
+
template["name"],
|
|
201
|
+
template["category"],
|
|
202
|
+
template["class"],
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
console.print(table)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def _get_template_category(eval_name: str) -> str:
|
|
209
|
+
"""Get the category for a template."""
|
|
210
|
+
for category, templates in TEMPLATE_CATEGORIES.items():
|
|
211
|
+
if eval_name in templates:
|
|
212
|
+
return category
|
|
213
|
+
return "other"
|