agentevolve-optimizer 0.5.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.
Files changed (414) hide show
  1. agent_evolve/__init__.py +722 -0
  2. agent_evolve/agentic.py +2800 -0
  3. agent_evolve/api.py +767 -0
  4. agent_evolve/application/__init__.py +1580 -0
  5. agent_evolve/application/action_allocation.py +744 -0
  6. agent_evolve/application/action_allocation_frame.py +347 -0
  7. agent_evolve/application/action_allocation_frame_commit.py +185 -0
  8. agent_evolve/application/action_allocation_frame_commit_v3.py +184 -0
  9. agent_evolve/application/action_allocation_frame_v3.py +338 -0
  10. agent_evolve/application/action_archive_value.py +497 -0
  11. agent_evolve/application/action_evidence_consistency.py +455 -0
  12. agent_evolve/application/action_forecast_partitioning.py +1471 -0
  13. agent_evolve/application/action_metric_projection.py +211 -0
  14. agent_evolve/application/action_role_value.py +680 -0
  15. agent_evolve/application/action_score_authorities.py +363 -0
  16. agent_evolve/application/action_structural_signature.py +116 -0
  17. agent_evolve/application/action_target_realization.py +402 -0
  18. agent_evolve/application/agentic_evolution.py +7734 -0
  19. agent_evolve/application/agentic_portfolio_residual_expert.py +835 -0
  20. agent_evolve/application/anchor_residual_identification.py +463 -0
  21. agent_evolve/application/archive_conditioned_action_target.py +208 -0
  22. agent_evolve/application/artifact_journal.py +246 -0
  23. agent_evolve/application/artifact_replay.py +347 -0
  24. agent_evolve/application/budgeted_optimizer.py +1828 -0
  25. agent_evolve/application/calibrated_campaign.py +485 -0
  26. agent_evolve/application/calibrated_current_prefix_forecast_opportunity.py +322 -0
  27. agent_evolve/application/calibrated_positive_gain_opportunity.py +1581 -0
  28. agent_evolve/application/campaign_capacity_recourse.py +254 -0
  29. agent_evolve/application/campaign_contextual_outcomes.py +119 -0
  30. agent_evolve/application/campaign_diagnostic_blocks.py +930 -0
  31. agent_evolve/application/campaign_evidence_registry.py +262 -0
  32. agent_evolve/application/campaign_execution.py +2537 -0
  33. agent_evolve/application/campaign_generation_audit.py +942 -0
  34. agent_evolve/application/campaign_learning.py +1812 -0
  35. agent_evolve/application/campaign_learning_runtime.py +1977 -0
  36. agent_evolve/application/campaign_search_phase.py +227 -0
  37. agent_evolve/application/campaign_selector_context_extension.py +220 -0
  38. agent_evolve/application/campaign_variation_envelope.py +649 -0
  39. agent_evolve/application/campaign_variation_trace.py +451 -0
  40. agent_evolve/application/candidate_archive_consequence.py +128 -0
  41. agent_evolve/application/causal_opportunity_portfolio_gate.py +385 -0
  42. agent_evolve/application/composite_outcome_updater.py +145 -0
  43. agent_evolve/application/composition_portfolio_selection.py +363 -0
  44. agent_evolve/application/concurrent_stage.py +144 -0
  45. agent_evolve/application/contextual_action_allocation.py +181 -0
  46. agent_evolve/application/contextual_campaign_outcomes.py +267 -0
  47. agent_evolve/application/contextual_campaign_planning.py +1366 -0
  48. agent_evolve/application/contextual_delayed_credit.py +651 -0
  49. agent_evolve/application/contextual_search_controller.py +2374 -0
  50. agent_evolve/application/current_prefix_forecast_opportunity.py +714 -0
  51. agent_evolve/application/decision_metric_projection.py +112 -0
  52. agent_evolve/application/derived_action_semantics.py +129 -0
  53. agent_evolve/application/detailed_evaluation.py +449 -0
  54. agent_evolve/application/earned_lineage.py +1011 -0
  55. agent_evolve/application/effective_choice_audit.py +484 -0
  56. agent_evolve/application/empirical_consequence_calibration.py +908 -0
  57. agent_evolve/application/evaluation_accounting.py +325 -0
  58. agent_evolve/application/evaluation_cache.py +199 -0
  59. agent_evolve/application/evaluation_escrow.py +547 -0
  60. agent_evolve/application/evaluation_recourse.py +253 -0
  61. agent_evolve/application/event_recorder.py +151 -0
  62. agent_evolve/application/evolution_campaign.py +1840 -0
  63. agent_evolve/application/executable_hypothesis.py +323 -0
  64. agent_evolve/application/factorial_branch_pilot.py +772 -0
  65. agent_evolve/application/finite_acquisition_capacity_recourse.py +672 -0
  66. agent_evolve/application/finite_acquisition_residual_expert.py +373 -0
  67. agent_evolve/application/finite_acquisition_variation_envelope.py +802 -0
  68. agent_evolve/application/finite_action_hypothesis_semantics.py +446 -0
  69. agent_evolve/application/finite_action_selection.py +188 -0
  70. agent_evolve/application/finite_action_set.py +306 -0
  71. agent_evolve/application/finite_action_transition.py +537 -0
  72. agent_evolve/application/finite_variation_eligibility.py +296 -0
  73. agent_evolve/application/forecast_geometry_portfolio.py +799 -0
  74. agent_evolve/application/forecast_opportunity_shadow_calibration.py +316 -0
  75. agent_evolve/application/front_proximity_admission.py +311 -0
  76. agent_evolve/application/front_proximity_parent_basis.py +458 -0
  77. agent_evolve/application/frozen_hurdle_score.py +659 -0
  78. agent_evolve/application/g3_causal_screen.py +2257 -0
  79. agent_evolve/application/g3_causal_validation.py +1046 -0
  80. agent_evolve/application/g3_postseal_curation.py +818 -0
  81. agent_evolve/application/gated_agentic_generator.py +205 -0
  82. agent_evolve/application/generation_feedback.py +293 -0
  83. agent_evolve/application/generative_proposal_journal.py +185 -0
  84. agent_evolve/application/geometry_conditional_elasticity.py +453 -0
  85. agent_evolve/application/global_wave_action_allocation.py +1151 -0
  86. agent_evolve/application/head_mass_conditional_seat.py +268 -0
  87. agent_evolve/application/identifiable_reflection_evidence.py +1147 -0
  88. agent_evolve/application/identifiable_reflection_learning.py +395 -0
  89. agent_evolve/application/identifiable_reflection_request.py +364 -0
  90. agent_evolve/application/in_memory_residual_archive.py +341 -0
  91. agent_evolve/application/insight_memory.py +1804 -0
  92. agent_evolve/application/live_runtime_manifest.py +758 -0
  93. agent_evolve/application/llm_task_queue.py +769 -0
  94. agent_evolve/application/matched_finite_action_block.py +409 -0
  95. agent_evolve/application/materialized_action_broker.py +2328 -0
  96. agent_evolve/application/materialized_action_constraints.py +83 -0
  97. agent_evolve/application/materialized_variation.py +211 -0
  98. agent_evolve/application/multi_option_evolution.py +1536 -0
  99. agent_evolve/application/outcome_adaptive_action_racing.py +2827 -0
  100. agent_evolve/application/outcome_adaptive_residual_campaign_runtime.py +580 -0
  101. agent_evolve/application/outcome_adaptive_residual_portfolio_evolution.py +3671 -0
  102. agent_evolve/application/outcome_conditioned_portfolio_selection.py +1374 -0
  103. agent_evolve/application/outcome_relation.py +193 -0
  104. agent_evolve/application/paired_allocation_comparison.py +241 -0
  105. agent_evolve/application/paired_block_schedule.py +127 -0
  106. agent_evolve/application/parent_measurement.py +226 -0
  107. agent_evolve/application/pareto_archive.py +811 -0
  108. agent_evolve/application/portfolio_campaign_runtime.py +4739 -0
  109. agent_evolve/application/portfolio_evolution.py +2950 -0
  110. agent_evolve/application/portfolio_hypothesis_observations.py +814 -0
  111. agent_evolve/application/portfolio_memory_attribution.py +581 -0
  112. agent_evolve/application/portfolio_memory_dose.py +788 -0
  113. agent_evolve/application/portfolio_memory_matched_control.py +938 -0
  114. agent_evolve/application/portfolio_memory_transfer.py +297 -0
  115. agent_evolve/application/portfolio_optimization_memory.py +363 -0
  116. agent_evolve/application/portfolio_outcome_feedback.py +1613 -0
  117. agent_evolve/application/portfolio_projection.py +335 -0
  118. agent_evolve/application/portfolio_recombination.py +2032 -0
  119. agent_evolve/application/post_evolution_reflection.py +834 -0
  120. agent_evolve/application/postcommit_rank_authority.py +245 -0
  121. agent_evolve/application/precommitted_portfolio_racing.py +2762 -0
  122. agent_evolve/application/prequential_archive_opportunity_calibration.py +1154 -0
  123. agent_evolve/application/prequential_residual_exploration.py +343 -0
  124. agent_evolve/application/prequential_score_portfolio.py +954 -0
  125. agent_evolve/application/projections.py +292 -0
  126. agent_evolve/application/protected_action_committee.py +1027 -0
  127. agent_evolve/application/protected_branch_pilot.py +376 -0
  128. agent_evolve/application/protected_current_prefix_forecast_opportunity.py +552 -0
  129. agent_evolve/application/provider_replay.py +910 -0
  130. agent_evolve/application/rank_balanced_causal_pilot.py +1372 -0
  131. agent_evolve/application/recombination_residual_expert.py +403 -0
  132. agent_evolve/application/reflection_workflow.py +571 -0
  133. agent_evolve/application/region_conditional_credit.py +911 -0
  134. agent_evolve/application/residual_campaign_runtime.py +531 -0
  135. agent_evolve/application/residual_headroom_campaign_runtime.py +459 -0
  136. agent_evolve/application/residual_headroom_ledger.py +1544 -0
  137. agent_evolve/application/residual_learning_transaction.py +396 -0
  138. agent_evolve/application/residual_portfolio_evolution.py +1228 -0
  139. agent_evolve/application/residual_reachability.py +749 -0
  140. agent_evolve/application/residual_stage_credit.py +499 -0
  141. agent_evolve/application/same_prefix_paired_audit.py +1580 -0
  142. agent_evolve/application/semantic_coverage_score_portfolio.py +838 -0
  143. agent_evolve/application/sequential_lineage_allocation.py +1017 -0
  144. agent_evolve/application/sequential_market_replay.py +1395 -0
  145. agent_evolve/application/sequential_residual_campaign_runtime.py +305 -0
  146. agent_evolve/application/sequential_residual_portfolio_evolution.py +940 -0
  147. agent_evolve/application/single_score_action_allocation.py +299 -0
  148. agent_evolve/application/source_exposure_allocation.py +906 -0
  149. agent_evolve/application/staged_memory.py +210 -0
  150. agent_evolve/application/stratified_cold_start_allocation.py +732 -0
  151. agent_evolve/application/support_guarded_hurdle_score.py +549 -0
  152. agent_evolve/application/target_conditioned_action_forecast.py +595 -0
  153. agent_evolve/application/target_conditioned_campaign.py +566 -0
  154. agent_evolve/application/treatment_assignment.py +201 -0
  155. agent_evolve/application/trusted_objective_evidence.py +217 -0
  156. agent_evolve/application/two_stage_action_evolution.py +1131 -0
  157. agent_evolve/application/v8lite_allocation_policy.py +1083 -0
  158. agent_evolve/application/v9_candidate_policy.py +1303 -0
  159. agent_evolve/bootstrap.py +108 -0
  160. agent_evolve/campaign_presets.py +517 -0
  161. agent_evolve/campaign_profiles.py +452 -0
  162. agent_evolve/campaign_variation_topology.py +288 -0
  163. agent_evolve/campaign_workload.py +950 -0
  164. agent_evolve/cli.py +797 -0
  165. agent_evolve/contract.py +241 -0
  166. agent_evolve/core/__init__.py +91 -0
  167. agent_evolve/core/action_semantics.py +411 -0
  168. agent_evolve/core/authored.py +105 -0
  169. agent_evolve/core/formatting.py +286 -0
  170. agent_evolve/core/optimization_semantics.py +324 -0
  171. agent_evolve/core/problem.py +167 -0
  172. agent_evolve/core/results.py +323 -0
  173. agent_evolve/core/stats.py +70 -0
  174. agent_evolve/core/telemetry.py +100 -0
  175. agent_evolve/domain/__init__.py +89 -0
  176. agent_evolve/domain/artifact.py +162 -0
  177. agent_evolve/domain/durable_text.py +68 -0
  178. agent_evolve/domain/event.py +1454 -0
  179. agent_evolve/domain/finite_action_set.py +426 -0
  180. agent_evolve/domain/finite_variation.py +526 -0
  181. agent_evolve/domain/generative_emission.py +559 -0
  182. agent_evolve/domain/ids.py +163 -0
  183. agent_evolve/domain/inline_text.py +106 -0
  184. agent_evolve/domain/insight.py +27 -0
  185. agent_evolve/domain/lineage.py +737 -0
  186. agent_evolve/domain/llm_task_queue.py +960 -0
  187. agent_evolve/domain/outcome.py +96 -0
  188. agent_evolve/domain/patch.py +854 -0
  189. agent_evolve/domain/typed_json.py +542 -0
  190. agent_evolve/domain/variation_space.py +158 -0
  191. agent_evolve/driver.py +1014 -0
  192. agent_evolve/harness/__init__.py +29 -0
  193. agent_evolve/harness/base.py +242 -0
  194. agent_evolve/harness/directives.py +163 -0
  195. agent_evolve/harness/generative_seal.py +479 -0
  196. agent_evolve/harness/registry.py +41 -0
  197. agent_evolve/infrastructure/__init__.py +39 -0
  198. agent_evolve/infrastructure/artifacts/__init__.py +6 -0
  199. agent_evolve/infrastructure/artifacts/_verification.py +67 -0
  200. agent_evolve/infrastructure/artifacts/filesystem.py +343 -0
  201. agent_evolve/infrastructure/artifacts/in_memory.py +73 -0
  202. agent_evolve/infrastructure/asyncio_runtime.py +109 -0
  203. agent_evolve/infrastructure/authored_runtime.py +188 -0
  204. agent_evolve/infrastructure/authored_worker.py +171 -0
  205. agent_evolve/infrastructure/clock.py +53 -0
  206. agent_evolve/infrastructure/events/__init__.py +6 -0
  207. agent_evolve/infrastructure/events/_validation.py +89 -0
  208. agent_evolve/infrastructure/events/in_memory.py +56 -0
  209. agent_evolve/infrastructure/events/jsonl.py +193 -0
  210. agent_evolve/infrastructure/exception_provenance.py +215 -0
  211. agent_evolve/infrastructure/ids.py +118 -0
  212. agent_evolve/infrastructure/lineage_codec.py +1836 -0
  213. agent_evolve/infrastructure/outcome_adaptive_phase_journal.py +170 -0
  214. agent_evolve/infrastructure/residual_headroom_journal.py +221 -0
  215. agent_evolve/infrastructure/resource_lease.py +370 -0
  216. agent_evolve/infrastructure/sanitization/__init__.py +8 -0
  217. agent_evolve/infrastructure/sanitization/strict_json.py +484 -0
  218. agent_evolve/infrastructure/sequential_phase_journal.py +170 -0
  219. agent_evolve/infrastructure/stream_liveness.py +383 -0
  220. agent_evolve/infrastructure/subprocess_boundary.py +136 -0
  221. agent_evolve/integrations/__init__.py +1 -0
  222. agent_evolve/integrations/botorch/__init__.py +28 -0
  223. agent_evolve/integrations/botorch/finite_qlognehvi.py +190 -0
  224. agent_evolve/integrations/botorch/finite_qlognehvi_batch.py +155 -0
  225. agent_evolve/integrations/botorch/finite_qlognehvi_batch_identity.py +20 -0
  226. agent_evolve/integrations/botorch/finite_qlognehvi_batch_worker.py +55 -0
  227. agent_evolve/integrations/botorch/finite_qlognehvi_identity.py +22 -0
  228. agent_evolve/integrations/botorch/finite_qlognehvi_worker.py +55 -0
  229. agent_evolve/integrations/botorch/subprocess_qlognehvi.py +261 -0
  230. agent_evolve/integrations/botorch/subprocess_qlognehvi_batch.py +273 -0
  231. agent_evolve/integrations/completion.py +242 -0
  232. agent_evolve/integrations/pydantic_ai/__init__.py +441 -0
  233. agent_evolve/integrations/pydantic_ai/action_forecast.py +1068 -0
  234. agent_evolve/integrations/pydantic_ai/agentic_generator.py +2308 -0
  235. agent_evolve/integrations/pydantic_ai/async_generator.py +1604 -0
  236. agent_evolve/integrations/pydantic_ai/boundary_codec.py +1526 -0
  237. agent_evolve/integrations/pydantic_ai/calibrated_portfolio_campaign.py +756 -0
  238. agent_evolve/integrations/pydantic_ai/calibrated_portfolio_selection.py +7537 -0
  239. agent_evolve/integrations/pydantic_ai/campaign_acquisition.py +609 -0
  240. agent_evolve/integrations/pydantic_ai/execution_binding.py +138 -0
  241. agent_evolve/integrations/pydantic_ai/forecast_geometry_action_committee.py +217 -0
  242. agent_evolve/integrations/pydantic_ai/harness.py +159 -0
  243. agent_evolve/integrations/pydantic_ai/heterogeneous_model_execution.py +306 -0
  244. agent_evolve/integrations/pydantic_ai/hierarchical_residual_adaptive_semantic_view.py +179 -0
  245. agent_evolve/integrations/pydantic_ai/json_schema_dialect.py +108 -0
  246. agent_evolve/integrations/pydantic_ai/materialized_hierarchical_residual_expert.py +952 -0
  247. agent_evolve/integrations/pydantic_ai/materialized_portfolio_judge.py +520 -0
  248. agent_evolve/integrations/pydantic_ai/model_execution_profile.py +659 -0
  249. agent_evolve/integrations/pydantic_ai/outbound_request_manifest.py +1170 -0
  250. agent_evolve/integrations/pydantic_ai/portable_residual_consequence_features.py +575 -0
  251. agent_evolve/integrations/pydantic_ai/portfolio_selection.py +422 -0
  252. agent_evolve/integrations/pydantic_ai/progress_aware_openrouter.py +416 -0
  253. agent_evolve/integrations/pydantic_ai/provider_attempt_join.py +1523 -0
  254. agent_evolve/integrations/pydantic_ai/provider_free_calibrated_runner.py +607 -0
  255. agent_evolve/integrations/pydantic_ai/queued_runner.py +2634 -0
  256. agent_evolve/integrations/pydantic_ai/reconciled_residual_reachability.py +1417 -0
  257. agent_evolve/integrations/pydantic_ai/residual_forecast_geometry.py +445 -0
  258. agent_evolve/integrations/pydantic_ai/residual_reachability.py +674 -0
  259. agent_evolve/integrations/pydantic_ai/residual_semantic_cells.py +239 -0
  260. agent_evolve/integrations/pydantic_ai/sealed_output_replay.py +1068 -0
  261. agent_evolve/integrations/pydantic_ai/semantic_coverage_residual_portfolio.py +770 -0
  262. agent_evolve/integrations/pydantic_ai/semantic_decision_replay.py +383 -0
  263. agent_evolve/integrations/pydantic_ai/support_adaptive_residual_portfolio.py +135 -0
  264. agent_evolve/integrations/pydantic_ai/trusted_residual_prompt_context.py +143 -0
  265. agent_evolve/integrations/pydantic_ai/validated_openrouter_model.py +107 -0
  266. agent_evolve/integrations/pymoo_adapter.py +242 -0
  267. agent_evolve/policies/__init__.py +17 -0
  268. agent_evolve/policies/check.py +469 -0
  269. agent_evolve/policies/emit_scaffold.py +451 -0
  270. agent_evolve/policies/feedback/__init__.py +37 -0
  271. agent_evolve/policies/feedback/held_out_asn.py +1325 -0
  272. agent_evolve/policies/genetic.py +607 -0
  273. agent_evolve/policies/llm_backoff.py +183 -0
  274. agent_evolve/policies/llm_chooser.py +226 -0
  275. agent_evolve/policies/llm_generator.py +1760 -0
  276. agent_evolve/policies/llm_init.py +267 -0
  277. agent_evolve/policies/llm_operator.py +109 -0
  278. agent_evolve/policies/llm_prior.py +194 -0
  279. agent_evolve/policies/llm_surrogate.py +334 -0
  280. agent_evolve/policies/measurement_evidence.py +704 -0
  281. agent_evolve/policies/memory/__init__.py +223 -0
  282. agent_evolve/policies/memory/balanced_subset_blocks.py +707 -0
  283. agent_evolve/policies/memory/compatibility_matching.py +593 -0
  284. agent_evolve/policies/memory/global_falsification.py +1841 -0
  285. agent_evolve/policies/memory/prompt_shape.py +503 -0
  286. agent_evolve/policies/memory/randomized_subset.py +714 -0
  287. agent_evolve/policies/memory/staged_causal.py +1270 -0
  288. agent_evolve/policies/memory/treatment_compliance.py +759 -0
  289. agent_evolve/policies/objective_resolution/__init__.py +17 -0
  290. agent_evolve/policies/objective_resolution/fixed_grid.py +364 -0
  291. agent_evolve/policies/operator_portfolio.py +407 -0
  292. agent_evolve/policies/reguidance.py +1133 -0
  293. agent_evolve/policies/reward/__init__.py +83 -0
  294. agent_evolve/policies/reward/affine_candidate_consequence.py +156 -0
  295. agent_evolve/policies/reward/affine_candidate_consequence_3d.py +159 -0
  296. agent_evolve/policies/reward/affine_hypervolume.py +490 -0
  297. agent_evolve/policies/reward/affine_hypervolume_3d.py +567 -0
  298. agent_evolve/policies/reward/contextual_marginal_utility.py +318 -0
  299. agent_evolve/policies/reward/frozen_archive.py +360 -0
  300. agent_evolve/policies/reward/frozen_wave_archive.py +368 -0
  301. agent_evolve/policies/search_state.py +208 -0
  302. agent_evolve/policies/selection/__init__.py +345 -0
  303. agent_evolve/policies/selection/acquisition_certified_slate.py +684 -0
  304. agent_evolve/policies/selection/affine_frontier_context.py +330 -0
  305. agent_evolve/policies/selection/affine_frontier_target.py +473 -0
  306. agent_evolve/policies/selection/archive_elite.py +1346 -0
  307. agent_evolve/policies/selection/calibrated_portfolio_binding.py +640 -0
  308. agent_evolve/policies/selection/calibrated_slate.py +1394 -0
  309. agent_evolve/policies/selection/calibrated_slate_codec.py +579 -0
  310. agent_evolve/policies/selection/common_candidate_pool.py +685 -0
  311. agent_evolve/policies/selection/diagnostic_sampling.py +319 -0
  312. agent_evolve/policies/selection/disjoint_pairs.py +479 -0
  313. agent_evolve/policies/selection/elite_explorer.py +719 -0
  314. agent_evolve/policies/selection/finite_action.py +187 -0
  315. agent_evolve/policies/selection/finite_option_prompt_projection.py +377 -0
  316. agent_evolve/policies/selection/finite_palette_evidence.py +247 -0
  317. agent_evolve/policies/selection/forecast_calibration.py +922 -0
  318. agent_evolve/policies/selection/frontier_probe_slate.py +814 -0
  319. agent_evolve/policies/selection/frozen_archive_pairs.py +762 -0
  320. agent_evolve/policies/selection/full_support_slate.py +91 -0
  321. agent_evolve/policies/selection/meaningful_direction.py +240 -0
  322. agent_evolve/policies/selection/memory_dose_feasibility.py +259 -0
  323. agent_evolve/policies/selection/model_anchored_slate.py +826 -0
  324. agent_evolve/policies/selection/phenotype_recourse.py +979 -0
  325. agent_evolve/policies/selection/proposal_support.py +368 -0
  326. agent_evolve/policies/selection/random_portfolio.py +254 -0
  327. agent_evolve/policies/selection/regret_bounded_slate.py +1084 -0
  328. agent_evolve/policies/selection/residual_frontier.py +463 -0
  329. agent_evolve/policies/selection/residual_frontier_target.py +605 -0
  330. agent_evolve/policies/selection/structural_posterior_slate.py +1571 -0
  331. agent_evolve/policies/selection/target_conditioned_allocator.py +648 -0
  332. agent_evolve/policies/selection/target_conditioned_features.py +812 -0
  333. agent_evolve/policies/selection/target_conditioned_prequential.py +1527 -0
  334. agent_evolve/policies/selection/task_keyed_palette.py +906 -0
  335. agent_evolve/policies/semantics.py +147 -0
  336. agent_evolve/policies/structure.py +362 -0
  337. agent_evolve/policies/structured_output_budget.py +62 -0
  338. agent_evolve/policies/surrogate.py +696 -0
  339. agent_evolve/policies/variation/__init__.py +1 -0
  340. agent_evolve/policies/variation/compositional_finite_catalog.py +426 -0
  341. agent_evolve/policies/variation/crossover_inheritance.py +575 -0
  342. agent_evolve/policies/variation/disjoint_recombination.py +611 -0
  343. agent_evolve/policies/variation/exact_composition_capacity.py +214 -0
  344. agent_evolve/policies/variation/exact_parent_crossover.py +950 -0
  345. agent_evolve/policies/variation/multiscale_restart_catalog.py +372 -0
  346. agent_evolve/policies/variation/source_union_finite_catalog.py +403 -0
  347. agent_evolve/policies/variation/typed_patch.py +1981 -0
  348. agent_evolve/policies/weighted_prior.py +394 -0
  349. agent_evolve/ports/__init__.py +383 -0
  350. agent_evolve/ports/action_allocation.py +733 -0
  351. agent_evolve/ports/action_allocation_frame.py +1153 -0
  352. agent_evolve/ports/action_allocation_frame_commit.py +294 -0
  353. agent_evolve/ports/action_allocation_frame_commit_v3.py +432 -0
  354. agent_evolve/ports/action_allocation_frame_v3.py +995 -0
  355. agent_evolve/ports/action_forecast.py +1568 -0
  356. agent_evolve/ports/action_metric_projection.py +165 -0
  357. agent_evolve/ports/agentic_generator.py +1561 -0
  358. agent_evolve/ports/archive_context.py +136 -0
  359. agent_evolve/ports/artifact_sanitizer.py +44 -0
  360. agent_evolve/ports/artifact_store.py +225 -0
  361. agent_evolve/ports/clock.py +13 -0
  362. agent_evolve/ports/contextual_search_allocation.py +827 -0
  363. agent_evolve/ports/decision_metric_projection.py +258 -0
  364. agent_evolve/ports/event_store.py +55 -0
  365. agent_evolve/ports/executable_hypothesis.py +557 -0
  366. agent_evolve/ports/finite_acquisition.py +377 -0
  367. agent_evolve/ports/finite_acquisition_batch.py +296 -0
  368. agent_evolve/ports/finite_acquisition_batch_json.py +164 -0
  369. agent_evolve/ports/finite_acquisition_json.py +247 -0
  370. agent_evolve/ports/finite_acquisition_space.py +168 -0
  371. agent_evolve/ports/finite_action_selection.py +348 -0
  372. agent_evolve/ports/finite_action_set.py +256 -0
  373. agent_evolve/ports/frontier_target.py +396 -0
  374. agent_evolve/ports/generation_failure.py +43 -0
  375. agent_evolve/ports/hard_feasibility.py +233 -0
  376. agent_evolve/ports/id_factory.py +34 -0
  377. agent_evolve/ports/llm_task_queue.py +93 -0
  378. agent_evolve/ports/objective_resolution.py +419 -0
  379. agent_evolve/ports/paired_allocation_comparison.py +401 -0
  380. agent_evolve/ports/paired_block_schedule.py +475 -0
  381. agent_evolve/ports/parent_measurement.py +336 -0
  382. agent_evolve/ports/portfolio_memory_dose.py +643 -0
  383. agent_evolve/ports/portfolio_selection.py +3169 -0
  384. agent_evolve/ports/postcommit_rank_authority.py +467 -0
  385. agent_evolve/ports/presented_action_evidence.py +794 -0
  386. agent_evolve/ports/resource_lease.py +162 -0
  387. agent_evolve/ports/structured_generator.py +734 -0
  388. agent_evolve/ports/structured_output_budget.py +120 -0
  389. agent_evolve/ports/subprocess_boundary.py +138 -0
  390. agent_evolve/ports/treatment_assignment.py +466 -0
  391. agent_evolve/ports/variation_catalog.py +76 -0
  392. agent_evolve/ports/variation_source.py +226 -0
  393. agent_evolve/proposal_mode.py +157 -0
  394. agent_evolve/proposers/__init__.py +10 -0
  395. agent_evolve/proposers/random_proposer.py +188 -0
  396. agent_evolve/provider_accounting.py +163 -0
  397. agent_evolve/py.typed +0 -0
  398. agent_evolve/reference_method.py +1570 -0
  399. agent_evolve/session/__init__.py +11 -0
  400. agent_evolve/session/authorship.py +864 -0
  401. agent_evolve/session/evaluate.py +236 -0
  402. agent_evolve/session/fidelity.py +237 -0
  403. agent_evolve/session/genetic_loop.py +742 -0
  404. agent_evolve/session/loop.py +803 -0
  405. agent_evolve/session/screening.py +671 -0
  406. agent_evolve/settings.py +376 -0
  407. agent_evolve/workload_kit.py +368 -0
  408. agent_evolve/workload_prompt.py +398 -0
  409. agentevolve_optimizer-0.5.0.dist-info/METADATA +599 -0
  410. agentevolve_optimizer-0.5.0.dist-info/RECORD +414 -0
  411. agentevolve_optimizer-0.5.0.dist-info/WHEEL +5 -0
  412. agentevolve_optimizer-0.5.0.dist-info/entry_points.txt +2 -0
  413. agentevolve_optimizer-0.5.0.dist-info/licenses/LICENSE +21 -0
  414. agentevolve_optimizer-0.5.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,325 @@
1
+ """Workload-neutral accounting for candidate occurrences and physical evaluations.
2
+
3
+ An optimizer can administer two distinct candidate occurrences that resolve to
4
+ the same benchmark phenotype. The evaluation cache should coalesce that work,
5
+ but experiment reports must never silently relabel the cache hit as a fresh
6
+ physical evaluation. This module validates the complete seed/stage partition
7
+ and publishes both quantities explicitly.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from dataclasses import dataclass
13
+
14
+
15
+ @dataclass(frozen=True, slots=True)
16
+ class CampaignEvaluationAccounting:
17
+ """Exact occurrence/physical-call partition for one completed campaign.
18
+
19
+ ``planned_candidate_occurrences`` is an exact commitment by default. A
20
+ campaign whose evolutionary operators may *typed-abstain* (for example,
21
+ when no legal crossover pair exists) can additionally publish a
22
+ ``minimum_candidate_occurrences``. In that mode the frozen plan is a hard
23
+ capacity ceiling and the minimum is the mandatory work floor. This keeps
24
+ legal operator abstention distinct from both silent budget loss and cache
25
+ reuse: every realized occurrence is still partitioned exactly, while the
26
+ unfilled capacity is reported explicitly.
27
+ """
28
+
29
+ planned_candidate_occurrences: int
30
+ seed_occurrences: int
31
+ seed_unique_evaluations: int
32
+ stage_occurrences: tuple[int, ...]
33
+ stage_unique_evaluations: tuple[int, ...]
34
+ candidate_occurrences: int
35
+ unique_evaluations: int
36
+ minimum_candidate_occurrences: int | None = None
37
+
38
+ def __post_init__(self) -> None:
39
+ for name in (
40
+ "planned_candidate_occurrences",
41
+ "seed_occurrences",
42
+ "seed_unique_evaluations",
43
+ "candidate_occurrences",
44
+ "unique_evaluations",
45
+ ):
46
+ value = getattr(self, name)
47
+ if type(value) is not int or value < 0:
48
+ raise ValueError(f"{name} must be a non-negative exact integer")
49
+ if self.minimum_candidate_occurrences is not None and (
50
+ type(self.minimum_candidate_occurrences) is not int
51
+ or self.minimum_candidate_occurrences < 0
52
+ ):
53
+ raise ValueError(
54
+ "minimum_candidate_occurrences must be a non-negative exact "
55
+ "integer or None"
56
+ )
57
+ for name in ("stage_occurrences", "stage_unique_evaluations"):
58
+ values = getattr(self, name)
59
+ if type(values) is not tuple or any(
60
+ type(value) is not int or value < 0 for value in values
61
+ ):
62
+ raise ValueError(f"{name} must be an exact non-negative tuple")
63
+ if len(self.stage_occurrences) != len(self.stage_unique_evaluations):
64
+ raise ValueError("stage occurrence and evaluation tuples must align")
65
+ if self.seed_unique_evaluations > self.seed_occurrences:
66
+ raise ValueError("seed physical evaluations exceed seed occurrences")
67
+ if any(
68
+ unique > occurrences
69
+ for occurrences, unique in zip(
70
+ self.stage_occurrences,
71
+ self.stage_unique_evaluations,
72
+ strict=True,
73
+ )
74
+ ):
75
+ raise ValueError("stage physical evaluations exceed occurrences")
76
+ if self.candidate_occurrences != (
77
+ self.seed_occurrences + sum(self.stage_occurrences)
78
+ ):
79
+ raise ValueError("candidate occurrences do not equal the stage partition")
80
+ if self.unique_evaluations != (
81
+ self.seed_unique_evaluations + sum(self.stage_unique_evaluations)
82
+ ):
83
+ raise ValueError("unique evaluations do not equal the stage partition")
84
+ if self.minimum_candidate_occurrences is None:
85
+ if self.candidate_occurrences != self.planned_candidate_occurrences:
86
+ raise ValueError("completed occurrences differ from the frozen plan")
87
+ elif not (
88
+ self.minimum_candidate_occurrences
89
+ <= self.candidate_occurrences
90
+ <= self.planned_candidate_occurrences
91
+ ):
92
+ raise ValueError(
93
+ "completed occurrences escape the frozen capacity envelope"
94
+ )
95
+
96
+ @property
97
+ def planned_underfill_occurrences(self) -> int:
98
+ self.__post_init__()
99
+ return self.planned_candidate_occurrences - self.candidate_occurrences
100
+
101
+ @property
102
+ def candidate_capacity_utilization(self) -> float:
103
+ self.__post_init__()
104
+ if self.planned_candidate_occurrences == 0:
105
+ return 1.0
106
+ return self.candidate_occurrences / self.planned_candidate_occurrences
107
+
108
+ @property
109
+ def cache_reuse_occurrences(self) -> int:
110
+ self.__post_init__()
111
+ return self.candidate_occurrences - self.unique_evaluations
112
+
113
+ @property
114
+ def physical_evaluation_utilization(self) -> float:
115
+ self.__post_init__()
116
+ if self.candidate_occurrences == 0:
117
+ return 1.0
118
+ return self.unique_evaluations / self.candidate_occurrences
119
+
120
+ def within_cache_reuse_limit(self, maximum: int) -> bool:
121
+ self.__post_init__()
122
+ if type(maximum) is not int or maximum < 0:
123
+ raise ValueError("maximum must be a non-negative exact integer")
124
+ return self.cache_reuse_occurrences <= maximum
125
+
126
+ def to_record(self) -> dict[str, object]:
127
+ self.__post_init__()
128
+ return {
129
+ "schema_version": 1,
130
+ "planned_candidate_occurrences": self.planned_candidate_occurrences,
131
+ "minimum_candidate_occurrences": self.minimum_candidate_occurrences,
132
+ "candidate_plan_mode": (
133
+ "exact"
134
+ if self.minimum_candidate_occurrences is None
135
+ else "typed_operator_abstention_capacity_envelope"
136
+ ),
137
+ "seed_occurrences": self.seed_occurrences,
138
+ "seed_unique_evaluations": self.seed_unique_evaluations,
139
+ "stage_occurrences": list(self.stage_occurrences),
140
+ "stage_unique_evaluations": list(self.stage_unique_evaluations),
141
+ "candidate_occurrences": self.candidate_occurrences,
142
+ "unique_evaluations": self.unique_evaluations,
143
+ "planned_underfill_occurrences": self.planned_underfill_occurrences,
144
+ "candidate_capacity_utilization_hex": (
145
+ self.candidate_capacity_utilization.hex()
146
+ ),
147
+ "cache_reuse_occurrences": self.cache_reuse_occurrences,
148
+ "physical_evaluation_utilization_hex": (
149
+ self.physical_evaluation_utilization.hex()
150
+ ),
151
+ }
152
+
153
+
154
+ @dataclass(frozen=True, slots=True)
155
+ class CampaignPortfolioEvidenceAccounting:
156
+ """Exact evidence partition for finite-portfolio campaign outcomes.
157
+
158
+ Evaluator-declared candidate infeasibility is a terminal scientific
159
+ outcome, but it cannot publish objective deltas or forecast-calibration
160
+ observations. This accounting keeps those candidates in the proposal and
161
+ feedback action budget without fabricating numeric evidence for them.
162
+ """
163
+
164
+ planned_portfolio_occurrences: int
165
+ portfolio_scored_occurrences: int
166
+ portfolio_candidate_infeasible_occurrences: int
167
+ authenticated_mutation_observations: int
168
+ reflection_source_scored_occurrences: int
169
+ reflection_identifiable_contrasts: int
170
+ forecast_enabled: bool
171
+ planned_selector_receipts: int
172
+ forecast_receipts: int
173
+ forecast_actions: int
174
+ forecast_scored_actions: int
175
+ forecast_candidate_infeasible_actions: int
176
+ objective_metric_count: int
177
+ forecast_observations: int
178
+ reflection_typed_exclusions: int = 0
179
+
180
+ def __post_init__(self) -> None:
181
+ if type(self.forecast_enabled) is not bool:
182
+ raise TypeError("forecast_enabled must be an exact bool")
183
+ for name in (
184
+ "planned_portfolio_occurrences",
185
+ "portfolio_scored_occurrences",
186
+ "portfolio_candidate_infeasible_occurrences",
187
+ "authenticated_mutation_observations",
188
+ "reflection_source_scored_occurrences",
189
+ "reflection_identifiable_contrasts",
190
+ "reflection_typed_exclusions",
191
+ "planned_selector_receipts",
192
+ "forecast_receipts",
193
+ "forecast_actions",
194
+ "forecast_scored_actions",
195
+ "forecast_candidate_infeasible_actions",
196
+ "objective_metric_count",
197
+ "forecast_observations",
198
+ ):
199
+ value = getattr(self, name)
200
+ if type(value) is not int or value < 0:
201
+ raise ValueError(f"{name} must be a non-negative exact integer")
202
+ if self.objective_metric_count == 0:
203
+ raise ValueError("objective_metric_count must be positive")
204
+ if self.reflection_source_scored_occurrences > (
205
+ self.portfolio_scored_occurrences
206
+ ):
207
+ raise ValueError(
208
+ "reflection source scored occurrences exceed portfolio scores"
209
+ )
210
+
211
+ @property
212
+ def exact_portfolio_outcome_partition(self) -> bool:
213
+ self.__post_init__()
214
+ return self.planned_portfolio_occurrences == (
215
+ self.portfolio_scored_occurrences
216
+ + self.portfolio_candidate_infeasible_occurrences
217
+ )
218
+
219
+ @property
220
+ def exact_authenticated_mutation_evidence(self) -> bool:
221
+ self.__post_init__()
222
+ return (
223
+ self.authenticated_mutation_observations
224
+ == self.portfolio_scored_occurrences
225
+ )
226
+
227
+ @property
228
+ def exact_reflection_contrast_accounting(self) -> bool:
229
+ """Compatibility name for the exact typed reflection partition."""
230
+
231
+ return self.exact_reflection_evidence_partition
232
+
233
+ @property
234
+ def exact_reflection_evidence_partition(self) -> bool:
235
+ self.__post_init__()
236
+ return (
237
+ self.reflection_identifiable_contrasts
238
+ + self.reflection_typed_exclusions
239
+ == self.reflection_source_scored_occurrences
240
+ )
241
+
242
+ @property
243
+ def exact_forecast_feedback(self) -> bool:
244
+ self.__post_init__()
245
+ if not self.forecast_enabled:
246
+ return (
247
+ self.planned_selector_receipts == 0
248
+ and self.forecast_receipts == 0
249
+ and self.forecast_actions == 0
250
+ and self.forecast_scored_actions == 0
251
+ and self.forecast_candidate_infeasible_actions == 0
252
+ and self.forecast_observations == 0
253
+ )
254
+ return (
255
+ self.forecast_receipts == self.planned_selector_receipts
256
+ and self.forecast_actions == self.planned_portfolio_occurrences
257
+ and self.forecast_scored_actions == self.portfolio_scored_occurrences
258
+ and self.forecast_candidate_infeasible_actions
259
+ == self.portfolio_candidate_infeasible_occurrences
260
+ and self.forecast_observations
261
+ == self.portfolio_scored_occurrences * self.objective_metric_count
262
+ )
263
+
264
+ @property
265
+ def all_exact(self) -> bool:
266
+ self.__post_init__()
267
+ return (
268
+ self.exact_portfolio_outcome_partition
269
+ and self.exact_authenticated_mutation_evidence
270
+ and self.exact_reflection_evidence_partition
271
+ and self.exact_forecast_feedback
272
+ )
273
+
274
+ def to_record(self) -> dict[str, object]:
275
+ self.__post_init__()
276
+ return {
277
+ "schema_version": 2,
278
+ "planned_portfolio_occurrences": self.planned_portfolio_occurrences,
279
+ "portfolio_scored_occurrences": self.portfolio_scored_occurrences,
280
+ "portfolio_candidate_infeasible_occurrences": (
281
+ self.portfolio_candidate_infeasible_occurrences
282
+ ),
283
+ "authenticated_mutation_observations": (
284
+ self.authenticated_mutation_observations
285
+ ),
286
+ "reflection_source_scored_occurrences": (
287
+ self.reflection_source_scored_occurrences
288
+ ),
289
+ "reflection_identifiable_contrasts": (
290
+ self.reflection_identifiable_contrasts
291
+ ),
292
+ "reflection_typed_exclusions": self.reflection_typed_exclusions,
293
+ "forecast_enabled": self.forecast_enabled,
294
+ "planned_selector_receipts": self.planned_selector_receipts,
295
+ "forecast_receipts": self.forecast_receipts,
296
+ "forecast_actions": self.forecast_actions,
297
+ "forecast_scored_actions": self.forecast_scored_actions,
298
+ "forecast_candidate_infeasible_actions": (
299
+ self.forecast_candidate_infeasible_actions
300
+ ),
301
+ "objective_metric_count": self.objective_metric_count,
302
+ "forecast_observations": self.forecast_observations,
303
+ "gates": {
304
+ "exact_portfolio_outcome_partition": (
305
+ self.exact_portfolio_outcome_partition
306
+ ),
307
+ "exact_authenticated_mutation_evidence": (
308
+ self.exact_authenticated_mutation_evidence
309
+ ),
310
+ "exact_reflection_contrast_accounting": (
311
+ self.exact_reflection_contrast_accounting
312
+ ),
313
+ "exact_reflection_evidence_partition": (
314
+ self.exact_reflection_evidence_partition
315
+ ),
316
+ "exact_forecast_feedback": self.exact_forecast_feedback,
317
+ },
318
+ "all_exact": self.all_exact,
319
+ }
320
+
321
+
322
+ __all__ = [
323
+ "CampaignEvaluationAccounting",
324
+ "CampaignPortfolioEvidenceAccounting",
325
+ ]
@@ -0,0 +1,199 @@
1
+ """Cancellation-safe single-flight caching for expensive async evaluations.
2
+
3
+ The caller owns canonical configuration hashing. This module never serializes or
4
+ normalizes configurations, so cache identity cannot silently lose type or value
5
+ information. Every normally returned value is cacheable, including a domain's
6
+ ordinary invalid-result value; raised exceptions and cancellations are not.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import asyncio
12
+ from collections import OrderedDict
13
+ from dataclasses import dataclass
14
+ from enum import Enum
15
+ from typing import Awaitable, Callable, Generic, Optional, TypeVar
16
+
17
+
18
+ ValueT = TypeVar("ValueT")
19
+
20
+
21
+ class EvaluationCacheEventType(str, Enum):
22
+ """The deliberately small observable lifecycle of the cache."""
23
+
24
+ HIT = "hit"
25
+ MISS = "miss"
26
+ COALESCED = "coalesced"
27
+ EVICTED = "evicted"
28
+
29
+
30
+ @dataclass(frozen=True, slots=True)
31
+ class EvaluationCacheSnapshot:
32
+ """Immutable cache occupancy and cumulative request counters."""
33
+
34
+ capacity: Optional[int]
35
+ cached_entries: int
36
+ in_flight: int
37
+ hits: int
38
+ misses: int
39
+ coalesced: int
40
+ evictions: int
41
+
42
+
43
+ @dataclass(frozen=True, slots=True)
44
+ class EvaluationCacheTraceEvent:
45
+ """One ordered cache lifecycle event with its post-event snapshot."""
46
+
47
+ sequence: int
48
+ event_type: EvaluationCacheEventType
49
+ config_hash: str
50
+ snapshot: EvaluationCacheSnapshot
51
+
52
+
53
+ EvaluationFactory = Callable[[], Awaitable[ValueT]]
54
+ EvaluationCacheTraceCallback = Callable[[EvaluationCacheTraceEvent], None]
55
+
56
+
57
+ class AsyncEvaluationCache(Generic[ValueT]):
58
+ """Coalesce identical evaluations and optionally retain results in an LRU.
59
+
60
+ ``get_or_evaluate`` shields shared work from each individual awaiter. Thus,
61
+ cancelling one awaiter does not cancel an evaluation still needed by another
62
+ awaiter (or prevent its result from being cached). If the evaluation itself
63
+ raises or is cancelled, its in-flight entry is removed and a later request is
64
+ a fresh miss.
65
+
66
+ Trace callbacks are synchronous observation hooks. They run in serialized
67
+ event order, and callback failures are isolated from cache semantics.
68
+ """
69
+
70
+ def __init__(
71
+ self,
72
+ *,
73
+ capacity: Optional[int] = None,
74
+ trace_callback: Optional[EvaluationCacheTraceCallback] = None,
75
+ ) -> None:
76
+ if capacity is not None and (type(capacity) is not int or capacity < 1):
77
+ raise ValueError("capacity must be None or a positive integer")
78
+ if trace_callback is not None and not callable(trace_callback):
79
+ raise TypeError("trace_callback must be callable or None")
80
+
81
+ self._capacity = capacity
82
+ self._trace_callback = trace_callback
83
+ self._values: "OrderedDict[str, ValueT]" = OrderedDict()
84
+ self._in_flight: dict[str, "asyncio.Task[ValueT]"] = {}
85
+ self._lock = asyncio.Lock()
86
+
87
+ self._hits = 0
88
+ self._misses = 0
89
+ self._coalesced = 0
90
+ self._evictions = 0
91
+ self._event_sequence = 0
92
+
93
+ async def get_or_evaluate(
94
+ self,
95
+ config_hash: str,
96
+ evaluate: EvaluationFactory[ValueT],
97
+ ) -> ValueT:
98
+ """Return a cached value or await one shared evaluation for ``config_hash``."""
99
+
100
+ self._validate_config_hash(config_hash)
101
+ if not callable(evaluate):
102
+ raise TypeError("evaluate must be callable")
103
+
104
+ async with self._lock:
105
+ if config_hash in self._values:
106
+ value = self._values.pop(config_hash)
107
+ self._values[config_hash] = value
108
+ self._hits += 1
109
+ self._emit_locked(EvaluationCacheEventType.HIT, config_hash)
110
+ return value
111
+
112
+ task = self._in_flight.get(config_hash)
113
+ if task is None:
114
+ task = asyncio.create_task(
115
+ self._evaluate_and_store(config_hash, evaluate)
116
+ )
117
+ self._in_flight[config_hash] = task
118
+ self._misses += 1
119
+ self._emit_locked(EvaluationCacheEventType.MISS, config_hash)
120
+ else:
121
+ self._coalesced += 1
122
+ self._emit_locked(EvaluationCacheEventType.COALESCED, config_hash)
123
+
124
+ # An awaiter's cancellation must not propagate into shared evaluation work.
125
+ return await asyncio.shield(task)
126
+
127
+ async def snapshot(self) -> EvaluationCacheSnapshot:
128
+ """Return an atomic occupancy and counter snapshot."""
129
+
130
+ async with self._lock:
131
+ return self._snapshot_locked()
132
+
133
+ async def _evaluate_and_store(
134
+ self,
135
+ config_hash: str,
136
+ evaluate: EvaluationFactory[ValueT],
137
+ ) -> ValueT:
138
+ current_task = asyncio.current_task()
139
+ if current_task is None: # pragma: no cover - guaranteed by create_task
140
+ raise RuntimeError("evaluation did not run inside an asyncio task")
141
+
142
+ try:
143
+ value = await evaluate()
144
+ except BaseException:
145
+ async with self._lock:
146
+ if self._in_flight.get(config_hash) is current_task:
147
+ del self._in_flight[config_hash]
148
+ raise
149
+
150
+ async with self._lock:
151
+ if self._in_flight.get(config_hash) is not current_task:
152
+ raise RuntimeError("single-flight evaluation lost its ownership entry")
153
+ del self._in_flight[config_hash]
154
+ self._values[config_hash] = value
155
+ self._values.move_to_end(config_hash)
156
+
157
+ if self._capacity is not None and len(self._values) > self._capacity:
158
+ evicted_hash, _ = self._values.popitem(last=False)
159
+ self._evictions += 1
160
+ self._emit_locked(EvaluationCacheEventType.EVICTED, evicted_hash)
161
+
162
+ return value
163
+
164
+ @staticmethod
165
+ def _validate_config_hash(config_hash: str) -> None:
166
+ if type(config_hash) is not str or not config_hash:
167
+ raise ValueError("config_hash must be a nonempty string")
168
+
169
+ def _snapshot_locked(self) -> EvaluationCacheSnapshot:
170
+ return EvaluationCacheSnapshot(
171
+ capacity=self._capacity,
172
+ cached_entries=len(self._values),
173
+ in_flight=len(self._in_flight),
174
+ hits=self._hits,
175
+ misses=self._misses,
176
+ coalesced=self._coalesced,
177
+ evictions=self._evictions,
178
+ )
179
+
180
+ def _emit_locked(
181
+ self,
182
+ event_type: EvaluationCacheEventType,
183
+ config_hash: str,
184
+ ) -> None:
185
+ callback = self._trace_callback
186
+ if callback is None:
187
+ return
188
+ self._event_sequence += 1
189
+ event = EvaluationCacheTraceEvent(
190
+ sequence=self._event_sequence,
191
+ event_type=event_type,
192
+ config_hash=config_hash,
193
+ snapshot=self._snapshot_locked(),
194
+ )
195
+ try:
196
+ callback(event)
197
+ except Exception:
198
+ # Observation must not turn a valid evaluation into a failed one.
199
+ return