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,286 @@
1
+ """Pure formatting/parsing helpers shared by the loop and the LLM prompts.
2
+
3
+ Everything here is a pure function of its arguments (no I/O, no globals).
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ import json
9
+ import re
10
+ from dataclasses import dataclass
11
+ from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple
12
+
13
+ from pydantic import BaseModel
14
+
15
+ from agent_evolve.core.problem import ObjectiveSpec
16
+ from agent_evolve.core.results import Candidate, objective_value
17
+
18
+
19
+ @dataclass
20
+ class CandidateResult:
21
+ """Intermediate evaluation record (richer than the public :class:`Candidate`)."""
22
+
23
+ configuration: Dict[str, Any]
24
+ objectives: Dict[str, float]
25
+ is_valid: bool
26
+ error_message: Optional[str] = None
27
+ failure_phase: Optional[str] = None
28
+ #: True iff ``Problem.evaluate`` was actually invoked for this candidate.
29
+ evaluation_attempted: bool = False
30
+ insight: str = ""
31
+ #: Original element from the LLM ``candidates`` list (before/while parsing).
32
+ raw_llm_element: Optional[Any] = None
33
+
34
+
35
+ # ------------------------------------------------------------------
36
+ # Prettifiers (consumed by LLM prompts)
37
+ # ------------------------------------------------------------------
38
+
39
+ def prettify_configuration(config: Dict[str, Any], indent: int = 2) -> str:
40
+ return json.dumps(config, indent=indent, sort_keys=True, default=str)
41
+
42
+
43
+ def dump_raw_llm_element(obj: Any, *, max_len: int = 12_000) -> str:
44
+ """Serialize a raw LLM list element for logs and failure prompts."""
45
+ if obj is None:
46
+ return "(none)"
47
+ try:
48
+ s = json.dumps(obj, indent=2, default=str, ensure_ascii=False)
49
+ except (TypeError, ValueError):
50
+ s = repr(obj)
51
+ if len(s) > max_len:
52
+ return s[:max_len] + f"\n... [truncated, {len(s)} chars total]"
53
+ return s
54
+
55
+
56
+ def prettify_objectives(objectives: Sequence[ObjectiveSpec]) -> str:
57
+ lines = ["OBJECTIVES:", "=" * 60]
58
+ for spec in objectives:
59
+ desc = "higher is better" if spec.goal == "max" else "lower is better"
60
+ lines.append(f" - {spec.name}: {desc}")
61
+ return "\n".join(lines)
62
+
63
+
64
+ def prettify_results(
65
+ results: Sequence[CandidateResult],
66
+ objectives: Sequence[ObjectiveSpec],
67
+ render: Optional[Callable[[Dict[str, Any]], str]] = None,
68
+ ) -> str:
69
+ """Format candidate results for LLM prompts.
70
+
71
+ ``render`` optionally produces a compact one-line view of each configuration
72
+ (e.g. a problem-specific summary); when absent, pretty JSON is used.
73
+ """
74
+ lines: List[str] = []
75
+ for i, r in enumerate(results, 1):
76
+ lines.append(f"--- Candidate {i} ---")
77
+ config_str = render(r.configuration) if render is not None else prettify_configuration(r.configuration)
78
+ lines.append(f"Configuration: {config_str}")
79
+ if getattr(r, "raw_llm_element", None) is not None:
80
+ lines.append(
81
+ "Raw LLM element (exact item from the model's candidates list): "
82
+ + dump_raw_llm_element(r.raw_llm_element)
83
+ )
84
+ if r.is_valid:
85
+ parts = []
86
+ for spec in objectives:
87
+ val = objective_value(r.objectives, spec.name)
88
+ arrow = "\u2191" if spec.goal == "max" else "\u2193"
89
+ parts.append(f"{spec.name}={val:.4f}{arrow}")
90
+ lines.append(f"Objectives: {', '.join(parts)}")
91
+ else:
92
+ lines.append("Status: INVALID")
93
+ if r.failure_phase:
94
+ lines.append(f"Failure Phase: {r.failure_phase}")
95
+ if r.error_message:
96
+ lines.append(f"Error: {r.error_message}")
97
+ if r.insight:
98
+ lines.append(f"Insight: {r.insight}")
99
+ lines.append("")
100
+ return "\n".join(lines)
101
+
102
+
103
+ # ------------------------------------------------------------------
104
+ # Search-space description for LLM context
105
+ # ------------------------------------------------------------------
106
+
107
+ def format_search_space_description(
108
+ objectives: Sequence[ObjectiveSpec],
109
+ *,
110
+ config_schema: Optional[Dict[str, Any]] = None,
111
+ example_config: Optional[Dict[str, Any]] = None,
112
+ constraints: Optional[str] = None,
113
+ problem_description: Optional[str] = None,
114
+ ) -> str:
115
+ lines: List[str] = []
116
+ lines.append("=" * 70)
117
+ lines.append("MULTI-OBJECTIVE OPTIMIZATION PROBLEM")
118
+ lines.append("=" * 70)
119
+ lines.append("")
120
+ lines.append("OBJECTIVES:")
121
+ for spec in objectives:
122
+ desc = "MAXIMIZE (higher is better)" if spec.goal == "max" else "MINIMIZE (lower is better)"
123
+ lines.append(f" \u2022 {spec.name}: {desc}")
124
+ lines.append("")
125
+
126
+ if problem_description:
127
+ lines.append("PROBLEM DESCRIPTION:")
128
+ lines.append(problem_description)
129
+ lines.append("")
130
+
131
+ if config_schema:
132
+ lines.append("CONFIGURATION SCHEMA:")
133
+ lines.append(prettify_configuration(config_schema))
134
+ lines.append("")
135
+
136
+ if example_config:
137
+ lines.append("EXAMPLE CONFIGURATION:")
138
+ lines.append(prettify_configuration(example_config))
139
+ lines.append("")
140
+
141
+ if constraints:
142
+ lines.append("CONSTRAINTS:")
143
+ lines.append(constraints)
144
+ lines.append("")
145
+
146
+ return "\n".join(lines)
147
+
148
+
149
+ # ------------------------------------------------------------------
150
+ # Conversions between CandidateResult and the public Candidate
151
+ # ------------------------------------------------------------------
152
+
153
+ def result_to_candidate(
154
+ result: CandidateResult,
155
+ metadata: Optional[Dict[str, Any]] = None,
156
+ ) -> Candidate[Dict[str, Any]]:
157
+ return Candidate(
158
+ configuration=result.configuration,
159
+ objectives=result.objectives,
160
+ metadata=metadata or {"is_pareto": False},
161
+ )
162
+
163
+
164
+ def candidate_to_result(candidate: Candidate[Dict[str, Any]]) -> CandidateResult:
165
+ return CandidateResult(
166
+ configuration=candidate.configuration,
167
+ objectives=candidate.objectives,
168
+ is_valid=True,
169
+ evaluation_attempted=True,
170
+ )
171
+
172
+
173
+ # ------------------------------------------------------------------
174
+ # Parse LLM candidate output
175
+ # ------------------------------------------------------------------
176
+
177
+ def parse_llm_json_array(s: str) -> List[Any]:
178
+ """Parse a JSON array (or single object) from an LLM ``str`` field.
179
+
180
+ The single-JSON-string output contract avoids the ``[{}, {}, ...]`` degradation
181
+ that ``list[dict]`` structured outputs are prone to. Strips optional markdown fences.
182
+ """
183
+ s = (s or "").strip()
184
+ if not s:
185
+ raise ValueError("Empty candidates JSON string")
186
+ if s.startswith("```"):
187
+ s = re.sub(r"^```(?:json)?\s*", "", s, flags=re.IGNORECASE)
188
+ s = re.sub(r"\s*```\s*$", "", s)
189
+ data = json.loads(s)
190
+ if isinstance(data, dict):
191
+ inner = data.get("candidates")
192
+ if isinstance(inner, list):
193
+ return inner
194
+ return [data]
195
+ if isinstance(data, list):
196
+ return data
197
+ raise ValueError(f"Candidates JSON must be an array or object, got {type(data).__name__}")
198
+
199
+
200
+ def parse_candidates(
201
+ candidates: Any,
202
+ expected_count: int,
203
+ log_fn: Callable[[str], None] = lambda m: None,
204
+ ) -> Tuple[List[Dict[str, Any]], List[Any]]:
205
+ """Normalise LLM output into configuration dicts.
206
+
207
+ Returns ``(parsed_configs, raw_elements)`` with one raw element per input list
208
+ item (same order), so failures can show what the model actually returned even
209
+ when the parsed dict is ``{}`` or wrong.
210
+ """
211
+ if isinstance(candidates, str):
212
+ try:
213
+ candidates = parse_llm_json_array(candidates)
214
+ except Exception as exc:
215
+ log_fn(f"Warning: could not parse candidates as JSON array string: {exc}")
216
+ return [], []
217
+
218
+ if isinstance(candidates, dict):
219
+ inner = candidates.get("candidates")
220
+ if isinstance(inner, list):
221
+ candidates = inner
222
+ else:
223
+ log_fn(
224
+ f"Warning: LLM returned a dict without a 'candidates' list "
225
+ f"(keys: {list(candidates.keys())})."
226
+ )
227
+ return [], []
228
+
229
+ if not isinstance(candidates, list):
230
+ log_fn(f"Warning: LLM returned non-list candidates: {type(candidates)}")
231
+ return [], []
232
+
233
+ parsed: List[Dict[str, Any]] = []
234
+ raw_elements: List[Any] = []
235
+ for c in candidates:
236
+ raw_elements.append(c)
237
+ if isinstance(c, BaseModel):
238
+ parsed.append(c.model_dump())
239
+ elif isinstance(c, dict):
240
+ parsed.append(c)
241
+ elif isinstance(c, str):
242
+ try:
243
+ parsed.append(json.loads(c))
244
+ except Exception:
245
+ log_fn(f"Warning: Could not parse candidate string: {c[:100]}")
246
+ parsed.append({})
247
+ else:
248
+ log_fn(
249
+ f"Warning: candidate element has unexpected type {type(c).__name__}"
250
+ )
251
+ parsed.append({})
252
+
253
+ if len(parsed) != expected_count:
254
+ log_fn(f"Warning: Expected {expected_count} candidates, got {len(parsed)}")
255
+ return parsed, raw_elements
256
+
257
+
258
+ def result_to_json(result: Any) -> str:
259
+ """One machine-readable document for a ``SearchResult``.
260
+
261
+ Blocks that were never populated serialize as ``null`` rather than being
262
+ omitted, so a reader can tell "measured zero" (a present block with zero
263
+ counts) from "nobody looked" (null). Values outside JSON's vocabulary fall
264
+ back to ``str`` -- a printable document beats a crash on an exotic locus
265
+ type, and the exact values live in the caller's hands anyway.
266
+ """
267
+ import dataclasses
268
+
269
+ def _candidate(c: Any) -> Dict[str, Any]:
270
+ return {"configuration": c.configuration, "objectives": c.objectives}
271
+
272
+ payload = {
273
+ "best": _candidate(result.best),
274
+ "pareto_front": [_candidate(c) for c in result.pareto_front],
275
+ "evaluations": result.evaluations,
276
+ "history": result.history,
277
+ "provider_usage": (
278
+ dataclasses.asdict(result.provider_usage)
279
+ if result.provider_usage is not None else None
280
+ ),
281
+ "telemetry": (
282
+ dataclasses.asdict(result.telemetry)
283
+ if result.telemetry is not None else None
284
+ ),
285
+ }
286
+ return json.dumps(payload, sort_keys=True, default=str)
@@ -0,0 +1,324 @@
1
+ """Immutable, prompt-safe semantics for optimization metrics and ordering.
2
+
3
+ The application core must not guess what a benchmark metric means. This
4
+ module gives benchmark adapters a small inverted API for publishing that
5
+ meaning once, binding it to the objective and outcome-relation identities,
6
+ and rendering the same canonical record into every agentic prompt.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import hashlib
12
+ import json
13
+ import math
14
+ import re
15
+ from dataclasses import dataclass, field
16
+ from enum import Enum
17
+ from typing import Sequence
18
+
19
+ from agent_evolve.core.problem import ObjectiveSpec, validate_objective_specs
20
+ from agent_evolve.domain.patch import require_sha256
21
+
22
+
23
+ _TOKEN = re.compile(r"^[a-z][a-z0-9_.-]{0,95}$")
24
+ _SEMANTICS_HASH_DOMAIN = b"agent-evolve:optimization-semantics:v1\x00"
25
+
26
+
27
+ class MetricRole(str, Enum):
28
+ """Closed role vocabulary for values exposed to an optimizer."""
29
+
30
+ OBJECTIVE = "objective"
31
+ VIOLATION = "violation"
32
+ CONSTRAINT = "constraint"
33
+ DIAGNOSTIC = "diagnostic"
34
+
35
+
36
+ class MetricSense(str, Enum):
37
+ """How better values of a metric are interpreted."""
38
+
39
+ MINIMIZE = "minimize"
40
+ MAXIMIZE = "maximize"
41
+ TARGET = "target"
42
+ SATISFY_BOUNDS = "satisfy_bounds"
43
+ INFORMATIONAL = "informational"
44
+
45
+
46
+ class OutcomeOrderingKind(str, Enum):
47
+ """High-level structure of the benchmark's outcome comparison."""
48
+
49
+ LEXICOGRAPHIC = "lexicographic"
50
+ PARETO = "pareto"
51
+ SCALAR = "scalar"
52
+ CUSTOM = "custom"
53
+
54
+
55
+ def _nonempty(value: object, name: str) -> str:
56
+ if type(value) is not str or not value.strip():
57
+ raise ValueError(f"{name} must be a non-empty exact string")
58
+ return value
59
+
60
+
61
+ def _token(value: object, name: str) -> str:
62
+ text = _nonempty(value, name)
63
+ if _TOKEN.fullmatch(text) is None:
64
+ raise ValueError(f"{name} must use the closed token grammar")
65
+ return text
66
+
67
+
68
+ def _finite_optional(value: object, name: str) -> float | None:
69
+ if value is None:
70
+ return None
71
+ if isinstance(value, bool) or not isinstance(value, (int, float)):
72
+ raise TypeError(f"{name} must be a finite number or None")
73
+ number = float(value)
74
+ if not math.isfinite(number):
75
+ raise ValueError(f"{name} must be finite")
76
+ return number
77
+
78
+
79
+ @dataclass(frozen=True, slots=True)
80
+ class MetricSemantics:
81
+ """Exact human-facing meaning of one objective/evidence metric."""
82
+
83
+ metric_id: str
84
+ name: str
85
+ role: MetricRole
86
+ sense: MetricSense
87
+ definition: str
88
+ aggregation: str
89
+ witness_interpretation: str
90
+ reference_target: float | None = None
91
+ bounds: tuple[float | None, float | None] | None = None
92
+ tolerance: float | None = None
93
+
94
+ def __post_init__(self) -> None:
95
+ _token(self.name, "metric name")
96
+ if type(self.role) is not MetricRole:
97
+ raise TypeError("role must be an exact MetricRole")
98
+ if type(self.sense) is not MetricSense:
99
+ raise TypeError("sense must be an exact MetricSense")
100
+ expected_prefix = f"{self.role.value}:"
101
+ if (
102
+ type(self.metric_id) is not str
103
+ or not self.metric_id.startswith(expected_prefix)
104
+ or _TOKEN.fullmatch(self.metric_id[len(expected_prefix) :]) is None
105
+ ):
106
+ raise ValueError(
107
+ "metric_id must be '<role>:<closed-token-name>' and match role"
108
+ )
109
+ _nonempty(self.definition, "metric definition")
110
+ _nonempty(self.aggregation, "metric aggregation")
111
+ _nonempty(self.witness_interpretation, "witness_interpretation")
112
+ target = _finite_optional(self.reference_target, "reference_target")
113
+ tolerance = _finite_optional(self.tolerance, "tolerance")
114
+ if tolerance is not None and tolerance < 0:
115
+ raise ValueError("tolerance must be non-negative")
116
+ if self.sense is MetricSense.TARGET and target is None:
117
+ raise ValueError("target-sense metrics require reference_target")
118
+ if self.bounds is not None:
119
+ if type(self.bounds) is not tuple or len(self.bounds) != 2:
120
+ raise TypeError("bounds must be an exact (lower, upper) tuple")
121
+ lower = _finite_optional(self.bounds[0], "bounds lower")
122
+ upper = _finite_optional(self.bounds[1], "bounds upper")
123
+ if lower is None and upper is None:
124
+ raise ValueError("bounds must publish at least one endpoint")
125
+ if lower is not None and upper is not None and lower > upper:
126
+ raise ValueError("bounds lower endpoint exceeds upper endpoint")
127
+ elif self.sense is MetricSense.SATISFY_BOUNDS:
128
+ raise ValueError("satisfy-bounds metrics require bounds")
129
+
130
+ def to_record(self) -> dict[str, object]:
131
+ return {
132
+ "metric_id": self.metric_id,
133
+ "name": self.name,
134
+ "role": self.role.value,
135
+ "sense": self.sense.value,
136
+ "definition": self.definition,
137
+ "aggregation": self.aggregation,
138
+ "reference_target": self.reference_target,
139
+ "bounds": None if self.bounds is None else list(self.bounds),
140
+ "tolerance": self.tolerance,
141
+ "witness_interpretation": self.witness_interpretation,
142
+ }
143
+
144
+
145
+ @dataclass(frozen=True, slots=True)
146
+ class OutcomeOrderingSemantics:
147
+ """Human-readable ordering bound to the executable relation policy."""
148
+
149
+ kind: OutcomeOrderingKind
150
+ metric_priority: tuple[str, ...]
151
+ description: str
152
+ equivalence: str
153
+ policy_id: str
154
+ policy_version: int
155
+ definition_sha256: str
156
+
157
+ def __post_init__(self) -> None:
158
+ if type(self.kind) is not OutcomeOrderingKind:
159
+ raise TypeError("kind must be an exact OutcomeOrderingKind")
160
+ if type(self.metric_priority) is not tuple or not self.metric_priority:
161
+ raise ValueError("metric_priority must be a non-empty exact tuple")
162
+ if any(type(value) is not str or not value for value in self.metric_priority):
163
+ raise TypeError("metric_priority entries must be non-empty strings")
164
+ if len(set(self.metric_priority)) != len(self.metric_priority):
165
+ raise ValueError("metric_priority must not contain duplicates")
166
+ _nonempty(self.description, "outcome ordering description")
167
+ _nonempty(self.equivalence, "outcome equivalence description")
168
+ _token(self.policy_id, "outcome policy_id")
169
+ if type(self.policy_version) is not int or self.policy_version <= 0:
170
+ raise ValueError("outcome policy_version must be a positive exact integer")
171
+ require_sha256(self.definition_sha256, "outcome definition_sha256")
172
+
173
+ @property
174
+ def relation_identity(self) -> tuple[str, int, str]:
175
+ return self.policy_id, self.policy_version, self.definition_sha256
176
+
177
+ def to_record(self) -> dict[str, object]:
178
+ return {
179
+ "kind": self.kind.value,
180
+ "metric_priority": list(self.metric_priority),
181
+ "description": self.description,
182
+ "equivalence": self.equivalence,
183
+ "relation_policy": {
184
+ "policy_id": self.policy_id,
185
+ "policy_version": self.policy_version,
186
+ "definition_sha256": self.definition_sha256,
187
+ },
188
+ }
189
+
190
+
191
+ @dataclass(frozen=True, slots=True)
192
+ class OptimizationSemantics:
193
+ """Versioned semantic contract supplied by a benchmark adapter."""
194
+
195
+ semantics_id: str
196
+ semantics_version: int
197
+ metrics: tuple[MetricSemantics, ...]
198
+ outcome_ordering: OutcomeOrderingSemantics
199
+ definition_sha256: str = field(init=False)
200
+
201
+ def __post_init__(self) -> None:
202
+ _token(self.semantics_id, "semantics_id")
203
+ if type(self.semantics_version) is not int or self.semantics_version <= 0:
204
+ raise ValueError("semantics_version must be a positive exact integer")
205
+ if type(self.metrics) is not tuple or not self.metrics:
206
+ raise ValueError("metrics must be a non-empty exact tuple")
207
+ for metric in self.metrics:
208
+ if type(metric) is not MetricSemantics:
209
+ raise TypeError("metrics must contain exact MetricSemantics values")
210
+ MetricSemantics.__post_init__(metric)
211
+ metric_ids = tuple(metric.metric_id for metric in self.metrics)
212
+ if len(set(metric_ids)) != len(metric_ids):
213
+ raise ValueError("metric IDs must be unique")
214
+ if type(self.outcome_ordering) is not OutcomeOrderingSemantics:
215
+ raise TypeError(
216
+ "outcome_ordering must be an exact OutcomeOrderingSemantics"
217
+ )
218
+ OutcomeOrderingSemantics.__post_init__(self.outcome_ordering)
219
+ missing = set(self.outcome_ordering.metric_priority) - set(metric_ids)
220
+ if missing:
221
+ raise ValueError(
222
+ "outcome metric_priority references unknown metrics: "
223
+ + ", ".join(sorted(missing))
224
+ )
225
+ encoded = json.dumps(
226
+ self._definition_record(),
227
+ allow_nan=False,
228
+ ensure_ascii=True,
229
+ separators=(",", ":"),
230
+ sort_keys=True,
231
+ ).encode("ascii")
232
+ object.__setattr__(
233
+ self,
234
+ "definition_sha256",
235
+ hashlib.sha256(_SEMANTICS_HASH_DOMAIN + encoded).hexdigest(),
236
+ )
237
+
238
+ def _definition_record(self) -> dict[str, object]:
239
+ return {
240
+ "schema_version": 1,
241
+ "semantics_id": self.semantics_id,
242
+ "semantics_version": self.semantics_version,
243
+ "metrics": [metric.to_record() for metric in self.metrics],
244
+ "outcome_ordering": self.outcome_ordering.to_record(),
245
+ }
246
+
247
+ @property
248
+ def identity(self) -> tuple[str, int, str]:
249
+ return self.semantics_id, self.semantics_version, self.definition_sha256
250
+
251
+ def to_record(self) -> dict[str, object]:
252
+ return {
253
+ **self._definition_record(),
254
+ "definition_sha256": self.definition_sha256,
255
+ }
256
+
257
+ def validate_binding(
258
+ self,
259
+ objectives: Sequence[ObjectiveSpec],
260
+ outcome_relation_identity: tuple[str, int, str],
261
+ ) -> None:
262
+ """Bind published prose to executable objective and relation semantics."""
263
+
264
+ validate_objective_specs(objectives)
265
+ if self.outcome_ordering.relation_identity != outcome_relation_identity:
266
+ raise ValueError(
267
+ "optimization semantics outcome ordering differs from the "
268
+ "executable outcome relation"
269
+ )
270
+ objective_metrics = {
271
+ metric.name: metric
272
+ for metric in self.metrics
273
+ if metric.role is MetricRole.OBJECTIVE
274
+ }
275
+ expected_names = {objective.name for objective in objectives}
276
+ if set(objective_metrics) != expected_names:
277
+ raise ValueError(
278
+ "optimization semantics objective metrics differ from declared "
279
+ "problem objectives"
280
+ )
281
+ for objective in objectives:
282
+ expected_sense = (
283
+ MetricSense.MINIMIZE
284
+ if objective.goal == "min"
285
+ else MetricSense.MAXIMIZE
286
+ )
287
+ if objective_metrics[objective.name].sense is not expected_sense:
288
+ raise ValueError(
289
+ f"optimization semantics sense differs for {objective.name!r}"
290
+ )
291
+
292
+
293
+ def render_optimization_semantics(semantics: OptimizationSemantics) -> str:
294
+ """Return the canonical prompt block shared by proposal and reflection."""
295
+
296
+ if type(semantics) is not OptimizationSemantics:
297
+ raise TypeError("semantics must be an exact OptimizationSemantics")
298
+ OptimizationSemantics.__post_init__(semantics)
299
+ payload = json.dumps(
300
+ semantics.to_record(),
301
+ allow_nan=False,
302
+ ensure_ascii=True,
303
+ separators=(",", ":"),
304
+ sort_keys=True,
305
+ )
306
+ return "\n".join(
307
+ (
308
+ "OPTIMIZATION SEMANTICS (VERSIONED, AUTHORITATIVE)",
309
+ "Use these exact metric definitions, witness signs, and outcome "
310
+ "ordering; do not infer semantics from metric names.",
311
+ payload,
312
+ )
313
+ )
314
+
315
+
316
+ __all__ = [
317
+ "MetricRole",
318
+ "MetricSemantics",
319
+ "MetricSense",
320
+ "OptimizationSemantics",
321
+ "OutcomeOrderingKind",
322
+ "OutcomeOrderingSemantics",
323
+ "render_optimization_semantics",
324
+ ]