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,45 @@
|
|
|
1
|
+
"""Agent endpoint adapter tree (plan §4.1 + §13).
|
|
2
|
+
|
|
3
|
+
Each adapter conforms to ``AgentEndpoint``. Existing runtime paths keep
|
|
4
|
+
running through ``LiveKitEngine`` — the adapters here give hosted-runner
|
|
5
|
+
and matrix-runner callers a stable spec-level surface without waiting
|
|
6
|
+
for a full engine rewrite.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from .base import (
|
|
12
|
+
AgentEndpoint,
|
|
13
|
+
AgentEndpointManifest,
|
|
14
|
+
DiscoveryRequest,
|
|
15
|
+
DiscoverySnapshot,
|
|
16
|
+
EndpointHandle,
|
|
17
|
+
ReadinessResult,
|
|
18
|
+
ReconciliationResult,
|
|
19
|
+
)
|
|
20
|
+
from .callable import CallableAgentEndpoint
|
|
21
|
+
from .http import HttpAgentEndpoint
|
|
22
|
+
from .livekit import LiveKitAgentEndpoint
|
|
23
|
+
from .retell import RetellAgentEndpoint, RetellCall, RetellCallOriginator
|
|
24
|
+
from .vapi import VapiAgentEndpoint, VapiCall, VapiCallOriginator
|
|
25
|
+
from .websocket import WebSocketAgentEndpoint
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
"AgentEndpoint",
|
|
29
|
+
"AgentEndpointManifest",
|
|
30
|
+
"CallableAgentEndpoint",
|
|
31
|
+
"DiscoveryRequest",
|
|
32
|
+
"DiscoverySnapshot",
|
|
33
|
+
"EndpointHandle",
|
|
34
|
+
"HttpAgentEndpoint",
|
|
35
|
+
"LiveKitAgentEndpoint",
|
|
36
|
+
"ReadinessResult",
|
|
37
|
+
"ReconciliationResult",
|
|
38
|
+
"RetellAgentEndpoint",
|
|
39
|
+
"RetellCall",
|
|
40
|
+
"RetellCallOriginator",
|
|
41
|
+
"VapiAgentEndpoint",
|
|
42
|
+
"VapiCall",
|
|
43
|
+
"VapiCallOriginator",
|
|
44
|
+
"WebSocketAgentEndpoint",
|
|
45
|
+
]
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""Turn-based HTTP target agent (used by the ``http`` actor source).
|
|
2
|
+
|
|
3
|
+
Lifted out of ``hosted/targets.py`` so ``endpoints`` can own it without a cycle
|
|
4
|
+
(``targets`` now dispatches through the endpoint registry).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
from typing import Any, Optional
|
|
11
|
+
|
|
12
|
+
import httpx
|
|
13
|
+
|
|
14
|
+
from fi.simulate.agent.wrapper import AgentInput, AgentWrapper
|
|
15
|
+
|
|
16
|
+
_HTTP_TIMEOUT_SECONDS = 60.0
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class HttpChatAgent(AgentWrapper):
|
|
20
|
+
"""Turn-based target that relays each turn to an HTTP chat endpoint."""
|
|
21
|
+
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
*,
|
|
25
|
+
url: str,
|
|
26
|
+
auth_header: str = "Authorization",
|
|
27
|
+
auth_env: Optional[str] = None,
|
|
28
|
+
extra_headers: Optional[dict[str, str]] = None,
|
|
29
|
+
) -> None:
|
|
30
|
+
self._url = url
|
|
31
|
+
self._auth_header = auth_header
|
|
32
|
+
self._auth_env = auth_env
|
|
33
|
+
self._extra_headers = extra_headers or {}
|
|
34
|
+
|
|
35
|
+
def _headers(self) -> dict[str, str]:
|
|
36
|
+
headers = {"Content-Type": "application/json", **self._extra_headers}
|
|
37
|
+
if self._auth_env:
|
|
38
|
+
token = os.environ.get(self._auth_env)
|
|
39
|
+
if token:
|
|
40
|
+
headers[self._auth_header] = token
|
|
41
|
+
return headers
|
|
42
|
+
|
|
43
|
+
async def call(self, input: AgentInput) -> str:
|
|
44
|
+
payload = {
|
|
45
|
+
"thread_id": input.thread_id,
|
|
46
|
+
"messages": input.messages,
|
|
47
|
+
"new_message": input.new_message,
|
|
48
|
+
}
|
|
49
|
+
async with httpx.AsyncClient(timeout=_HTTP_TIMEOUT_SECONDS) as client:
|
|
50
|
+
response = await client.post(
|
|
51
|
+
self._url, json=payload, headers=self._headers()
|
|
52
|
+
)
|
|
53
|
+
response.raise_for_status()
|
|
54
|
+
return _extract_reply(response.json())
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _extract_reply(body: Any) -> str:
|
|
58
|
+
if isinstance(body, str):
|
|
59
|
+
return body
|
|
60
|
+
if isinstance(body, dict):
|
|
61
|
+
for key in ("content", "reply", "message", "response", "output", "text"):
|
|
62
|
+
value = body.get(key)
|
|
63
|
+
if isinstance(value, str) and value:
|
|
64
|
+
return value
|
|
65
|
+
choices = body.get("choices")
|
|
66
|
+
if isinstance(choices, list) and choices:
|
|
67
|
+
message = choices[0].get("message") if isinstance(choices[0], dict) else None
|
|
68
|
+
if isinstance(message, dict) and isinstance(message.get("content"), str):
|
|
69
|
+
return message["content"]
|
|
70
|
+
return ""
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
__all__ = ["HttpChatAgent"]
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
"""Actor-source resolvers (canonical plan §4.1) — the "drop in any agent" surface.
|
|
2
|
+
|
|
3
|
+
A turn-based target agent can be declared as any of several *kinds*, resolved to
|
|
4
|
+
a runnable ``AgentWrapper`` / callable the environment drives. The kinds and their
|
|
5
|
+
config keys are the pydantic-schema twin of the manifest ``agent:`` block
|
|
6
|
+
(``target`` / ``factory`` / ``args`` / ``kwargs`` / ``method`` / ``input_mode`` /
|
|
7
|
+
``system_prompt`` / …), so a manifest agent and a spec ActorSource are the same
|
|
8
|
+
declaration in two encodings — no third vocabulary.
|
|
9
|
+
|
|
10
|
+
Each resolver is attached to an ``EndpointProfile`` in ``profiles.py`` and reached
|
|
11
|
+
through the one ``endpoint_registry``. Heavy imports (``wrap_agent``, LLM clients,
|
|
12
|
+
``httpx``) are deferred into the resolver bodies so the planner/registry stay light.
|
|
13
|
+
|
|
14
|
+
Security (hosted runs execute *customer-supplied* config on our infra):
|
|
15
|
+
|
|
16
|
+
* Kinds that import + call caller-named Python (``python_callable`` /
|
|
17
|
+
``import_object`` / ``factory`` / ``framework``) are **rejected in hosted runs**
|
|
18
|
+
— the gate lives in ``resolve_chat_target`` and reads ``EndpointProfile.
|
|
19
|
+
runs_caller_code`` (deny-by-default), not a denylist. In-process execution of
|
|
20
|
+
customer code belongs in the sandboxed runtime (``RuntimeIsolation`` above
|
|
21
|
+
``shared_runner_process``), not the runner process. A single explicit,
|
|
22
|
+
scarily-named escape (``ALK_UNSAFE_INPROCESS_CODE_ACTORS``) exists only for a
|
|
23
|
+
trusted operator-configured default target and tests — never set it in prod.
|
|
24
|
+
* Env reads by ``system_prompt`` / ``http`` are restricted in hosted runs to the
|
|
25
|
+
keys the job itself provisioned (``secret_refs``), so a job cannot name an
|
|
26
|
+
arbitrary env var (e.g. another tenant's secret) to exfiltrate.
|
|
27
|
+
* Local (developer) runs resolve with ``hosted=False`` and stay permissive — the
|
|
28
|
+
developer is running their own code on their own machine.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
from __future__ import annotations
|
|
32
|
+
|
|
33
|
+
import importlib
|
|
34
|
+
import os
|
|
35
|
+
from typing import Any, Callable, Mapping, Optional
|
|
36
|
+
|
|
37
|
+
_UNSAFE_INPROCESS_ENV = "ALK_UNSAFE_INPROCESS_CODE_ACTORS"
|
|
38
|
+
|
|
39
|
+
_WRAP_KEYS = (
|
|
40
|
+
"method",
|
|
41
|
+
"input_mode",
|
|
42
|
+
"input_key",
|
|
43
|
+
"input_kwargs",
|
|
44
|
+
"output_key",
|
|
45
|
+
"system_prompt",
|
|
46
|
+
"metadata",
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class ActorSourceError(ValueError):
|
|
51
|
+
"""Raised when an actor-source config cannot be resolved to a runnable agent."""
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def inprocess_code_allowed() -> bool:
|
|
55
|
+
"""Whether in-process execution of caller code is explicitly permitted (the
|
|
56
|
+
trusted operator-default target / tests). Deny by default."""
|
|
57
|
+
return os.environ.get(_UNSAFE_INPROCESS_ENV, "").strip().lower() in (
|
|
58
|
+
"1",
|
|
59
|
+
"true",
|
|
60
|
+
"yes",
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _allowed_env_keys(secret_refs: Optional[Mapping[str, Any]]) -> set[str]:
|
|
65
|
+
keys: set[str] = set()
|
|
66
|
+
for name, ref in (secret_refs or {}).items():
|
|
67
|
+
ref_key = getattr(ref, "key", None)
|
|
68
|
+
keys.add(str(ref_key if ref_key is not None else name))
|
|
69
|
+
return keys
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _require_env_allowed(
|
|
73
|
+
env_key: str, secret_refs: Optional[Mapping[str, Any]], *, hosted: bool
|
|
74
|
+
) -> None:
|
|
75
|
+
if not hosted:
|
|
76
|
+
return
|
|
77
|
+
if env_key not in _allowed_env_keys(secret_refs):
|
|
78
|
+
raise ActorSourceError(
|
|
79
|
+
f"env_not_provisioned: hosted actor may only read job-provisioned "
|
|
80
|
+
f"secrets; {env_key!r} is not in the job's secret_env"
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _load_attr(ref: Any) -> Any:
|
|
85
|
+
if not isinstance(ref, str) or ":" not in ref:
|
|
86
|
+
raise ActorSourceError("actor target requires 'module:attribute'")
|
|
87
|
+
module_name, _, attr = ref.partition(":")
|
|
88
|
+
if not module_name or not attr:
|
|
89
|
+
raise ActorSourceError(f"actor target malformed: {ref!r}")
|
|
90
|
+
module = importlib.import_module(module_name)
|
|
91
|
+
obj = getattr(module, attr, None)
|
|
92
|
+
if obj is None:
|
|
93
|
+
raise ActorSourceError(f"actor target not found: {ref!r}")
|
|
94
|
+
return obj
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _wrap_opts(config: Mapping[str, Any]) -> dict[str, Any]:
|
|
98
|
+
return {key: config[key] for key in _WRAP_KEYS if config.get(key) is not None}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _instantiate_if_factory(loaded: Any, config: Mapping[str, Any]) -> Any:
|
|
102
|
+
if not (config.get("factory") or config.get("instantiate")):
|
|
103
|
+
return loaded
|
|
104
|
+
args = config.get("args") or config.get("factory_args") or []
|
|
105
|
+
kwargs = config.get("kwargs") or config.get("factory_kwargs") or {}
|
|
106
|
+
return loaded(*list(args), **dict(kwargs))
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
# --------------------------------------------------------------------------- #
|
|
110
|
+
# resolvers — (config, secret_refs, *, hosted) -> AgentWrapper | Callable
|
|
111
|
+
# The code-loading kinds are rejected in hosted runs by resolve_chat_target
|
|
112
|
+
# (profile.runs_caller_code) before they are ever called; ``hosted`` is accepted
|
|
113
|
+
# here for a uniform signature and defensive checks.
|
|
114
|
+
# --------------------------------------------------------------------------- #
|
|
115
|
+
def resolve_python_callable(
|
|
116
|
+
config: Mapping[str, Any],
|
|
117
|
+
secret_refs: Optional[Mapping[str, Any]] = None,
|
|
118
|
+
*,
|
|
119
|
+
hosted: bool = False,
|
|
120
|
+
) -> Callable[..., Any]:
|
|
121
|
+
ref = config.get("target") or config.get("callable")
|
|
122
|
+
target = _load_attr(ref)
|
|
123
|
+
if not callable(target):
|
|
124
|
+
raise ActorSourceError(f"actor target is not callable: {ref!r}")
|
|
125
|
+
return target
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def resolve_import_object(
|
|
129
|
+
config: Mapping[str, Any],
|
|
130
|
+
secret_refs: Optional[Mapping[str, Any]] = None,
|
|
131
|
+
*,
|
|
132
|
+
hosted: bool = False,
|
|
133
|
+
) -> Any:
|
|
134
|
+
from fi.simulate.agent.generic import wrap_agent
|
|
135
|
+
|
|
136
|
+
obj = _load_attr(config.get("target"))
|
|
137
|
+
return wrap_agent(obj, **_wrap_opts(config))
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def resolve_factory(
|
|
141
|
+
config: Mapping[str, Any],
|
|
142
|
+
secret_refs: Optional[Mapping[str, Any]] = None,
|
|
143
|
+
*,
|
|
144
|
+
hosted: bool = False,
|
|
145
|
+
) -> Any:
|
|
146
|
+
from fi.simulate.agent.generic import wrap_agent
|
|
147
|
+
|
|
148
|
+
cls = _load_attr(config.get("target"))
|
|
149
|
+
instance = _instantiate_if_factory(cls, {**config, "factory": True})
|
|
150
|
+
return wrap_agent(instance, **_wrap_opts(config))
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def resolve_framework(
|
|
154
|
+
config: Mapping[str, Any],
|
|
155
|
+
secret_refs: Optional[Mapping[str, Any]] = None,
|
|
156
|
+
*,
|
|
157
|
+
hosted: bool = False,
|
|
158
|
+
) -> Any:
|
|
159
|
+
from fi.simulate.agent.generic import wrap_agent
|
|
160
|
+
|
|
161
|
+
loaded = _instantiate_if_factory(_load_attr(config.get("target")), config)
|
|
162
|
+
return wrap_agent(loaded, **_wrap_opts(config))
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def resolve_system_prompt(
|
|
166
|
+
config: Mapping[str, Any],
|
|
167
|
+
secret_refs: Optional[Mapping[str, Any]] = None,
|
|
168
|
+
*,
|
|
169
|
+
hosted: bool = False,
|
|
170
|
+
) -> Any:
|
|
171
|
+
from fi.simulate.agent.wrappers import OpenAIAgentWrapper
|
|
172
|
+
|
|
173
|
+
prompt = config.get("system_prompt") or config.get("prompt")
|
|
174
|
+
if not prompt:
|
|
175
|
+
raise ActorSourceError("system_prompt actor requires 'system_prompt'")
|
|
176
|
+
api_key_env = str(config.get("api_key_env", "OPENAI_API_KEY"))
|
|
177
|
+
_require_env_allowed(api_key_env, secret_refs, hosted=hosted)
|
|
178
|
+
api_key = os.environ.get(api_key_env)
|
|
179
|
+
if not api_key:
|
|
180
|
+
raise ActorSourceError(f"system_prompt actor needs {api_key_env} in the env")
|
|
181
|
+
try:
|
|
182
|
+
import openai
|
|
183
|
+
except ImportError as exc: # pragma: no cover - optional dep
|
|
184
|
+
raise ActorSourceError("system_prompt actor requires the openai package") from exc
|
|
185
|
+
client_kwargs: dict[str, Any] = {"api_key": api_key}
|
|
186
|
+
base_url = config.get("base_url")
|
|
187
|
+
if base_url:
|
|
188
|
+
client_kwargs["base_url"] = str(base_url)
|
|
189
|
+
client = openai.AsyncOpenAI(**client_kwargs)
|
|
190
|
+
return OpenAIAgentWrapper(
|
|
191
|
+
client, model=str(config.get("model", "gpt-4-turbo")), system_prompt=str(prompt)
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def resolve_http(
|
|
196
|
+
config: Mapping[str, Any],
|
|
197
|
+
secret_refs: Optional[Mapping[str, Any]] = None,
|
|
198
|
+
*,
|
|
199
|
+
hosted: bool = False,
|
|
200
|
+
) -> Any:
|
|
201
|
+
from fi.simulate.endpoints._http_actor import HttpChatAgent
|
|
202
|
+
|
|
203
|
+
url = config.get("url")
|
|
204
|
+
if not isinstance(url, str) or not url:
|
|
205
|
+
raise ActorSourceError("http actor requires config.url")
|
|
206
|
+
# auth_env is derived from the job's own secret_refs, so it is provisioned by
|
|
207
|
+
# construction — no arbitrary env read.
|
|
208
|
+
return HttpChatAgent(
|
|
209
|
+
url=url,
|
|
210
|
+
auth_header=str(config.get("auth_header") or "Authorization"),
|
|
211
|
+
auth_env=_auth_env_from_refs(secret_refs),
|
|
212
|
+
extra_headers=_string_map(config.get("headers")),
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def _auth_env_from_refs(secret_refs: Optional[Mapping[str, Any]]) -> Optional[str]:
|
|
217
|
+
if not secret_refs:
|
|
218
|
+
return None
|
|
219
|
+
for purpose in ("api_key", "authorization", "token"):
|
|
220
|
+
for name, ref in secret_refs.items():
|
|
221
|
+
ref_purpose = getattr(ref, "purpose", None)
|
|
222
|
+
ref_key = getattr(ref, "key", None)
|
|
223
|
+
if ref_purpose == purpose or name == purpose:
|
|
224
|
+
return ref_key
|
|
225
|
+
return None
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def _string_map(value: Any) -> dict[str, str]:
|
|
229
|
+
if not isinstance(value, dict):
|
|
230
|
+
return {}
|
|
231
|
+
return {str(k): str(v) for k, v in value.items()}
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
__all__ = [
|
|
235
|
+
"ActorSourceError",
|
|
236
|
+
"inprocess_code_allowed",
|
|
237
|
+
"resolve_factory",
|
|
238
|
+
"resolve_framework",
|
|
239
|
+
"resolve_http",
|
|
240
|
+
"resolve_import_object",
|
|
241
|
+
"resolve_python_callable",
|
|
242
|
+
"resolve_system_prompt",
|
|
243
|
+
]
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""AgentEndpoint Protocol + shared data types (plan §4.1)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import AsyncIterator
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
from typing import Protocol
|
|
8
|
+
|
|
9
|
+
from pydantic import BaseModel, Field, JsonValue
|
|
10
|
+
|
|
11
|
+
from fi.simulate.realtime.events import RealtimeEvent
|
|
12
|
+
from fi.simulate.realtime.media import AudioFrame
|
|
13
|
+
from fi.simulate.runtime.capabilities import EndpointCapabilities
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class AgentEndpointManifest(BaseModel):
|
|
17
|
+
"""Static declaration of an endpoint adapter's identity + shape.
|
|
18
|
+
|
|
19
|
+
The planner records the manifest on the plan so hosted runs can
|
|
20
|
+
reconstruct which adapter (name + version) executed a case.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
name: str
|
|
24
|
+
version: str = "1"
|
|
25
|
+
provider: str
|
|
26
|
+
world_kinds: list[str] = Field(default_factory=lambda: ["voice"])
|
|
27
|
+
capabilities: EndpointCapabilities = Field(default_factory=EndpointCapabilities)
|
|
28
|
+
metadata: dict[str, JsonValue] = Field(default_factory=dict)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class DiscoveryRequest(BaseModel):
|
|
32
|
+
run_id: str
|
|
33
|
+
test_case_id: str
|
|
34
|
+
required_capabilities: list[str] = Field(default_factory=list)
|
|
35
|
+
metadata: dict[str, JsonValue] = Field(default_factory=dict)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class DiscoverySnapshot(BaseModel):
|
|
39
|
+
capabilities: EndpointCapabilities
|
|
40
|
+
supported: bool = True
|
|
41
|
+
reasons: list[str] = Field(default_factory=list)
|
|
42
|
+
metadata: dict[str, JsonValue] = Field(default_factory=dict)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class EndpointHandle(BaseModel):
|
|
46
|
+
"""Opaque adapter handle returned by ``prepare`` and reused for the case."""
|
|
47
|
+
|
|
48
|
+
handle_id: str
|
|
49
|
+
endpoint_name: str
|
|
50
|
+
created_at: datetime
|
|
51
|
+
metadata: dict[str, JsonValue] = Field(default_factory=dict)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class ReadinessResult(BaseModel):
|
|
55
|
+
ready: bool
|
|
56
|
+
latency_ms: float | None = None
|
|
57
|
+
reason: str | None = None
|
|
58
|
+
metadata: dict[str, JsonValue] = Field(default_factory=dict)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class ReconciliationResult(BaseModel):
|
|
62
|
+
reconciled: bool
|
|
63
|
+
orphan_ids: list[str] = Field(default_factory=list)
|
|
64
|
+
metadata: dict[str, JsonValue] = Field(default_factory=dict)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class AgentEndpoint(Protocol):
|
|
68
|
+
"""Session-oriented target-agent adapter contract (plan §4.1).
|
|
69
|
+
|
|
70
|
+
Turn-based agents can still use the legacy ``AgentWrapper.call``
|
|
71
|
+
surface; this Protocol is the target for realtime/voice/session
|
|
72
|
+
agents where the engine needs prepare/wait_ready/stop lifecycle.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
manifest: AgentEndpointManifest
|
|
76
|
+
capabilities: EndpointCapabilities
|
|
77
|
+
|
|
78
|
+
async def discover(self, request: DiscoveryRequest) -> DiscoverySnapshot: ...
|
|
79
|
+
|
|
80
|
+
async def prepare(self, plan) -> EndpointHandle: ... # SimulationPlan
|
|
81
|
+
|
|
82
|
+
async def wait_ready(self, handle: EndpointHandle) -> ReadinessResult: ...
|
|
83
|
+
|
|
84
|
+
async def send(
|
|
85
|
+
self, handle: EndpointHandle, event: RealtimeEvent | AudioFrame
|
|
86
|
+
) -> None: ...
|
|
87
|
+
|
|
88
|
+
async def receive(
|
|
89
|
+
self, handle: EndpointHandle
|
|
90
|
+
) -> AsyncIterator[RealtimeEvent | AudioFrame]: ...
|
|
91
|
+
|
|
92
|
+
async def stop(self, handle: EndpointHandle) -> None: ...
|
|
93
|
+
|
|
94
|
+
async def cleanup(self, handle: EndpointHandle) -> None: ...
|
|
95
|
+
|
|
96
|
+
async def reconcile(self, handle: EndpointHandle) -> ReconciliationResult: ...
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
__all__ = [
|
|
100
|
+
"AgentEndpoint",
|
|
101
|
+
"AgentEndpointManifest",
|
|
102
|
+
"DiscoveryRequest",
|
|
103
|
+
"DiscoverySnapshot",
|
|
104
|
+
"EndpointHandle",
|
|
105
|
+
"ReadinessResult",
|
|
106
|
+
"ReconciliationResult",
|
|
107
|
+
]
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""Back-compat shim. Builtin endpoint registrations moved to
|
|
2
|
+
``fi.simulate.endpoints.profiles`` (slice 3) — importing this module still
|
|
3
|
+
triggers registration via that module's import side effect.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from fi.simulate.endpoints import profiles as _profiles # noqa: F401
|
|
9
|
+
|
|
10
|
+
__all__: list[str] = []
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""Callable target-agent adapter for turn-based chat runs."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import uuid
|
|
6
|
+
from collections.abc import AsyncIterator, Callable
|
|
7
|
+
from datetime import datetime, timezone
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from fi.simulate.realtime.events import RealtimeEvent
|
|
11
|
+
from fi.simulate.realtime.media import AudioFrame
|
|
12
|
+
from fi.simulate.runtime.capabilities import EndpointCapabilities
|
|
13
|
+
|
|
14
|
+
from .base import (
|
|
15
|
+
AgentEndpointManifest,
|
|
16
|
+
DiscoveryRequest,
|
|
17
|
+
DiscoverySnapshot,
|
|
18
|
+
EndpointHandle,
|
|
19
|
+
ReadinessResult,
|
|
20
|
+
ReconciliationResult,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class CallableAgentEndpoint:
|
|
25
|
+
"""Wraps a plain callable/coroutine target agent."""
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
agent_callable: Callable[..., Any],
|
|
30
|
+
*,
|
|
31
|
+
name: str = "callable-agent",
|
|
32
|
+
) -> None:
|
|
33
|
+
self._callable = agent_callable
|
|
34
|
+
self.manifest = AgentEndpointManifest(
|
|
35
|
+
name=name,
|
|
36
|
+
provider="callable",
|
|
37
|
+
world_kinds=["chat"],
|
|
38
|
+
capabilities=EndpointCapabilities(text=True, streaming=False),
|
|
39
|
+
)
|
|
40
|
+
self.capabilities = self.manifest.capabilities
|
|
41
|
+
|
|
42
|
+
async def discover(self, request: DiscoveryRequest) -> DiscoverySnapshot:
|
|
43
|
+
missing = [
|
|
44
|
+
cap
|
|
45
|
+
for cap in request.required_capabilities
|
|
46
|
+
if cap not in self.capabilities.supported()
|
|
47
|
+
]
|
|
48
|
+
return DiscoverySnapshot(
|
|
49
|
+
capabilities=self.capabilities,
|
|
50
|
+
supported=not missing,
|
|
51
|
+
reasons=[f"unsupported:{cap}" for cap in missing],
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
async def prepare(self, plan) -> EndpointHandle: # noqa: ANN001
|
|
55
|
+
return EndpointHandle(
|
|
56
|
+
handle_id=f"cb-{uuid.uuid4().hex[:12]}",
|
|
57
|
+
endpoint_name=self.manifest.name,
|
|
58
|
+
created_at=datetime.now(timezone.utc),
|
|
59
|
+
metadata={"plan_id": getattr(plan, "plan_id", None)},
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
async def wait_ready(self, handle: EndpointHandle) -> ReadinessResult:
|
|
63
|
+
del handle
|
|
64
|
+
return ReadinessResult(ready=True)
|
|
65
|
+
|
|
66
|
+
async def send(
|
|
67
|
+
self, handle: EndpointHandle, event: RealtimeEvent | AudioFrame
|
|
68
|
+
) -> None:
|
|
69
|
+
raise NotImplementedError("CallableAgentEndpoint is turn-based; use invoke()")
|
|
70
|
+
|
|
71
|
+
async def receive(
|
|
72
|
+
self, handle: EndpointHandle
|
|
73
|
+
) -> AsyncIterator[RealtimeEvent | AudioFrame]:
|
|
74
|
+
raise NotImplementedError("CallableAgentEndpoint is turn-based; use invoke()")
|
|
75
|
+
# unreachable, kept for Protocol conformance
|
|
76
|
+
yield # type: ignore[unreachable]
|
|
77
|
+
|
|
78
|
+
async def stop(self, handle: EndpointHandle) -> None:
|
|
79
|
+
del handle
|
|
80
|
+
|
|
81
|
+
async def cleanup(self, handle: EndpointHandle) -> None:
|
|
82
|
+
del handle
|
|
83
|
+
|
|
84
|
+
async def reconcile(self, handle: EndpointHandle) -> ReconciliationResult:
|
|
85
|
+
del handle
|
|
86
|
+
return ReconciliationResult(reconciled=True)
|
|
87
|
+
|
|
88
|
+
async def invoke(self, *args: Any, **kwargs: Any) -> Any:
|
|
89
|
+
result = self._callable(*args, **kwargs)
|
|
90
|
+
if hasattr(result, "__await__"):
|
|
91
|
+
return await result
|
|
92
|
+
return result
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
__all__ = ["CallableAgentEndpoint"]
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""HTTP target-agent adapter — capability declaration + Stage-6 seam."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import uuid
|
|
6
|
+
from collections.abc import AsyncIterator
|
|
7
|
+
from datetime import datetime, timezone
|
|
8
|
+
|
|
9
|
+
from pydantic import AnyHttpUrl
|
|
10
|
+
|
|
11
|
+
from fi.simulate.realtime.events import RealtimeEvent
|
|
12
|
+
from fi.simulate.realtime.media import AudioFrame
|
|
13
|
+
from fi.simulate.runtime.capabilities import EndpointCapabilities
|
|
14
|
+
|
|
15
|
+
from .base import (
|
|
16
|
+
AgentEndpointManifest,
|
|
17
|
+
DiscoveryRequest,
|
|
18
|
+
DiscoverySnapshot,
|
|
19
|
+
EndpointHandle,
|
|
20
|
+
ReadinessResult,
|
|
21
|
+
ReconciliationResult,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class HttpAgentEndpoint:
|
|
26
|
+
"""Points at an HTTP agent surface. Wire-up lands in Stage 6."""
|
|
27
|
+
|
|
28
|
+
def __init__(self, *, name: str, url: AnyHttpUrl | str) -> None:
|
|
29
|
+
self.manifest = AgentEndpointManifest(
|
|
30
|
+
name=name,
|
|
31
|
+
provider="http",
|
|
32
|
+
world_kinds=["chat"],
|
|
33
|
+
capabilities=EndpointCapabilities(text=True, tool_events=True),
|
|
34
|
+
metadata={"url": str(url)},
|
|
35
|
+
)
|
|
36
|
+
self.capabilities = self.manifest.capabilities
|
|
37
|
+
|
|
38
|
+
async def discover(self, request: DiscoveryRequest) -> DiscoverySnapshot:
|
|
39
|
+
del request
|
|
40
|
+
return DiscoverySnapshot(capabilities=self.capabilities)
|
|
41
|
+
|
|
42
|
+
async def prepare(self, plan) -> EndpointHandle: # noqa: ANN001
|
|
43
|
+
return EndpointHandle(
|
|
44
|
+
handle_id=f"http-{uuid.uuid4().hex[:12]}",
|
|
45
|
+
endpoint_name=self.manifest.name,
|
|
46
|
+
created_at=datetime.now(timezone.utc),
|
|
47
|
+
metadata={"plan_id": getattr(plan, "plan_id", None)},
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
async def wait_ready(self, handle: EndpointHandle) -> ReadinessResult:
|
|
51
|
+
del handle
|
|
52
|
+
raise NotImplementedError("HttpAgentEndpoint readiness lands in Stage 6")
|
|
53
|
+
|
|
54
|
+
async def send(
|
|
55
|
+
self, handle: EndpointHandle, event: RealtimeEvent | AudioFrame
|
|
56
|
+
) -> None:
|
|
57
|
+
raise NotImplementedError("HttpAgentEndpoint send lands in Stage 6")
|
|
58
|
+
|
|
59
|
+
async def receive(
|
|
60
|
+
self, handle: EndpointHandle
|
|
61
|
+
) -> AsyncIterator[RealtimeEvent | AudioFrame]:
|
|
62
|
+
raise NotImplementedError("HttpAgentEndpoint receive lands in Stage 6")
|
|
63
|
+
yield # type: ignore[unreachable]
|
|
64
|
+
|
|
65
|
+
async def stop(self, handle: EndpointHandle) -> None:
|
|
66
|
+
del handle
|
|
67
|
+
|
|
68
|
+
async def cleanup(self, handle: EndpointHandle) -> None:
|
|
69
|
+
del handle
|
|
70
|
+
|
|
71
|
+
async def reconcile(self, handle: EndpointHandle) -> ReconciliationResult:
|
|
72
|
+
del handle
|
|
73
|
+
return ReconciliationResult(reconciled=True)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
__all__ = ["HttpAgentEndpoint"]
|