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,744 @@
1
+ """Deterministic bounded-cost allocation over resolved action forecasts."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import hashlib
6
+ import json
7
+ import math
8
+ from dataclasses import dataclass
9
+
10
+ from agent_evolve.ports.action_allocation import (
11
+ ActionAllocationRequest,
12
+ ActionAllocationResult,
13
+ ActionPortfolioDecision,
14
+ AllocatedActionMember,
15
+ ForecastPortfolioUtilityInput,
16
+ ForecastQuantile,
17
+ PortfolioAllocationScore,
18
+ validate_action_portfolio_decision,
19
+ )
20
+ from agent_evolve.ports.action_forecast import ResolvedActionForecast
21
+ from agent_evolve.ports.portfolio_selection import (
22
+ pairwise_disjoint_parent_patch_pairs,
23
+ single_path_parent_patch_option_ids,
24
+ validate_pairwise_disjoint_parent_patch_selection,
25
+ )
26
+
27
+ GREEDY_RISK_DIVERSITY_ALLOCATOR_ID = "greedy_risk_diversity"
28
+ GREEDY_RISK_DIVERSITY_ALLOCATOR_VERSION = 2
29
+ GREEDY_RISK_DIVERSITY_ALLOCATOR_DEFINITION_SHA256 = hashlib.sha256(
30
+ b"agent-evolve:greedy-risk-diversity:v2:"
31
+ b"at-each-step-score-every-eligible-extension-at-p10-p50-p90;"
32
+ b"downside=min(p10,p90);risk=max(0,p50-downside);"
33
+ b"attainable-diversity=min(portfolio-size,eligible-distinct-families);"
34
+ b"diversity=selected-distinct-families/attainable-diversity;"
35
+ b"maximize-marginal-total-with-smallest-option-identity-tie-break"
36
+ ).hexdigest()
37
+ _CONFIGURATION_DOMAIN = b"agent-evolve:greedy-risk-diversity-config:v1\x00"
38
+ FEASIBLE_BEAM_RISK_DIVERSITY_ALLOCATOR_ID = "feasible_beam_risk_diversity"
39
+ FEASIBLE_BEAM_RISK_DIVERSITY_ALLOCATOR_VERSION = 3
40
+ FEASIBLE_BEAM_RISK_DIVERSITY_ALLOCATOR_DEFINITION_SHA256 = hashlib.sha256(
41
+ b"agent-evolve:feasible-beam-risk-diversity:v3:"
42
+ b"canonical-combination-beam;every-retained-prefix-has-a-hard-feasible-"
43
+ b"completion;pairwise-parent-patch-disjointness-and-minimum-distinct-"
44
+ b"families-and-exact-generic-arm-counts-and-minimum-single-path-actions-"
45
+ b"and-minimum-disjoint-parent-patch-pairs-are-trusted-code-constraints;"
46
+ b"score=p50-minus-quantile-downside-"
47
+ b"risk-plus-family-diversity;canonical-content-identity-tie-break"
48
+ ).hexdigest()
49
+ _FEASIBLE_BEAM_RISK_DIVERSITY_ALLOCATOR_V2_DEFINITION_SHA256 = hashlib.sha256(
50
+ b"agent-evolve:feasible-beam-risk-diversity:v2:"
51
+ b"canonical-combination-beam;every-retained-prefix-has-a-hard-feasible-"
52
+ b"completion;pairwise-parent-patch-disjointness-and-minimum-distinct-"
53
+ b"families-and-exact-generic-arm-counts-are-trusted-code-constraints;"
54
+ b"score=p50-minus-quantile-downside-"
55
+ b"risk-plus-family-diversity;canonical-content-identity-tie-break"
56
+ ).hexdigest()
57
+ _FEASIBLE_BEAM_CONFIGURATION_DOMAIN = (
58
+ b"agent-evolve:feasible-beam-risk-diversity-config:v1\x00"
59
+ )
60
+
61
+
62
+ def _configuration_sha256(risk_aversion: float, diversity_weight: float) -> str:
63
+ payload = json.dumps(
64
+ {
65
+ "risk_aversion_hex": risk_aversion.hex(),
66
+ "diversity_weight_hex": diversity_weight.hex(),
67
+ },
68
+ allow_nan=False,
69
+ ensure_ascii=True,
70
+ separators=(",", ":"),
71
+ sort_keys=True,
72
+ ).encode("ascii")
73
+ return hashlib.sha256(_CONFIGURATION_DOMAIN + payload).hexdigest()
74
+
75
+
76
+ @dataclass(frozen=True, slots=True)
77
+ class GreedyRiskAdjustedDiversityAllocator:
78
+ """Greedy marginal set allocator with O(k^2 n) elementary work.
79
+
80
+ The benchmark-owned, identified utility scores the complete forecast set,
81
+ so it can encode hypervolume, feasibility-first orderings, or any other
82
+ domain semantics. This generic policy adds only a quantile downside term
83
+ and a fixed family-diversity reward. It never enumerates k-combinations.
84
+ """
85
+
86
+ risk_aversion: float = 0.5
87
+ diversity_weight: float = 0.0
88
+
89
+ def __post_init__(self) -> None:
90
+ for name in ("risk_aversion", "diversity_weight"):
91
+ value = getattr(self, name)
92
+ if type(value) is not float or not math.isfinite(value):
93
+ raise TypeError(f"{name} must be a finite canonical float")
94
+ if value < 0.0:
95
+ raise ValueError(f"{name} must be non-negative")
96
+
97
+ @property
98
+ def configuration_sha256(self) -> str:
99
+ self.__post_init__()
100
+ return _configuration_sha256(self.risk_aversion, self.diversity_weight)
101
+
102
+ @staticmethod
103
+ def _utility(
104
+ request: ActionAllocationRequest,
105
+ members: tuple[ResolvedActionForecast, ...],
106
+ quantile: ForecastQuantile,
107
+ ) -> float:
108
+ canonical_members = tuple(
109
+ sorted(
110
+ members,
111
+ key=lambda value: (value.option_identity_sha256, value.option_id),
112
+ )
113
+ )
114
+ value = request.utility.utility(
115
+ ForecastPortfolioUtilityInput(
116
+ optimization_semantics=(
117
+ request.forecast_request.optimization_semantics
118
+ ),
119
+ parent_metric_values=(request.forecast_request.parent_metric_values),
120
+ metric_scales=request.forecast_request.metric_scales,
121
+ members=canonical_members,
122
+ quantile=quantile,
123
+ )
124
+ )
125
+ if type(value) is not float or not math.isfinite(value):
126
+ raise TypeError("bound portfolio utility must return a finite float")
127
+ return value
128
+
129
+ def _score(
130
+ self,
131
+ request: ActionAllocationRequest,
132
+ members: tuple[ResolvedActionForecast, ...],
133
+ *,
134
+ attainable_diversity: int,
135
+ ) -> PortfolioAllocationScore:
136
+ if type(attainable_diversity) is not int or attainable_diversity <= 0:
137
+ raise ValueError("attainable_diversity must be a positive exact integer")
138
+ p10 = self._utility(request, members, ForecastQuantile.P10)
139
+ p50 = self._utility(request, members, ForecastQuantile.P50)
140
+ p90 = self._utility(request, members, ForecastQuantile.P90)
141
+ downside = min(p10, p90)
142
+ risk_penalty = self.risk_aversion * max(0.0, p50 - downside)
143
+ diversity_reward = self.diversity_weight * (
144
+ len({member.family for member in members}) / attainable_diversity
145
+ )
146
+ return PortfolioAllocationScore(
147
+ p10_utility=p10,
148
+ p50_utility=p50,
149
+ p90_utility=p90,
150
+ downside_utility=downside,
151
+ risk_penalty=risk_penalty,
152
+ diversity_reward=diversity_reward,
153
+ total_utility=p50 - risk_penalty + diversity_reward,
154
+ )
155
+
156
+ def allocate(self, request: ActionAllocationRequest) -> ActionAllocationResult:
157
+ if type(request) is not ActionAllocationRequest:
158
+ raise TypeError("request must be an exact ActionAllocationRequest")
159
+ request.__post_init__()
160
+ self.__post_init__()
161
+ if request.exact_arm_count_constraints:
162
+ raise ValueError(
163
+ "GreedyRiskAdjustedDiversityAllocator does not implement exact "
164
+ "arm-count constraints; use FeasibleBeamActionAllocator"
165
+ )
166
+ if (
167
+ request.minimum_single_path_interventions
168
+ or request.minimum_disjoint_parent_patch_pairs
169
+ ):
170
+ raise ValueError(
171
+ "GreedyRiskAdjustedDiversityAllocator does not implement minimum "
172
+ "structural floors; use FeasibleBeamActionAllocator"
173
+ )
174
+ by_id = {value.option_id: value for value in request.forecasts.forecasts}
175
+ attainable_diversity = min(
176
+ request.portfolio_size,
177
+ len({by_id[option_id].family for option_id in request.eligible_option_ids}),
178
+ )
179
+ remaining = sorted(
180
+ (by_id[option_id] for option_id in request.eligible_option_ids),
181
+ key=lambda value: (value.option_identity_sha256, value.option_id),
182
+ )
183
+ required = tuple(
184
+ value
185
+ for value in remaining
186
+ if value.option_id in set(request.required_option_ids)
187
+ )
188
+ selected: list[ResolvedActionForecast] = []
189
+ members: list[AllocatedActionMember] = []
190
+ previous_total = 0.0
191
+ candidate_evaluations = 0
192
+ for rank in range(1, request.portfolio_size + 1):
193
+ if rank <= len(required):
194
+ best_forecast = required[rank - 1]
195
+ best_score = self._score(
196
+ request,
197
+ (*selected, best_forecast),
198
+ attainable_diversity=attainable_diversity,
199
+ )
200
+ best_marginal = best_score.total_utility - previous_total
201
+ candidate_evaluations += 1
202
+ else:
203
+ best_forecast = None
204
+ best_score = None
205
+ best_marginal = None
206
+ for candidate in remaining:
207
+ portfolio = (*selected, candidate)
208
+ score = self._score(
209
+ request,
210
+ portfolio,
211
+ attainable_diversity=attainable_diversity,
212
+ )
213
+ marginal = score.total_utility - previous_total
214
+ candidate_evaluations += 1
215
+ # ``remaining`` is canonical; strict comparison retains the
216
+ # smallest option identity on an exact numerical tie.
217
+ if best_marginal is None or marginal > best_marginal:
218
+ best_forecast = candidate
219
+ best_score = score
220
+ best_marginal = marginal
221
+ assert best_forecast is not None
222
+ assert best_score is not None
223
+ assert best_marginal is not None
224
+ selected.append(best_forecast)
225
+ remaining.remove(best_forecast)
226
+ members.append(
227
+ AllocatedActionMember(
228
+ rank=rank,
229
+ option_id=best_forecast.option_id,
230
+ option_identity_sha256=best_forecast.option_identity_sha256,
231
+ child_configuration_sha256=(
232
+ best_forecast.child_configuration_sha256
233
+ ),
234
+ family=best_forecast.family,
235
+ greedy_step_score=best_score,
236
+ marginal_total_utility=best_marginal,
237
+ )
238
+ )
239
+ previous_total = best_score.total_utility
240
+ decision = ActionPortfolioDecision(
241
+ allocation_request_sha256=request.request_sha256,
242
+ forecast_receipt_sha256=request.forecasts.receipt_sha256,
243
+ finite_contract_identity_sha256=(
244
+ request.forecast_request.finite_variation_contract.identity_sha256
245
+ ),
246
+ eligible_options_sha256=request.eligible_options_sha256,
247
+ members=tuple(members),
248
+ final_score=members[-1].greedy_step_score,
249
+ candidate_evaluations=candidate_evaluations,
250
+ utility_policy_id=request.utility.policy_id,
251
+ utility_policy_version=request.utility.policy_version,
252
+ utility_definition_sha256=request.utility.definition_sha256,
253
+ allocator_policy_id=GREEDY_RISK_DIVERSITY_ALLOCATOR_ID,
254
+ allocator_policy_version=GREEDY_RISK_DIVERSITY_ALLOCATOR_VERSION,
255
+ allocator_definition_sha256=(
256
+ GREEDY_RISK_DIVERSITY_ALLOCATOR_DEFINITION_SHA256
257
+ ),
258
+ allocator_configuration_sha256=self.configuration_sha256,
259
+ )
260
+ validate_action_portfolio_decision(request, decision)
261
+ return ActionAllocationResult(decision=decision)
262
+
263
+
264
+ @dataclass(frozen=True, slots=True)
265
+ class FeasibleBeamRiskAdjustedDiversityAllocator:
266
+ """Bounded beam allocation whose every published set is hard feasible.
267
+
268
+ The LLM forecasts consequences only. Trusted application code owns set
269
+ construction and cannot publish a portfolio that violates the generic
270
+ structural constraints sealed into :class:`ActionAllocationRequest`.
271
+ """
272
+
273
+ risk_aversion: float = 0.5
274
+ diversity_weight: float = 0.05
275
+ beam_width: int = 256
276
+
277
+ def __post_init__(self) -> None:
278
+ for name in ("risk_aversion", "diversity_weight"):
279
+ value = getattr(self, name)
280
+ if type(value) is not float or not math.isfinite(value):
281
+ raise TypeError(f"{name} must be a finite canonical float")
282
+ if value < 0.0:
283
+ raise ValueError(f"{name} must be non-negative")
284
+ if type(self.beam_width) is not int or self.beam_width <= 0:
285
+ raise ValueError("beam_width must be a positive exact integer")
286
+
287
+ @property
288
+ def configuration_sha256(self) -> str:
289
+ self.__post_init__()
290
+ payload = json.dumps(
291
+ {
292
+ "risk_aversion_hex": self.risk_aversion.hex(),
293
+ "diversity_weight_hex": self.diversity_weight.hex(),
294
+ "beam_width": self.beam_width,
295
+ },
296
+ allow_nan=False,
297
+ ensure_ascii=True,
298
+ separators=(",", ":"),
299
+ sort_keys=True,
300
+ ).encode("ascii")
301
+ return hashlib.sha256(_FEASIBLE_BEAM_CONFIGURATION_DOMAIN + payload).hexdigest()
302
+
303
+ @staticmethod
304
+ def _allowed_pairs(
305
+ request: ActionAllocationRequest,
306
+ ) -> frozenset[frozenset[str]] | None:
307
+ if not request.require_pairwise_disjoint_parent_patches:
308
+ return None
309
+ return frozenset(
310
+ frozenset(value)
311
+ for value in pairwise_disjoint_parent_patch_pairs(
312
+ request.forecast_request.finite_variation_contract,
313
+ request.eligible_option_ids,
314
+ )
315
+ )
316
+
317
+ @staticmethod
318
+ def _disjoint_pairs(
319
+ request: ActionAllocationRequest,
320
+ ) -> frozenset[frozenset[str]]:
321
+ if (
322
+ not request.require_pairwise_disjoint_parent_patches
323
+ and request.minimum_disjoint_parent_patch_pairs == 0
324
+ ):
325
+ return frozenset()
326
+ return frozenset(
327
+ frozenset(value)
328
+ for value in pairwise_disjoint_parent_patch_pairs(
329
+ request.forecast_request.finite_variation_contract,
330
+ request.eligible_option_ids,
331
+ )
332
+ )
333
+
334
+ @staticmethod
335
+ def _pairs_allowed(
336
+ indices: tuple[int, ...],
337
+ options: tuple[ResolvedActionForecast, ...],
338
+ allowed_pairs: frozenset[frozenset[str]] | None,
339
+ ) -> bool:
340
+ return allowed_pairs is None or all(
341
+ frozenset((options[left].option_id, options[right].option_id))
342
+ in allowed_pairs
343
+ for position, left in enumerate(indices)
344
+ for right in indices[position + 1 :]
345
+ )
346
+
347
+ @staticmethod
348
+ def _arm_constraints_have_completion(
349
+ *,
350
+ selected: tuple[int, ...],
351
+ remaining: tuple[int, ...],
352
+ needed: int,
353
+ arm_constraints: tuple[tuple[dict[str, int], tuple[str, ...]], ...],
354
+ ) -> bool:
355
+ """Cheap exact marginal-count bound for every generic arm axis."""
356
+
357
+ for target, arm_by_index in arm_constraints:
358
+ selected_counts = {arm_id: 0 for arm_id in target}
359
+ for index in selected:
360
+ selected_counts[arm_by_index[index]] += 1
361
+ deficits: dict[str, int] = {}
362
+ for arm_id, count in target.items():
363
+ deficit = count - selected_counts[arm_id]
364
+ if deficit < 0:
365
+ return False
366
+ deficits[arm_id] = deficit
367
+ if sum(deficits.values()) != needed:
368
+ return False
369
+ available_counts = {arm_id: 0 for arm_id in target}
370
+ for index in remaining:
371
+ available_counts[arm_by_index[index]] += 1
372
+ if any(
373
+ available_counts[arm_id] < deficit
374
+ for arm_id, deficit in deficits.items()
375
+ ):
376
+ return False
377
+ return True
378
+
379
+ @staticmethod
380
+ def _structural_floors_have_completion(
381
+ *,
382
+ selected: tuple[int, ...],
383
+ remaining: tuple[int, ...],
384
+ needed: int,
385
+ options: tuple[ResolvedActionForecast, ...],
386
+ single_path_indices: frozenset[int],
387
+ minimum_single_path_interventions: int,
388
+ disjoint_pairs: frozenset[frozenset[str]],
389
+ minimum_disjoint_parent_patch_pairs: int,
390
+ ) -> bool:
391
+ """Return a safe upper-bound test, exact when no slots remain."""
392
+
393
+ selected_single = sum(value in single_path_indices for value in selected)
394
+ if selected_single + min(
395
+ needed,
396
+ sum(value in single_path_indices for value in remaining),
397
+ ) < minimum_single_path_interventions:
398
+ return False
399
+
400
+ def pair(left: int, right: int) -> frozenset[str]:
401
+ return frozenset(
402
+ (options[left].option_id, options[right].option_id)
403
+ )
404
+
405
+ observed_pairs = sum(
406
+ pair(left, right) in disjoint_pairs
407
+ for position, left in enumerate(selected)
408
+ for right in selected[position + 1 :]
409
+ )
410
+ if needed == 0:
411
+ return observed_pairs >= minimum_disjoint_parent_patch_pairs
412
+ optimistic_pairs = (
413
+ observed_pairs
414
+ + len(selected) * needed
415
+ + needed * (needed - 1) // 2
416
+ )
417
+ return optimistic_pairs >= minimum_disjoint_parent_patch_pairs
418
+
419
+ @classmethod
420
+ def _has_completion(
421
+ cls,
422
+ *,
423
+ partial: tuple[int, ...],
424
+ options: tuple[ResolvedActionForecast, ...],
425
+ portfolio_size: int,
426
+ min_distinct_families: int | None,
427
+ allowed_pairs: frozenset[frozenset[str]] | None,
428
+ disjoint_pairs: frozenset[frozenset[str]],
429
+ single_path_indices: frozenset[int],
430
+ minimum_single_path_interventions: int,
431
+ minimum_disjoint_parent_patch_pairs: int,
432
+ required_indices: frozenset[int],
433
+ arm_constraints: tuple[tuple[dict[str, int], tuple[str, ...]], ...],
434
+ ) -> bool:
435
+ """Exact bounded-depth feasibility oracle for one canonical prefix."""
436
+
437
+ slots = portfolio_size - len(partial)
438
+ if slots < 0 or not cls._pairs_allowed(partial, options, allowed_pairs):
439
+ return False
440
+ missing_required = required_indices.difference(partial)
441
+ if len(missing_required) > slots:
442
+ return False
443
+ families = {options[index].family for index in partial}
444
+ all_remaining = tuple(range(partial[-1] + 1, len(options))) if partial else (
445
+ tuple(range(len(options)))
446
+ )
447
+ if not cls._structural_floors_have_completion(
448
+ selected=partial,
449
+ remaining=all_remaining,
450
+ needed=slots,
451
+ options=options,
452
+ single_path_indices=single_path_indices,
453
+ minimum_single_path_interventions=minimum_single_path_interventions,
454
+ disjoint_pairs=disjoint_pairs,
455
+ minimum_disjoint_parent_patch_pairs=(
456
+ minimum_disjoint_parent_patch_pairs
457
+ ),
458
+ ):
459
+ return False
460
+ if slots == 0:
461
+ return (
462
+ not missing_required
463
+ and (
464
+ min_distinct_families is None
465
+ or len(families) >= min_distinct_families
466
+ )
467
+ and cls._arm_constraints_have_completion(
468
+ selected=partial,
469
+ remaining=(),
470
+ needed=0,
471
+ arm_constraints=arm_constraints,
472
+ )
473
+ )
474
+ start = partial[-1] + 1 if partial else 0
475
+ if any(index < start for index in missing_required):
476
+ return False
477
+ compatible = tuple(
478
+ index
479
+ for index in range(start, len(options))
480
+ if all(
481
+ allowed_pairs is None
482
+ or frozenset((options[index].option_id, options[chosen].option_id))
483
+ in allowed_pairs
484
+ for chosen in partial
485
+ )
486
+ )
487
+ if len(compatible) < slots:
488
+ return False
489
+ if not missing_required.issubset(compatible):
490
+ return False
491
+ if not cls._arm_constraints_have_completion(
492
+ selected=partial,
493
+ remaining=compatible,
494
+ needed=slots,
495
+ arm_constraints=arm_constraints,
496
+ ):
497
+ return False
498
+ if (
499
+ min_distinct_families is not None
500
+ and len(families | {options[index].family for index in compatible})
501
+ < min_distinct_families
502
+ ):
503
+ return False
504
+
505
+ def visit(
506
+ chosen: tuple[int, ...],
507
+ remaining: tuple[int, ...],
508
+ ) -> bool:
509
+ needed = slots - len(chosen)
510
+ still_required = missing_required.difference(chosen)
511
+ if len(still_required) > needed or not still_required.issubset(remaining):
512
+ return False
513
+ if not cls._arm_constraints_have_completion(
514
+ selected=(*partial, *chosen),
515
+ remaining=remaining,
516
+ needed=needed,
517
+ arm_constraints=arm_constraints,
518
+ ):
519
+ return False
520
+ if not cls._structural_floors_have_completion(
521
+ selected=(*partial, *chosen),
522
+ remaining=remaining,
523
+ needed=needed,
524
+ options=options,
525
+ single_path_indices=single_path_indices,
526
+ minimum_single_path_interventions=(
527
+ minimum_single_path_interventions
528
+ ),
529
+ disjoint_pairs=disjoint_pairs,
530
+ minimum_disjoint_parent_patch_pairs=(
531
+ minimum_disjoint_parent_patch_pairs
532
+ ),
533
+ ):
534
+ return False
535
+ chosen_families = families | {options[index].family for index in chosen}
536
+ if needed == 0:
537
+ return not still_required and (
538
+ min_distinct_families is None
539
+ or len(chosen_families) >= min_distinct_families
540
+ )
541
+ if len(remaining) < needed:
542
+ return False
543
+ if (
544
+ min_distinct_families is not None
545
+ and len(
546
+ chosen_families | {options[index].family for index in remaining}
547
+ )
548
+ < min_distinct_families
549
+ ):
550
+ return False
551
+ for position, candidate in enumerate(remaining):
552
+ if all(
553
+ allowed_pairs is None
554
+ or frozenset(
555
+ (options[candidate].option_id, options[prior].option_id)
556
+ )
557
+ in allowed_pairs
558
+ for prior in chosen
559
+ ) and visit(
560
+ (*chosen, candidate),
561
+ remaining[position + 1 :],
562
+ ):
563
+ return True
564
+ return False
565
+
566
+ return visit((), compatible)
567
+
568
+ def allocate(self, request: ActionAllocationRequest) -> ActionAllocationResult:
569
+ if type(request) is not ActionAllocationRequest:
570
+ raise TypeError("request must be an exact ActionAllocationRequest")
571
+ request.__post_init__()
572
+ self.__post_init__()
573
+ by_id = {value.option_id: value for value in request.forecasts.forecasts}
574
+ options = tuple(
575
+ sorted(
576
+ (by_id[value] for value in request.eligible_option_ids),
577
+ key=lambda item: (item.option_identity_sha256, item.option_id),
578
+ )
579
+ )
580
+ allowed_pairs = self._allowed_pairs(request)
581
+ disjoint_pairs = self._disjoint_pairs(request)
582
+ single_path_option_ids = set(
583
+ single_path_parent_patch_option_ids(
584
+ request.forecast_request.finite_variation_contract,
585
+ request.eligible_option_ids,
586
+ )
587
+ )
588
+ single_path_indices = frozenset(
589
+ index
590
+ for index, option in enumerate(options)
591
+ if option.option_id in single_path_option_ids
592
+ )
593
+ required_option_ids = set(request.required_option_ids)
594
+ required_indices = frozenset(
595
+ index
596
+ for index, option in enumerate(options)
597
+ if option.option_id in required_option_ids
598
+ )
599
+ arm_constraints = tuple(
600
+ (
601
+ dict(constraint.target_counts),
602
+ tuple(
603
+ dict(constraint.option_arm_ids)[option.option_id]
604
+ for option in options
605
+ ),
606
+ )
607
+ for constraint in request.exact_arm_count_constraints
608
+ )
609
+ scorer = GreedyRiskAdjustedDiversityAllocator(
610
+ risk_aversion=self.risk_aversion,
611
+ diversity_weight=self.diversity_weight,
612
+ )
613
+ attainable_diversity = min(
614
+ request.portfolio_size,
615
+ len({value.family for value in options}),
616
+ )
617
+ beam: list[tuple[tuple[int, ...], PortfolioAllocationScore]] = []
618
+ candidate_evaluations = 0
619
+ for depth in range(1, request.portfolio_size + 1):
620
+ candidates: list[tuple[tuple[int, ...], PortfolioAllocationScore]] = []
621
+ prefixes = (((), None),) if depth == 1 else tuple(beam)
622
+ for prefix, _ in prefixes:
623
+ start = prefix[-1] + 1 if prefix else 0
624
+ for index in range(start, len(options)):
625
+ extension = (*prefix, index)
626
+ if not self._has_completion(
627
+ partial=extension,
628
+ options=options,
629
+ portfolio_size=request.portfolio_size,
630
+ min_distinct_families=request.min_distinct_families,
631
+ allowed_pairs=allowed_pairs,
632
+ disjoint_pairs=disjoint_pairs,
633
+ single_path_indices=single_path_indices,
634
+ minimum_single_path_interventions=(
635
+ request.minimum_single_path_interventions
636
+ ),
637
+ minimum_disjoint_parent_patch_pairs=(
638
+ request.minimum_disjoint_parent_patch_pairs
639
+ ),
640
+ required_indices=required_indices,
641
+ arm_constraints=arm_constraints,
642
+ ):
643
+ continue
644
+ score = scorer._score(
645
+ request,
646
+ tuple(options[value] for value in extension),
647
+ attainable_diversity=attainable_diversity,
648
+ )
649
+ candidate_evaluations += 1
650
+ candidates.append((extension, score))
651
+ if not candidates:
652
+ raise RuntimeError(
653
+ "feasibility oracle admitted no target-allocation prefix"
654
+ )
655
+ candidates.sort(
656
+ key=lambda value: (
657
+ -value[1].total_utility,
658
+ tuple(options[index].option_identity_sha256 for index in value[0]),
659
+ )
660
+ )
661
+ beam = candidates[: self.beam_width]
662
+
663
+ selected_indices, final_score = beam[0]
664
+ selected = tuple(options[index] for index in selected_indices)
665
+ if (
666
+ request.min_distinct_families is not None
667
+ and len({value.family for value in selected})
668
+ < request.min_distinct_families
669
+ ):
670
+ raise RuntimeError("beam allocator violated minimum family coverage")
671
+ if request.require_pairwise_disjoint_parent_patches:
672
+ validate_pairwise_disjoint_parent_patch_selection(
673
+ request.forecast_request.finite_variation_contract,
674
+ tuple(value.option_id for value in selected),
675
+ )
676
+ if not required_option_ids.issubset(value.option_id for value in selected):
677
+ raise RuntimeError("beam allocator omitted a required option")
678
+ prefix_scores = tuple(
679
+ scorer._score(
680
+ request,
681
+ selected[:index],
682
+ attainable_diversity=attainable_diversity,
683
+ )
684
+ for index in range(1, len(selected) + 1)
685
+ )
686
+ members = tuple(
687
+ AllocatedActionMember(
688
+ rank=index,
689
+ option_id=value.option_id,
690
+ option_identity_sha256=value.option_identity_sha256,
691
+ child_configuration_sha256=value.child_configuration_sha256,
692
+ family=value.family,
693
+ greedy_step_score=prefix_scores[index - 1],
694
+ marginal_total_utility=(
695
+ prefix_scores[index - 1].total_utility
696
+ - (0.0 if index == 1 else prefix_scores[index - 2].total_utility)
697
+ ),
698
+ )
699
+ for index, value in enumerate(selected, start=1)
700
+ )
701
+ if final_score != prefix_scores[-1]:
702
+ raise RuntimeError("beam final score differs from its selected prefix")
703
+ decision = ActionPortfolioDecision(
704
+ allocation_request_sha256=request.request_sha256,
705
+ forecast_receipt_sha256=request.forecasts.receipt_sha256,
706
+ finite_contract_identity_sha256=(
707
+ request.forecast_request.finite_variation_contract.identity_sha256
708
+ ),
709
+ eligible_options_sha256=request.eligible_options_sha256,
710
+ members=members,
711
+ final_score=final_score,
712
+ candidate_evaluations=candidate_evaluations,
713
+ utility_policy_id=request.utility.policy_id,
714
+ utility_policy_version=request.utility.policy_version,
715
+ utility_definition_sha256=request.utility.definition_sha256,
716
+ allocator_policy_id=FEASIBLE_BEAM_RISK_DIVERSITY_ALLOCATOR_ID,
717
+ allocator_policy_version=(
718
+ FEASIBLE_BEAM_RISK_DIVERSITY_ALLOCATOR_VERSION
719
+ if request.minimum_single_path_interventions
720
+ or request.minimum_disjoint_parent_patch_pairs
721
+ else 2
722
+ ),
723
+ allocator_definition_sha256=(
724
+ FEASIBLE_BEAM_RISK_DIVERSITY_ALLOCATOR_DEFINITION_SHA256
725
+ if request.minimum_single_path_interventions
726
+ or request.minimum_disjoint_parent_patch_pairs
727
+ else _FEASIBLE_BEAM_RISK_DIVERSITY_ALLOCATOR_V2_DEFINITION_SHA256
728
+ ),
729
+ allocator_configuration_sha256=self.configuration_sha256,
730
+ )
731
+ validate_action_portfolio_decision(request, decision)
732
+ return ActionAllocationResult(decision=decision)
733
+
734
+
735
+ __all__ = [
736
+ "FEASIBLE_BEAM_RISK_DIVERSITY_ALLOCATOR_DEFINITION_SHA256",
737
+ "FEASIBLE_BEAM_RISK_DIVERSITY_ALLOCATOR_ID",
738
+ "FEASIBLE_BEAM_RISK_DIVERSITY_ALLOCATOR_VERSION",
739
+ "GREEDY_RISK_DIVERSITY_ALLOCATOR_DEFINITION_SHA256",
740
+ "GREEDY_RISK_DIVERSITY_ALLOCATOR_ID",
741
+ "GREEDY_RISK_DIVERSITY_ALLOCATOR_VERSION",
742
+ "FeasibleBeamRiskAdjustedDiversityAllocator",
743
+ "GreedyRiskAdjustedDiversityAllocator",
744
+ ]