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
fi/evals/otel/tracer.py
ADDED
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
"""
|
|
2
|
+
OpenTelemetry Tracer Setup.
|
|
3
|
+
|
|
4
|
+
Factory functions and utilities for setting up OpenTelemetry
|
|
5
|
+
tracing with LLM-specific processors and exporters.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Any, Dict, Optional
|
|
9
|
+
from contextlib import contextmanager
|
|
10
|
+
import logging
|
|
11
|
+
import os
|
|
12
|
+
|
|
13
|
+
from .config import (
|
|
14
|
+
TraceConfig,
|
|
15
|
+
ExporterConfig,
|
|
16
|
+
SamplingStrategy,
|
|
17
|
+
)
|
|
18
|
+
from .types import ExporterType, ProcessorType
|
|
19
|
+
from .processors import (
|
|
20
|
+
OTEL_AVAILABLE,
|
|
21
|
+
CompositeSpanProcessor,
|
|
22
|
+
LLMSpanProcessor,
|
|
23
|
+
EvaluationSpanProcessor,
|
|
24
|
+
CostSpanProcessor,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
logger = logging.getLogger(__name__)
|
|
28
|
+
|
|
29
|
+
# Global tracer provider instance
|
|
30
|
+
_tracer_provider: Optional[Any] = None
|
|
31
|
+
_is_initialized = False
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def setup_tracing(
|
|
35
|
+
config: Optional[TraceConfig] = None,
|
|
36
|
+
service_name: Optional[str] = None,
|
|
37
|
+
project_name: Optional[str] = None,
|
|
38
|
+
otlp_endpoint: Optional[str] = None,
|
|
39
|
+
**kwargs,
|
|
40
|
+
) -> Any:
|
|
41
|
+
"""
|
|
42
|
+
Set up OpenTelemetry tracing for LLM applications.
|
|
43
|
+
|
|
44
|
+
This is the main entry point for configuring OTEL tracing.
|
|
45
|
+
It creates exporters, processors, and a tracer provider.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
config: Full TraceConfig, or None to use defaults/env vars
|
|
49
|
+
service_name: Service name (overrides config)
|
|
50
|
+
otlp_endpoint: OTLP endpoint (overrides config)
|
|
51
|
+
**kwargs: Additional arguments passed to TraceConfig
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
The configured TracerProvider
|
|
55
|
+
|
|
56
|
+
Example:
|
|
57
|
+
# Simple setup with environment variables
|
|
58
|
+
setup_tracing(service_name="my-llm-service")
|
|
59
|
+
|
|
60
|
+
# Full configuration
|
|
61
|
+
from fi.evals.otel import TraceConfig, ExporterConfig, ExporterType
|
|
62
|
+
|
|
63
|
+
config = TraceConfig(
|
|
64
|
+
service_name="my-service",
|
|
65
|
+
exporters=[
|
|
66
|
+
ExporterConfig(type=ExporterType.OTLP_GRPC, endpoint="localhost:4317"),
|
|
67
|
+
ExporterConfig(type=ExporterType.CONSOLE),
|
|
68
|
+
],
|
|
69
|
+
)
|
|
70
|
+
setup_tracing(config)
|
|
71
|
+
"""
|
|
72
|
+
global _tracer_provider, _is_initialized
|
|
73
|
+
|
|
74
|
+
if not OTEL_AVAILABLE:
|
|
75
|
+
logger.warning(
|
|
76
|
+
"OpenTelemetry SDK not available. Install with: "
|
|
77
|
+
"pip install opentelemetry-sdk opentelemetry-exporter-otlp"
|
|
78
|
+
)
|
|
79
|
+
return None
|
|
80
|
+
|
|
81
|
+
# Build configuration
|
|
82
|
+
if config is None:
|
|
83
|
+
config = _build_config_from_env(service_name, otlp_endpoint, **kwargs)
|
|
84
|
+
else:
|
|
85
|
+
# Override with explicit args
|
|
86
|
+
if service_name:
|
|
87
|
+
config.service_name = service_name
|
|
88
|
+
if otlp_endpoint:
|
|
89
|
+
config.exporters = [ExporterConfig(
|
|
90
|
+
type=ExporterType.OTLP_GRPC,
|
|
91
|
+
endpoint=otlp_endpoint,
|
|
92
|
+
)]
|
|
93
|
+
|
|
94
|
+
if not config.enabled:
|
|
95
|
+
logger.info("Tracing is disabled")
|
|
96
|
+
return None
|
|
97
|
+
|
|
98
|
+
# Import OTEL components
|
|
99
|
+
from opentelemetry import trace
|
|
100
|
+
from opentelemetry.sdk.trace import TracerProvider
|
|
101
|
+
from opentelemetry.sdk.resources import Resource, SERVICE_NAME
|
|
102
|
+
|
|
103
|
+
# Create resource
|
|
104
|
+
resource_attrs = {
|
|
105
|
+
SERVICE_NAME: config.service_name,
|
|
106
|
+
"service.version": config.service_version or "unknown",
|
|
107
|
+
"deployment.environment": config.deployment_environment,
|
|
108
|
+
**config.resource.attributes,
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# Always set trace source
|
|
112
|
+
resource_attrs["fi.trace.source"] = "traceai"
|
|
113
|
+
|
|
114
|
+
# Auto-inject FutureAGI project attributes when using FUTUREAGI exporter
|
|
115
|
+
has_fi_exporter = any(
|
|
116
|
+
e.type == ExporterType.FUTUREAGI for e in config.exporters
|
|
117
|
+
)
|
|
118
|
+
if has_fi_exporter:
|
|
119
|
+
import json as _json
|
|
120
|
+
import uuid as _uuid
|
|
121
|
+
resource_attrs.setdefault(
|
|
122
|
+
"project_name",
|
|
123
|
+
project_name or os.environ.get("FI_PROJECT_NAME", config.service_name),
|
|
124
|
+
)
|
|
125
|
+
resource_attrs.setdefault("project_type", "observe")
|
|
126
|
+
resource_attrs.setdefault(
|
|
127
|
+
"project_version_name",
|
|
128
|
+
os.environ.get("FI_PROJECT_VERSION_NAME", "v1"),
|
|
129
|
+
)
|
|
130
|
+
resource_attrs.setdefault("project_version_id", str(_uuid.uuid4()))
|
|
131
|
+
resource_attrs.setdefault("eval_tags", _json.dumps([]))
|
|
132
|
+
resource_attrs.setdefault("metadata", _json.dumps({}))
|
|
133
|
+
|
|
134
|
+
resource = Resource.create(resource_attrs)
|
|
135
|
+
|
|
136
|
+
# Create tracer provider
|
|
137
|
+
provider = TracerProvider(
|
|
138
|
+
resource=resource,
|
|
139
|
+
sampler=_create_sampler(config),
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# Add exporters
|
|
143
|
+
for exporter_config in config.exporters:
|
|
144
|
+
exporter = _create_exporter(exporter_config)
|
|
145
|
+
if exporter:
|
|
146
|
+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
147
|
+
provider.add_span_processor(BatchSpanProcessor(exporter))
|
|
148
|
+
|
|
149
|
+
# Add custom processors
|
|
150
|
+
custom_processors = _create_custom_processors(config)
|
|
151
|
+
if custom_processors:
|
|
152
|
+
provider.add_span_processor(custom_processors)
|
|
153
|
+
|
|
154
|
+
# Set as global provider
|
|
155
|
+
trace.set_tracer_provider(provider)
|
|
156
|
+
_tracer_provider = provider
|
|
157
|
+
_is_initialized = True
|
|
158
|
+
|
|
159
|
+
logger.info(
|
|
160
|
+
f"OpenTelemetry tracing initialized for '{config.service_name}' "
|
|
161
|
+
f"with {len(config.exporters)} exporter(s)"
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
return provider
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def _build_config_from_env(
|
|
168
|
+
service_name: Optional[str] = None,
|
|
169
|
+
otlp_endpoint: Optional[str] = None,
|
|
170
|
+
**kwargs,
|
|
171
|
+
) -> TraceConfig:
|
|
172
|
+
"""Build TraceConfig from environment variables."""
|
|
173
|
+
# Service name
|
|
174
|
+
service_name = service_name or os.getenv("OTEL_SERVICE_NAME", "llm-service")
|
|
175
|
+
|
|
176
|
+
# OTLP endpoint
|
|
177
|
+
endpoint = otlp_endpoint or os.getenv("OTEL_EXPORTER_OTLP_ENDPOINT")
|
|
178
|
+
|
|
179
|
+
# Build exporters
|
|
180
|
+
exporters = []
|
|
181
|
+
if endpoint:
|
|
182
|
+
exporters.append(ExporterConfig(
|
|
183
|
+
type=ExporterType.OTLP_GRPC,
|
|
184
|
+
endpoint=endpoint,
|
|
185
|
+
headers=_parse_headers(os.getenv("OTEL_EXPORTER_OTLP_HEADERS", "")),
|
|
186
|
+
))
|
|
187
|
+
else:
|
|
188
|
+
# Default to console
|
|
189
|
+
exporters.append(ExporterConfig(type=ExporterType.CONSOLE))
|
|
190
|
+
|
|
191
|
+
return TraceConfig(
|
|
192
|
+
service_name=service_name,
|
|
193
|
+
exporters=exporters,
|
|
194
|
+
deployment_environment=os.getenv("OTEL_DEPLOYMENT_ENVIRONMENT", "development"),
|
|
195
|
+
**kwargs,
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def _parse_headers(headers_str: str) -> Dict[str, str]:
|
|
200
|
+
"""Parse headers from comma-separated key=value string."""
|
|
201
|
+
if not headers_str:
|
|
202
|
+
return {}
|
|
203
|
+
|
|
204
|
+
headers = {}
|
|
205
|
+
for pair in headers_str.split(","):
|
|
206
|
+
if "=" in pair:
|
|
207
|
+
key, value = pair.split("=", 1)
|
|
208
|
+
headers[key.strip()] = value.strip()
|
|
209
|
+
return headers
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def _create_sampler(config: TraceConfig) -> Any:
|
|
213
|
+
"""Create a sampler based on configuration."""
|
|
214
|
+
from opentelemetry.sdk.trace.sampling import (
|
|
215
|
+
ALWAYS_ON,
|
|
216
|
+
ALWAYS_OFF,
|
|
217
|
+
TraceIdRatioBased,
|
|
218
|
+
ParentBased,
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
if config.sampling_strategy == SamplingStrategy.ALWAYS_ON:
|
|
222
|
+
return ALWAYS_ON
|
|
223
|
+
elif config.sampling_strategy == SamplingStrategy.ALWAYS_OFF:
|
|
224
|
+
return ALWAYS_OFF
|
|
225
|
+
elif config.sampling_strategy == SamplingStrategy.RATIO:
|
|
226
|
+
return TraceIdRatioBased(config.sampling_ratio)
|
|
227
|
+
elif config.sampling_strategy == SamplingStrategy.PARENT_BASED:
|
|
228
|
+
return ParentBased(TraceIdRatioBased(config.sampling_ratio))
|
|
229
|
+
else:
|
|
230
|
+
return ALWAYS_ON
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def _create_exporter(config: ExporterConfig) -> Optional[Any]:
|
|
234
|
+
"""Create an exporter based on configuration."""
|
|
235
|
+
try:
|
|
236
|
+
if config.type == ExporterType.CONSOLE:
|
|
237
|
+
from opentelemetry.sdk.trace.export import ConsoleSpanExporter
|
|
238
|
+
return ConsoleSpanExporter()
|
|
239
|
+
|
|
240
|
+
elif config.type == ExporterType.OTLP_GRPC:
|
|
241
|
+
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
|
|
242
|
+
OTLPSpanExporter,
|
|
243
|
+
)
|
|
244
|
+
return OTLPSpanExporter(
|
|
245
|
+
endpoint=config.endpoint or "localhost:4317",
|
|
246
|
+
headers=config.headers or None,
|
|
247
|
+
insecure=config.insecure,
|
|
248
|
+
timeout=config.timeout_ms // 1000,
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
elif config.type == ExporterType.OTLP_HTTP:
|
|
252
|
+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
|
|
253
|
+
OTLPSpanExporter,
|
|
254
|
+
)
|
|
255
|
+
return OTLPSpanExporter(
|
|
256
|
+
endpoint=config.endpoint or "http://localhost:4318/v1/traces",
|
|
257
|
+
headers=config.headers or None,
|
|
258
|
+
timeout=config.timeout_ms // 1000,
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
elif config.type == ExporterType.JAEGER:
|
|
262
|
+
try:
|
|
263
|
+
from opentelemetry.exporter.jaeger.thrift import JaegerExporter
|
|
264
|
+
return JaegerExporter(
|
|
265
|
+
agent_host_name=config.endpoint.split(":")[0] if config.endpoint else "localhost",
|
|
266
|
+
agent_port=int(config.endpoint.split(":")[1]) if config.endpoint and ":" in config.endpoint else 6831,
|
|
267
|
+
)
|
|
268
|
+
except ImportError:
|
|
269
|
+
logger.warning("Jaeger exporter not available. Install opentelemetry-exporter-jaeger")
|
|
270
|
+
return None
|
|
271
|
+
|
|
272
|
+
elif config.type == ExporterType.ZIPKIN:
|
|
273
|
+
try:
|
|
274
|
+
from opentelemetry.exporter.zipkin.json import ZipkinExporter
|
|
275
|
+
return ZipkinExporter(
|
|
276
|
+
endpoint=config.endpoint or "http://localhost:9411/api/v2/spans",
|
|
277
|
+
)
|
|
278
|
+
except ImportError:
|
|
279
|
+
logger.warning("Zipkin exporter not available. Install opentelemetry-exporter-zipkin")
|
|
280
|
+
return None
|
|
281
|
+
|
|
282
|
+
elif config.type in (ExporterType.ARIZE, ExporterType.PHOENIX, ExporterType.LANGFUSE):
|
|
283
|
+
# These platforms support OTLP
|
|
284
|
+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
|
|
285
|
+
OTLPSpanExporter,
|
|
286
|
+
)
|
|
287
|
+
return OTLPSpanExporter(
|
|
288
|
+
endpoint=config.endpoint,
|
|
289
|
+
headers=config.headers or None,
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
elif config.type == ExporterType.FUTUREAGI:
|
|
293
|
+
# Use OTLP HTTP for FutureAGI backend
|
|
294
|
+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
|
|
295
|
+
OTLPSpanExporter,
|
|
296
|
+
)
|
|
297
|
+
if config.endpoint:
|
|
298
|
+
endpoint = config.endpoint
|
|
299
|
+
else:
|
|
300
|
+
base = os.environ.get("FI_BASE_URL", "https://api.futureagi.com")
|
|
301
|
+
endpoint = f"{base.rstrip('/')}/tracer/v1/traces"
|
|
302
|
+
# Auto-inject FI auth headers if not provided
|
|
303
|
+
headers = config.headers
|
|
304
|
+
if not headers:
|
|
305
|
+
api_key = os.environ.get("FI_API_KEY", "")
|
|
306
|
+
secret_key = os.environ.get("FI_SECRET_KEY", "")
|
|
307
|
+
if api_key and secret_key:
|
|
308
|
+
headers = {
|
|
309
|
+
"X-Api-Key": api_key,
|
|
310
|
+
"X-Secret-Key": secret_key,
|
|
311
|
+
}
|
|
312
|
+
return OTLPSpanExporter(
|
|
313
|
+
endpoint=endpoint,
|
|
314
|
+
headers=headers or None,
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
else:
|
|
318
|
+
logger.warning(f"Unsupported exporter type: {config.type}")
|
|
319
|
+
return None
|
|
320
|
+
|
|
321
|
+
except ImportError as e:
|
|
322
|
+
logger.warning(f"Failed to create exporter {config.type}: {e}")
|
|
323
|
+
return None
|
|
324
|
+
except Exception as e:
|
|
325
|
+
logger.error(f"Error creating exporter {config.type}: {e}")
|
|
326
|
+
return None
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def _create_custom_processors(config: TraceConfig) -> Optional[CompositeSpanProcessor]:
|
|
330
|
+
"""Create custom span processors based on configuration."""
|
|
331
|
+
processors = []
|
|
332
|
+
|
|
333
|
+
# Check for processor configs
|
|
334
|
+
processor_types = {p.type for p in config.processors if p.enabled}
|
|
335
|
+
|
|
336
|
+
# LLM processor
|
|
337
|
+
if ProcessorType.LLM in processor_types:
|
|
338
|
+
processors.append(LLMSpanProcessor(
|
|
339
|
+
capture_prompts=config.content.capture_prompts,
|
|
340
|
+
capture_completions=config.content.capture_completions,
|
|
341
|
+
max_content_length=config.content.max_content_length,
|
|
342
|
+
redact_patterns=config.content.redact_patterns,
|
|
343
|
+
))
|
|
344
|
+
|
|
345
|
+
# Evaluation processor
|
|
346
|
+
if config.evaluation.enabled:
|
|
347
|
+
processors.append(EvaluationSpanProcessor(
|
|
348
|
+
metrics=config.evaluation.metrics,
|
|
349
|
+
sample_rate=config.evaluation.sample_rate,
|
|
350
|
+
async_evaluation=config.evaluation.async_evaluation,
|
|
351
|
+
timeout_ms=config.evaluation.timeout_ms,
|
|
352
|
+
cache_enabled=config.evaluation.cache_enabled,
|
|
353
|
+
cache_ttl_seconds=config.evaluation.cache_ttl_seconds,
|
|
354
|
+
evaluator_model=config.evaluation.evaluator_model,
|
|
355
|
+
))
|
|
356
|
+
|
|
357
|
+
# Cost processor
|
|
358
|
+
if config.cost.enabled:
|
|
359
|
+
processors.append(CostSpanProcessor(
|
|
360
|
+
custom_pricing=None, # Could extend config for this
|
|
361
|
+
alert_threshold_usd=config.cost.alert_threshold_usd,
|
|
362
|
+
))
|
|
363
|
+
|
|
364
|
+
if not processors:
|
|
365
|
+
return None
|
|
366
|
+
|
|
367
|
+
return CompositeSpanProcessor(processors)
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
def get_tracer(name: str = "fi.evals") -> Any:
|
|
371
|
+
"""
|
|
372
|
+
Get a tracer instance.
|
|
373
|
+
|
|
374
|
+
Args:
|
|
375
|
+
name: Tracer name (typically module name)
|
|
376
|
+
|
|
377
|
+
Returns:
|
|
378
|
+
Tracer instance
|
|
379
|
+
"""
|
|
380
|
+
if not OTEL_AVAILABLE:
|
|
381
|
+
return _NoOpTracer()
|
|
382
|
+
|
|
383
|
+
from opentelemetry import trace
|
|
384
|
+
return trace.get_tracer(name)
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
def get_current_span() -> Any:
|
|
388
|
+
"""Get the current active span."""
|
|
389
|
+
if not OTEL_AVAILABLE:
|
|
390
|
+
return None
|
|
391
|
+
|
|
392
|
+
from opentelemetry import trace
|
|
393
|
+
return trace.get_current_span()
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
def is_tracing_enabled() -> bool:
|
|
397
|
+
"""Check if tracing is enabled and initialized."""
|
|
398
|
+
return _is_initialized and _tracer_provider is not None
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
@contextmanager
|
|
402
|
+
def trace_llm_call(
|
|
403
|
+
name: str,
|
|
404
|
+
model: Optional[str] = None,
|
|
405
|
+
system: Optional[str] = None,
|
|
406
|
+
**attributes,
|
|
407
|
+
):
|
|
408
|
+
"""
|
|
409
|
+
Context manager for tracing an LLM call.
|
|
410
|
+
|
|
411
|
+
Creates a span with LLM-specific attributes.
|
|
412
|
+
|
|
413
|
+
Args:
|
|
414
|
+
name: Span name
|
|
415
|
+
model: Model name
|
|
416
|
+
system: Provider system (openai, anthropic, etc.)
|
|
417
|
+
**attributes: Additional span attributes
|
|
418
|
+
|
|
419
|
+
Yields:
|
|
420
|
+
The active span
|
|
421
|
+
|
|
422
|
+
Example:
|
|
423
|
+
with trace_llm_call("chat", model="gpt-4", system="openai") as span:
|
|
424
|
+
response = client.chat.completions.create(...)
|
|
425
|
+
span.set_attribute("gen_ai.usage.input_tokens", response.usage.prompt_tokens)
|
|
426
|
+
"""
|
|
427
|
+
from .conventions import GenAIAttributes, OPERATION_CHAT
|
|
428
|
+
|
|
429
|
+
tracer = get_tracer()
|
|
430
|
+
|
|
431
|
+
# Build initial attributes
|
|
432
|
+
span_attrs = {
|
|
433
|
+
GenAIAttributes.SPAN_KIND: "LLM",
|
|
434
|
+
GenAIAttributes.OPERATION_NAME: OPERATION_CHAT,
|
|
435
|
+
}
|
|
436
|
+
if model:
|
|
437
|
+
span_attrs[GenAIAttributes.REQUEST_MODEL] = model
|
|
438
|
+
if system:
|
|
439
|
+
span_attrs[GenAIAttributes.PROVIDER_NAME] = system
|
|
440
|
+
span_attrs.update(attributes)
|
|
441
|
+
|
|
442
|
+
with tracer.start_as_current_span(name, attributes=span_attrs) as span:
|
|
443
|
+
yield span
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
def shutdown_tracing() -> None:
|
|
447
|
+
"""Shutdown the tracer provider and flush pending spans."""
|
|
448
|
+
global _tracer_provider, _is_initialized
|
|
449
|
+
|
|
450
|
+
if _tracer_provider:
|
|
451
|
+
try:
|
|
452
|
+
_tracer_provider.shutdown()
|
|
453
|
+
except Exception as e:
|
|
454
|
+
logger.warning(f"Error shutting down tracer: {e}")
|
|
455
|
+
|
|
456
|
+
_tracer_provider = None
|
|
457
|
+
_is_initialized = False
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
class _NoOpTracer:
|
|
461
|
+
"""No-op tracer for when OTEL is not available."""
|
|
462
|
+
|
|
463
|
+
def start_span(self, name: str, **kwargs):
|
|
464
|
+
return _NoOpSpan()
|
|
465
|
+
|
|
466
|
+
def start_as_current_span(self, name: str, **kwargs):
|
|
467
|
+
return _NoOpContextManager()
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
class _NoOpSpan:
|
|
471
|
+
"""No-op span."""
|
|
472
|
+
|
|
473
|
+
def set_attribute(self, key: str, value: Any) -> None:
|
|
474
|
+
pass
|
|
475
|
+
|
|
476
|
+
def add_event(self, name: str, attributes: Optional[Dict] = None) -> None:
|
|
477
|
+
pass
|
|
478
|
+
|
|
479
|
+
def set_status(self, status: Any) -> None:
|
|
480
|
+
pass
|
|
481
|
+
|
|
482
|
+
def end(self, end_time: Optional[int] = None) -> None:
|
|
483
|
+
pass
|
|
484
|
+
|
|
485
|
+
def record_exception(self, exception: Exception) -> None:
|
|
486
|
+
pass
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
class _NoOpContextManager:
|
|
490
|
+
"""No-op context manager."""
|
|
491
|
+
|
|
492
|
+
def __enter__(self):
|
|
493
|
+
return _NoOpSpan()
|
|
494
|
+
|
|
495
|
+
def __exit__(self, *args):
|
|
496
|
+
pass
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
__all__ = [
|
|
500
|
+
"setup_tracing",
|
|
501
|
+
"get_tracer",
|
|
502
|
+
"get_current_span",
|
|
503
|
+
"is_tracing_enabled",
|
|
504
|
+
"trace_llm_call",
|
|
505
|
+
"shutdown_tracing",
|
|
506
|
+
]
|