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,147 @@
1
+ """What the model is told things MEAN. One renderer, shared by every prompt.
2
+
3
+ The program's own trace-first findings (I7) showed information-channel
4
+ defects masquerading as capability failures: an objective traded against but
5
+ never rendered, grids shown as bare number lists. The structural channel
6
+ (names, domains, directions) was always faithful; the SEMANTIC channel --
7
+ what a parameter is, what an objective measures, what the evaluator does --
8
+ had no carrier at all. This module is that carrier.
9
+
10
+ Sources, all harvested rather than invented, all optional, all already
11
+ writable by a problem author today:
12
+
13
+ - ``search_space_description()`` (existing optional method), else the
14
+ problem class docstring, else the candidate model's docstring -- the
15
+ domain in prose;
16
+ - ``evaluate``'s docstring -- what an evaluation actually runs;
17
+ - ``ObjectiveSpec.description`` -- what each objective measures;
18
+ - pydantic ``Field(description=...)`` -- what each parameter means, read
19
+ from the model's own JSON schema (these were previously harvested by
20
+ nothing and silently dropped).
21
+
22
+ Every helper degrades to the structural rendering when a source is absent:
23
+ a missing description never breaks a prompt, it just starves it.
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ from typing import Any, Iterable, List, Optional, Sequence
29
+
30
+ from agent_evolve.policies.genetic import Locus, locus_domain
31
+
32
+ __all__ = ["objective_lines", "parameter_lines", "domain_card"]
33
+
34
+ _MAX_VALUES_SHOWN = 12
35
+ _MAX_PROSE = 900
36
+
37
+
38
+ def _first_paragraph(text: Optional[str]) -> str:
39
+ if not text:
40
+ return ""
41
+ paragraph = text.strip().split("\n\n")[0]
42
+ collapsed = " ".join(paragraph.split())
43
+ return collapsed[:_MAX_PROSE]
44
+
45
+
46
+ def objective_lines(specs: Sequence[Any]) -> List[str]:
47
+ """One line per objective: name, direction, and its meaning when given."""
48
+
49
+ out = []
50
+ for spec in specs:
51
+ line = f"{spec.name} ({spec.goal})"
52
+ description = _first_paragraph(getattr(spec, "description", ""))
53
+ if description:
54
+ line += f" -- {description}"
55
+ out.append(line)
56
+ return out
57
+
58
+
59
+ def _rendered_domain(domain: tuple) -> str:
60
+ if len(domain) <= _MAX_VALUES_SHOWN:
61
+ return f"one of {list(domain)}"
62
+ head = list(domain[:_MAX_VALUES_SHOWN - 2])
63
+ return (f"one of {head + ['...'] + [domain[-1]]} "
64
+ f"({len(domain)} levels)")
65
+
66
+
67
+ def parameter_lines(
68
+ candidate_model: Any,
69
+ *,
70
+ fields: Optional[Iterable[str]] = None,
71
+ ) -> List[str]:
72
+ """One line per field: domain, shape, and the Field description when given."""
73
+
74
+ try:
75
+ schema = candidate_model.model_json_schema()
76
+ except Exception:
77
+ return []
78
+ properties = schema.get("properties", {}) or {}
79
+ wanted = list(fields) if fields is not None else list(properties)
80
+ out = []
81
+ for name in wanted:
82
+ node = properties.get(name, {})
83
+ if not isinstance(node, dict):
84
+ node = {}
85
+ domain = locus_domain(candidate_model, Locus(name))
86
+ is_sequence = node.get("type") == "array"
87
+ if domain:
88
+ shape = ("sequence field, each position "
89
+ if is_sequence else "") + _rendered_domain(domain)
90
+ elif is_sequence:
91
+ shape = "sequence field"
92
+ else:
93
+ shape = "unconstrained by the schema"
94
+ line = f"{name}: {shape}"
95
+ description = _first_paragraph(node.get("description"))
96
+ if description:
97
+ line += f" -- {description}"
98
+ out.append(line)
99
+ return out
100
+
101
+
102
+ def domain_card(problem: Any) -> str:
103
+ """Everything the model should be told about WHAT it is optimizing.
104
+
105
+ Renders only the sections that have content; a problem that documents
106
+ nothing yields the structural card (objectives + parameters), which is
107
+ exactly what prompts carried before this module existed.
108
+ """
109
+
110
+ blocks: List[str] = []
111
+
112
+ prose = ""
113
+ describe = getattr(problem, "search_space_description", None)
114
+ if callable(describe):
115
+ try:
116
+ prose = _first_paragraph(describe()) or ""
117
+ # search_space_description is often multi-paragraph and entirely
118
+ # load-bearing; keep it whole rather than first-paragraph only.
119
+ prose = str(describe()).strip()[:_MAX_PROSE]
120
+ except Exception:
121
+ prose = ""
122
+ if not prose:
123
+ prose = _first_paragraph(getattr(type(problem), "__doc__", ""))
124
+ if not prose:
125
+ candidate_model = getattr(problem, "candidate_model", None)
126
+ prose = _first_paragraph(getattr(candidate_model, "__doc__", ""))
127
+ if prose:
128
+ blocks.append(f"PROBLEM:\n{prose}")
129
+
130
+ evaluate = getattr(problem, "evaluate", None)
131
+ evaluation = _first_paragraph(getattr(evaluate, "__doc__", ""))
132
+ if evaluation:
133
+ blocks.append(f"EVALUATION:\n{evaluation}")
134
+
135
+ objectives = list(getattr(problem, "objectives", ()) or ())
136
+ if objectives:
137
+ blocks.append("OBJECTIVES:\n" + "\n".join(
138
+ f" {line}" for line in objective_lines(objectives)))
139
+
140
+ candidate_model = getattr(problem, "candidate_model", None)
141
+ if candidate_model is not None:
142
+ lines = parameter_lines(candidate_model)
143
+ if lines:
144
+ blocks.append("PARAMETERS:\n" + "\n".join(
145
+ f" {line}" for line in lines))
146
+
147
+ return "\n\n".join(blocks)
@@ -0,0 +1,362 @@
1
+ """Learning the landscape's structure, and spending the knowledge.
2
+
3
+ The loop this package shipped with could only ever ask "which parents, which
4
+ cut points" -- decisions *inside* a fixed schema-uniform sampling distribution.
5
+ That caps what any guidance can buy: on an exhaustively-censused venue the best
6
+ achievable operator choice reached 7 of 34 frontier configurations, while
7
+ simply sampling from the right quarter of the space reaches 11. The ceiling was
8
+ the distribution, not the chooser.
9
+
10
+ This module adds the phase that was missing. A *screen* spends a few
11
+ evaluations on a design that can actually identify structure; *attribution*
12
+ turns those evaluations into per-level evidence; a *prior proposer* -- a plain
13
+ rule or a model -- turns the evidence into a :class:`DomainRestriction` that
14
+ narrows where every later operator samples.
15
+
16
+ Two things are load-bearing and neither is about language models.
17
+
18
+ A screen must be CROSSED, not merely balanced. Balancing each locus marginally
19
+ leaves its contrast confounded with every other locus, and a confounded table
20
+ says "nothing is excludable" no matter who reads it. Measured: on the same
21
+ venue, a marginally-balanced 8-run screen identified one of two deciding loci,
22
+ while a crossed 4-run screen identified both. Fewer evaluations, better design.
23
+
24
+ A prior governs SAMPLING, not the caller's input. Seeds are data the caller
25
+ supplied and survive a restriction untouched; only drawn candidates -- fresh
26
+ initialization and mutation -- are confined. A prior that could delete a seed
27
+ would be overruling the one thing the problem stated outright.
28
+
29
+ And the prior must be falsifiable. A restriction that removes the good region
30
+ is unrecoverable by construction, so callers get :func:`restriction_is_paying`
31
+ to check the bet against the screen's own best and unwind it.
32
+ """
33
+
34
+ from __future__ import annotations
35
+
36
+ import itertools
37
+ import random
38
+ from dataclasses import dataclass, field
39
+ from typing import Any, Callable, Iterable, Mapping, Sequence
40
+
41
+ from agent_evolve.core.problem import ObjectiveSpec
42
+ from agent_evolve.policies.genetic import (
43
+ DomainRestriction,
44
+ Locus,
45
+ loci_of,
46
+ locus_domain,
47
+ read_locus,
48
+ write_locus,
49
+ )
50
+
51
+ __all__ = [
52
+ "LevelSummary",
53
+ "Attribution",
54
+ "crossed_screen",
55
+ "attribute",
56
+ "render_attribution",
57
+ "statistical_prior",
58
+ "restriction_is_paying",
59
+ "PriorProposer",
60
+ ]
61
+
62
+
63
+ @dataclass(frozen=True)
64
+ class LevelSummary:
65
+ """What the screen measured for one value of one locus."""
66
+
67
+ locus: str
68
+ value: Any
69
+ n: int
70
+ objective_means: Mapping[str, float]
71
+ nondominated: int
72
+
73
+
74
+ @dataclass(frozen=True)
75
+ class Attribution:
76
+ """Per-level evidence from the screened candidates."""
77
+
78
+ levels: tuple[LevelSummary, ...] = ()
79
+ n_evaluated: int = 0
80
+ blocking: tuple[str, ...] = ()
81
+
82
+ def for_locus(self, name: str) -> tuple[LevelSummary, ...]:
83
+ return tuple(s for s in self.levels if s.locus == name)
84
+
85
+
86
+ #: Turns measured evidence into a prior over where to sample. A rule, a model,
87
+ #: anything: the loop only requires that it narrows declared domains.
88
+ PriorProposer = Callable[[Attribution, Any], DomainRestriction]
89
+
90
+
91
+ def crossed_screen(
92
+ template: Mapping[str, Any],
93
+ candidate_model: Any,
94
+ *,
95
+ size: int,
96
+ blocking: Sequence[str] | None = None,
97
+ rng: random.Random | None = None,
98
+ pool_by_field: bool = False,
99
+ ) -> list[dict[str, Any]]:
100
+ """A screening design of *size* candidates that can identify structure.
101
+
102
+ The blocking loci are fully crossed -- every combination of their values
103
+ appears equally often -- so their contrasts are not confounded with each
104
+ other. Every remaining locus walks the same ladder of values inside each
105
+ block, so its levels are matched across blocks rather than correlated with
106
+ them.
107
+
108
+ Chosen automatically when *blocking* is omitted: the loci with the smallest
109
+ declared domains, taking as many as fit in *size*. Small domains are where
110
+ structural switches live, and they are the cheapest to cross.
111
+
112
+ ``pool_by_field`` changes the design for SEQUENCE fields, whose positions
113
+ share one vocabulary: crossing them is out of reach (k^n cells) and
114
+ per-position ladders leave per-level n tiny, but if positions are roughly
115
+ exchangeable the value effect can be measured POOLED across positions.
116
+ The design is then per-value: first one PURE candidate per value (every
117
+ position set to it -- the cleanest pooled contrast), then SPIKED
118
+ candidates (the value at every other position, the rest cycling through
119
+ the vocabulary) until *size* is spent. Whether positions really are
120
+ exchangeable is the bet this design makes; the caller's prior gets
121
+ unwound by the standard test when they are not.
122
+ """
123
+
124
+ r = rng or random.Random()
125
+ if pool_by_field:
126
+ return _pooled_screen(template, candidate_model, size=size)
127
+ all_loci = [lc for lc in loci_of(template) if locus_domain(candidate_model, lc)]
128
+ if not all_loci or size <= 0:
129
+ return []
130
+ domains = {lc: locus_domain(candidate_model, lc) for lc in all_loci}
131
+
132
+ if blocking is None:
133
+ block: list[Locus] = []
134
+ cells = 1
135
+ for lc in sorted(all_loci, key=lambda l: len(domains[l])):
136
+ if cells * len(domains[lc]) > size:
137
+ break
138
+ block.append(lc)
139
+ cells *= len(domains[lc])
140
+ else:
141
+ wanted = tuple(blocking)
142
+ block = [lc for lc in all_loci if str(lc) in wanted or lc.field in wanted]
143
+ cells = 1
144
+ for lc in block:
145
+ cells *= len(domains[lc])
146
+ if not block: # nothing crossable: fall back to a walk
147
+ block, cells = [], 1
148
+
149
+ rest = [lc for lc in all_loci if lc not in block]
150
+ per_cell = max(1, size // max(1, cells))
151
+ # One shared ladder of settings for the non-blocking loci, reused verbatim
152
+ # in every block: that is what keeps their levels matched across blocks.
153
+ ladder = [
154
+ {lc: domains[lc][t % len(domains[lc])] for lc in rest}
155
+ for t in range(per_cell)
156
+ ]
157
+
158
+ out: list[dict[str, Any]] = []
159
+ combos = list(itertools.product(*[domains[lc] for lc in block])) or [()]
160
+ for combo in combos:
161
+ for setting in ladder:
162
+ cfg = dict(template)
163
+ for lc, value in zip(block, combo):
164
+ cfg = write_locus(cfg, lc, value)
165
+ for lc, value in setting.items():
166
+ cfg = write_locus(cfg, lc, value)
167
+ out.append(cfg)
168
+ # Never exceed the budget the caller agreed to spend; if the crossing did
169
+ # not fill it, top up with schema-uniform draws rather than repeating.
170
+ while len(out) < size:
171
+ cfg = dict(template)
172
+ for lc in all_loci:
173
+ cfg = write_locus(cfg, lc, r.choice(domains[lc]))
174
+ out.append(cfg)
175
+ return out[:size]
176
+
177
+
178
+ def _pooled_screen(
179
+ template: Mapping[str, Any],
180
+ candidate_model: Any,
181
+ *,
182
+ size: int,
183
+ ) -> list[dict[str, Any]]:
184
+ """Pure and spiked candidates over each sequence field's shared vocabulary."""
185
+
186
+ sequence_loci = [lc for lc in loci_of(template) if lc.index is not None
187
+ and locus_domain(candidate_model, lc)]
188
+ if not sequence_loci or size <= 0:
189
+ return []
190
+ fields: dict[str, list[Locus]] = {}
191
+ for lc in sequence_loci:
192
+ fields.setdefault(lc.field, []).append(lc)
193
+
194
+ out: list[dict[str, Any]] = []
195
+ spike_round = 0
196
+ while len(out) < size:
197
+ for name, loci in fields.items():
198
+ domain = locus_domain(candidate_model, loci[0])
199
+ for value_index, value in enumerate(domain):
200
+ if len(out) >= size:
201
+ break
202
+ cfg = dict(template)
203
+ for position, lc in enumerate(loci):
204
+ if spike_round == 0:
205
+ cfg = write_locus(cfg, lc, value) # pure
206
+ elif position % 2 == 0:
207
+ cfg = write_locus(cfg, lc, value) # spiked
208
+ else:
209
+ fill = domain[(value_index + position + spike_round)
210
+ % len(domain)]
211
+ cfg = write_locus(cfg, lc, fill)
212
+ out.append(cfg)
213
+ spike_round += 1
214
+ return out[:size]
215
+
216
+
217
+ def _nondominated(points: Sequence[Sequence[float]]) -> list[bool]:
218
+ out = []
219
+ for a, pa in enumerate(points):
220
+ out.append(not any(
221
+ b != a
222
+ and all(x <= y for x, y in zip(pb, pa))
223
+ and any(x < y for x, y in zip(pb, pa))
224
+ for b, pb in enumerate(points)))
225
+ return out
226
+
227
+
228
+ def attribute(
229
+ evaluated: Sequence[tuple[Mapping[str, Any], Mapping[str, float]]],
230
+ specs: Sequence[ObjectiveSpec],
231
+ candidate_model: Any,
232
+ *,
233
+ blocking: Sequence[str] = (),
234
+ pool_by_field: bool = False,
235
+ ) -> Attribution:
236
+ """Summarise screened candidates per locus value.
237
+
238
+ Non-domination is computed WITHIN the screen, in minimisation-normalised
239
+ coordinates, because that is the only comparison an optimizer can make from
240
+ its own evaluations -- no global frontier is available at run time.
241
+
242
+ ``pool_by_field`` treats a sequence field's positions as exchangeable:
243
+ every (candidate, position) pair becomes one observation of the value it
244
+ holds, keyed by the bare field name. Per-position n on a short screen is
245
+ unusably small; pooled n is positions times larger. The exchangeability
246
+ bet itself is the caller's, and the standard unwind test is its check.
247
+ """
248
+
249
+ if not evaluated:
250
+ return Attribution((), 0, tuple(blocking))
251
+ names = [s.name for s in specs]
252
+ sign = {s.name: (-1.0 if s.goal == "max" else 1.0) for s in specs}
253
+ pts = [[sign[n] * float(obj[n]) for n in names] for _, obj in evaluated]
254
+ nd = _nondominated(pts)
255
+
256
+ scalar_loci: list[Locus] = []
257
+ pooled_fields: dict[str, list[Locus]] = {}
258
+ for lc in loci_of(evaluated[0][0]):
259
+ if not locus_domain(candidate_model, lc):
260
+ continue
261
+ if pool_by_field and lc.index is not None:
262
+ pooled_fields.setdefault(lc.field, []).append(lc)
263
+ else:
264
+ scalar_loci.append(lc)
265
+
266
+ levels: list[LevelSummary] = []
267
+ for lc in scalar_loci:
268
+ seen: dict[Any, list[int]] = {}
269
+ for i, (cfg, _obj) in enumerate(evaluated):
270
+ seen.setdefault(read_locus(cfg, lc), []).append(i)
271
+ for value, idxs in seen.items():
272
+ levels.append(LevelSummary(
273
+ locus=str(lc), value=value, n=len(idxs),
274
+ objective_means={
275
+ n: sum(float(evaluated[i][1][n]) for i in idxs) / len(idxs)
276
+ for n in names},
277
+ nondominated=sum(1 for i in idxs if nd[i]),
278
+ ))
279
+ for field_name, loci in pooled_fields.items():
280
+ seen = {}
281
+ for i, (cfg, _obj) in enumerate(evaluated):
282
+ for lc in loci:
283
+ seen.setdefault(read_locus(cfg, lc), []).append(i)
284
+ for value, idxs in seen.items():
285
+ levels.append(LevelSummary(
286
+ locus=field_name, value=value, n=len(idxs),
287
+ objective_means={
288
+ n: sum(float(evaluated[i][1][n]) for i in idxs) / len(idxs)
289
+ for n in names},
290
+ nondominated=sum(1 for i in idxs if nd[i]),
291
+ ))
292
+ return Attribution(tuple(levels), len(evaluated), tuple(blocking))
293
+
294
+
295
+ def render_attribution(attr: Attribution) -> str:
296
+ """The screen as text: what a reader (rule or model) gets to reason over."""
297
+
298
+ if not attr.levels:
299
+ return "(no screened evaluations)"
300
+ lines: list[str] = []
301
+ for name in dict.fromkeys(s.locus for s in attr.levels):
302
+ lines.append(f" {name}:")
303
+ for s in attr.for_locus(name):
304
+ means = " ".join(f"{k}={v:.6g}" for k, v in s.objective_means.items())
305
+ lines.append(f" {s.value}: n={s.n} {means} "
306
+ f"non-dominated {s.nondominated}/{s.n}")
307
+ return "\n".join(lines)
308
+
309
+
310
+ def statistical_prior(
311
+ attr: Attribution,
312
+ candidate_model: Any = None,
313
+ *,
314
+ min_levels: int = 2,
315
+ ) -> DomainRestriction:
316
+ """The credential-free prior: keep the levels the screen did not refute.
317
+
318
+ For each locus, a level is kept when its within-screen non-domination rate
319
+ ties the best rate for that locus. A locus whose levels all tie is left
320
+ alone -- which is the honest reading of a screen that separated nothing,
321
+ and the reason this rule abstains far more often than it commits.
322
+
323
+ This ships as the default so the phase is useful with no model and no
324
+ credential, and so any model-proposed prior has a rule to beat.
325
+ """
326
+
327
+ allowed: dict[str, list[Any]] = {}
328
+ for name in dict.fromkeys(s.locus for s in attr.levels):
329
+ summaries = attr.for_locus(name)
330
+ if len(summaries) < min_levels:
331
+ continue
332
+ rates = {s.value: (s.nondominated / s.n if s.n else 0.0) for s in summaries}
333
+ best = max(rates.values())
334
+ if best <= 0.0:
335
+ continue
336
+ keep = [v for v, rate in rates.items() if rate >= best]
337
+ if 0 < len(keep) < len(summaries):
338
+ allowed[name.split("[")[0]] = keep
339
+ return DomainRestriction(allowed)
340
+
341
+
342
+ def restriction_is_paying(
343
+ restriction: DomainRestriction,
344
+ screen_best: float,
345
+ current_best: float,
346
+ *,
347
+ goal: str = "min",
348
+ ) -> bool:
349
+ """Is the bet still worth holding?
350
+
351
+ A restriction that removed the good region cannot recover on its own, so a
352
+ caller that installed one must be able to notice and unwind it. The test is
353
+ deliberately weak -- the restricted search only has to have matched what the
354
+ screen already found -- because unwinding a prior that is merely unlucky
355
+ costs less than holding one that is wrong.
356
+ """
357
+
358
+ if not restriction.allowed:
359
+ return True
360
+ if goal == "max":
361
+ return current_best >= screen_best
362
+ return current_best <= screen_best
@@ -0,0 +1,62 @@
1
+ """Immutable structured-output budget policies."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from typing import ClassVar
7
+
8
+ from agent_evolve.ports.structured_generator import MAX_OUTPUT_TOKENS
9
+ from agent_evolve.ports.structured_output_budget import (
10
+ StructuredOutputRequestKind,
11
+ validate_structured_output_operation,
12
+ )
13
+
14
+
15
+ def _validate_budget(value: int, name: str) -> None:
16
+ if type(value) is not int or not 1 <= value <= MAX_OUTPUT_TOKENS:
17
+ raise ValueError(f"{name} must lie in [1, {MAX_OUTPUT_TOKENS}]")
18
+
19
+
20
+ @dataclass(frozen=True, slots=True)
21
+ class FixedStructuredOutputBudgetPolicy:
22
+ """Assign immutable output limits by agentic request kind.
23
+
24
+ The operation argument is deliberately retained by the policy port. This
25
+ fixed implementation ignores its value after validation; experiments that
26
+ need per-operator allocation can inject another implementation without
27
+ changing the engine or a benchmark adapter.
28
+ """
29
+
30
+ proposal_max_output_tokens: int = 2_048
31
+ reflection_max_output_tokens: int = 2_048
32
+
33
+ policy_id: ClassVar[str] = "fixed_by_agentic_request_kind"
34
+ policy_version: ClassVar[int] = 1
35
+
36
+ def __post_init__(self) -> None:
37
+ _validate_budget(
38
+ self.proposal_max_output_tokens,
39
+ "proposal_max_output_tokens",
40
+ )
41
+ _validate_budget(
42
+ self.reflection_max_output_tokens,
43
+ "reflection_max_output_tokens",
44
+ )
45
+
46
+ def max_output_tokens(
47
+ self,
48
+ *,
49
+ request_kind: StructuredOutputRequestKind,
50
+ operation: str,
51
+ ) -> int:
52
+ if type(request_kind) is not StructuredOutputRequestKind:
53
+ raise TypeError(
54
+ "request_kind must be an exact StructuredOutputRequestKind"
55
+ )
56
+ validate_structured_output_operation(operation)
57
+ if request_kind is StructuredOutputRequestKind.PROPOSAL:
58
+ return self.proposal_max_output_tokens
59
+ return self.reflection_max_output_tokens
60
+
61
+
62
+ __all__ = ["FixedStructuredOutputBudgetPolicy"]