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,267 @@
1
+ """Model-authored population initialization: the highest-leverage decision.
2
+
3
+ Initialization shapes the entire trajectory -- every later operator recombines
4
+ what the first generation contained. Until now that decision was schema-
5
+ uniform noise; this seam lets the model propose the initial population from
6
+ the domain card: on a sizing problem, textbook-informed starting points can
7
+ place the run in a different basin before a single evaluation is spent.
8
+
9
+ The authoring line, applied to initialization: every proposed member is
10
+ validated VALUE-BY-VALUE against the declared domains (declared loci must
11
+ hold declared values; undeclared loci must keep the template's value);
12
+ rejected members are counted and their slots fall back to schema-uniform
13
+ draws; the caller's own seeds always come first and always survive. The
14
+ budget then arbitrates: proposed members are evaluated like any other
15
+ candidate, and a bad initial population is paid for in the open.
16
+
17
+ WHAT THE ASK IS FOR is a separate decision from who answers it, and ``style``
18
+ declares it. ``"joint"`` -- the default, and every sealed row -- asks for one
19
+ list that is individually strong AND collectively diverse. That single ask
20
+ conflates two things, and the ladder measured the cost: median pool regret is
21
+ better at reasoning effort ``none`` than at ``medium`` on 23 of 24 paired
22
+ seeds, because deliberation buys DIVERSITY and the pool median pays for it.
23
+ ``"split"`` is the same one call with two labelled sub-asks -- k_exploit
24
+ strongest individual bets, k_explore configurations covering distinct regions
25
+ -- so effort and capability have a channel (the exploit subset) that is not
26
+ diversity-conflated, and the telemetry labels every returned member so that
27
+ subset can be scored on its own.
28
+ """
29
+
30
+ from __future__ import annotations
31
+
32
+ import json
33
+ import re
34
+ from dataclasses import dataclass, field
35
+ from typing import Any, Callable, Dict, List, Optional, Sequence
36
+
37
+ from agent_evolve.policies.genetic import Locus, loci_of, locus_domain, read_locus
38
+
39
+ __all__ = ["InitTelemetry", "author_initial_population", "INIT_PROMPT",
40
+ "SPLIT_INIT_PROMPT", "INIT_STYLES"]
41
+
42
+ Config = Dict[str, Any]
43
+
44
+ #: What the one initialization call asks for. See the module docstring.
45
+ INIT_STYLES = ("joint", "split")
46
+
47
+ #: The labels a returned member can carry, and the counter prefixes that go
48
+ #: with them. ``"joint"`` and ``"unlabeled"`` are labels without a subset:
49
+ #: nothing in the reply distinguished those members, so nothing counts them
50
+ #: apart.
51
+ _SUBSETS = ("exploit", "explore")
52
+
53
+
54
+ @dataclass
55
+ class InitTelemetry:
56
+ calls: int = 0
57
+ proposed: int = 0
58
+ accepted: int = 0
59
+ rejected_out_of_domain: int = 0
60
+ rejected_shape: int = 0
61
+ unparseable: int = 0
62
+ errors: int = 0
63
+ #: The split ask's two halves, counted apart. Zero under ``"joint"``, and
64
+ #: zero under a split reply that arrived as a bare list: a member nothing
65
+ #: labelled is not evidence about either half.
66
+ exploit_proposed: int = 0
67
+ exploit_accepted: int = 0
68
+ explore_proposed: int = 0
69
+ explore_accepted: int = 0
70
+ #: One label per RETURNED member, in the returned order -- so a scorer can
71
+ #: read the exploit subset's quality without re-deriving which member came
72
+ #: from which half. "exploit" | "explore" | "joint" | "unlabeled".
73
+ labels: List[str] = field(default_factory=list)
74
+
75
+ def as_dict(self) -> dict[str, int]:
76
+ return {name: getattr(self, name) for name in
77
+ ("calls", "proposed", "accepted", "rejected_out_of_domain",
78
+ "rejected_shape", "unparseable", "errors",
79
+ "exploit_proposed", "exploit_accepted",
80
+ "explore_proposed", "explore_accepted")}
81
+
82
+
83
+ INIT_PROMPT = """{context}
84
+
85
+ You are proposing the INITIAL POPULATION for an evolutionary search over the
86
+ problem above. These {k} configurations are the raw material every later
87
+ recombination works with; they should be individually strong bets AND
88
+ collectively diverse (covering distinct promising regions/trade-offs), based
89
+ on what the parameters and objectives MEAN.
90
+
91
+ Reply with ONLY a JSON list of exactly {k} configuration objects, each with
92
+ every parameter field, every value taken from that parameter's declared
93
+ domain. No commentary."""
94
+
95
+
96
+ SPLIT_INIT_PROMPT = """{context}
97
+
98
+ You are proposing the INITIAL POPULATION for an evolutionary search over the
99
+ problem above. These {k} configurations are the raw material every later
100
+ recombination works with, and they are asked for in TWO parts. Each part is
101
+ optimized for its own thing and for nothing else.
102
+
103
+ EXPLOIT: exactly {k_exploit} configurations that are the STRONGEST INDIVIDUAL
104
+ BETS on the evidence of the card above -- what you would submit if only the
105
+ single best member counted. Do not spend any of these on coverage.
106
+
107
+ EXPLORE: exactly {k_explore} configurations covering DISTINCT promising
108
+ regions and trade-offs of the space -- what you would submit if only the
109
+ spread counted. Do not spend any of these on being individually safe.
110
+
111
+ Every configuration in both parts carries every parameter field, with every
112
+ value taken from that parameter's declared domain.
113
+
114
+ Reply with ONLY this JSON shape and no other text:
115
+ {{"exploit": [...], "explore": [...]}}"""
116
+
117
+
118
+ def _bare_list(text: str) -> Optional[list]:
119
+ """The first bracketed run of *text* as a JSON list, or ``None``.
120
+
121
+ The parse every sealed initialization ran, factored out unchanged so that
122
+ both styles read a list the same way -- and so the split style's fallback
123
+ reads exactly what a joint reply would have been read as.
124
+ """
125
+
126
+ match = re.search(r"\[.*\]", text, re.S)
127
+ if match is None:
128
+ return None
129
+ try:
130
+ raw = json.loads(match.group(0))
131
+ except (ValueError, TypeError):
132
+ return None
133
+ return raw if isinstance(raw, list) else None
134
+
135
+
136
+ def _labelled_lists(text: str) -> Optional[tuple[list, list]]:
137
+ """``(exploit, explore)`` from the split reply shape, or ``None``.
138
+
139
+ ``None`` whenever either key is missing or is not a list: the reply did
140
+ not answer the ask that was made, and this seam repairs nothing.
141
+ """
142
+
143
+ match = re.search(r"\{.*\}", text, re.S)
144
+ if match is None:
145
+ return None
146
+ try:
147
+ raw = json.loads(match.group(0))
148
+ except (ValueError, TypeError):
149
+ return None
150
+ if not isinstance(raw, dict):
151
+ return None
152
+ exploit, explore = raw.get("exploit"), raw.get("explore")
153
+ if not isinstance(exploit, list) or not isinstance(explore, list):
154
+ return None
155
+ return exploit, explore
156
+
157
+
158
+ def _rejection(member: Any, template: Config, candidate_model: Any) -> Optional[str]:
159
+ """``None`` when *member* is admissible, else which counter it moves.
160
+
161
+ Value-by-value against the declared domains: a declared locus must hold a
162
+ declared value, an undeclared one must keep the template's. The one place
163
+ a member is judged, so both styles are judged identically.
164
+ """
165
+
166
+ if not isinstance(member, dict) or set(member) != set(template):
167
+ return "shape"
168
+ try:
169
+ member_loci = loci_of(member)
170
+ except Exception:
171
+ return "shape"
172
+ if member_loci != loci_of(template):
173
+ return "shape"
174
+ for locus in member_loci:
175
+ value = read_locus(member, locus)
176
+ domain = locus_domain(candidate_model, locus)
177
+ if domain:
178
+ if value not in domain:
179
+ return "domain"
180
+ elif value != read_locus(template, locus):
181
+ return "domain"
182
+ return None
183
+
184
+
185
+ def author_initial_population(
186
+ complete: Callable[[str], str],
187
+ *,
188
+ candidate_model: Any,
189
+ template: Config,
190
+ k: int,
191
+ domain_context: str,
192
+ telemetry: Optional[InitTelemetry] = None,
193
+ style: str = "joint",
194
+ ) -> List[Config]:
195
+ """Up to *k* validated initial members; whatever is rejected costs a slot,
196
+ not the run -- the loop fills shortfalls schema-uniformly.
197
+
198
+ *style* is the ASK (see the module docstring). ``"joint"`` is the sealed
199
+ one, prompt and parse unchanged. ``"split"`` is one call carrying two
200
+ labelled sub-asks, ``k_exploit = (k + 1) // 2`` strongest bets first and
201
+ the rest coverage; the halves are capped separately, members come back
202
+ exploit-first, and every returned member is labelled in the telemetry. A
203
+ split reply missing either key is read as a bare list if one is there --
204
+ unlabelled, counted in no half -- and is otherwise unparseable. Nothing is
205
+ repaired, in either style.
206
+ """
207
+
208
+ if style not in INIT_STYLES:
209
+ raise ValueError(
210
+ f"init style must be one of {INIT_STYLES}, got {style!r}")
211
+
212
+ tel = telemetry if telemetry is not None else InitTelemetry()
213
+ tel.calls += 1
214
+ k_exploit = (k + 1) // 2
215
+ prompt = (
216
+ INIT_PROMPT.format(context=domain_context, k=k) if style == "joint"
217
+ else SPLIT_INIT_PROMPT.format(
218
+ context=domain_context, k=k, k_exploit=k_exploit,
219
+ k_explore=k - k_exploit)
220
+ )
221
+ try:
222
+ text = complete(prompt)
223
+ except Exception:
224
+ tel.errors += 1
225
+ return []
226
+
227
+ batches: tuple[tuple[str, list], ...]
228
+ if style == "joint":
229
+ raw = _bare_list(text)
230
+ if raw is None:
231
+ tel.unparseable += 1
232
+ return []
233
+ batches = (("joint", raw[:k]),)
234
+ else:
235
+ pair = _labelled_lists(text)
236
+ if pair is not None:
237
+ batches = (("exploit", pair[0][:k_exploit]),
238
+ ("explore", pair[1][:k - k_exploit]))
239
+ else:
240
+ raw = _bare_list(text)
241
+ if raw is None:
242
+ tel.unparseable += 1
243
+ return []
244
+ batches = (("unlabeled", raw[:k]),)
245
+
246
+ accepted: List[Config] = []
247
+ for label, members in batches:
248
+ subset = label if label in _SUBSETS else None
249
+ for member in members:
250
+ tel.proposed += 1
251
+ if subset:
252
+ setattr(tel, f"{subset}_proposed",
253
+ getattr(tel, f"{subset}_proposed") + 1)
254
+ reason = _rejection(member, template, candidate_model)
255
+ if reason == "shape":
256
+ tel.rejected_shape += 1
257
+ continue
258
+ if reason is not None:
259
+ tel.rejected_out_of_domain += 1
260
+ continue
261
+ tel.accepted += 1
262
+ if subset:
263
+ setattr(tel, f"{subset}_accepted",
264
+ getattr(tel, f"{subset}_accepted") + 1)
265
+ tel.labels.append(label)
266
+ accepted.append(dict(member))
267
+ return accepted
@@ -0,0 +1,109 @@
1
+ """The model writes variation operators: moves, not candidates.
2
+
3
+ A hand-rolled operator zoo encodes what its author guessed about structure
4
+ in general. The model is asked once, from the schema and objective meanings,
5
+ to write up to three ``vary`` functions encoding what THIS domain's
6
+ structure rewards -- co-moving coupled parameters, preserving named motifs,
7
+ reordering adjacent actions. Each authored operator becomes one arm in the
8
+ measured portfolio: it earns offspring slots through survival credit, its
9
+ children pass the material check or its slot falls back to the classical
10
+ arm, and the preregistered retirement rule ends arms that never produce a
11
+ survivor. The model authors the move; the run decides what it was worth.
12
+
13
+ Extraction and gating mirror ``llm_surrogate``: fenced blocks only, the
14
+ worker's own import gate applied at authoring time, every rejection counted.
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import re
20
+ from typing import Callable, List, Optional, Sequence
21
+
22
+ from agent_evolve.core.authored import CONTRACTS, AuthoredArtifact, authored_artifact
23
+ from agent_evolve.core.problem import ObjectiveSpec
24
+ from agent_evolve.infrastructure.authored_worker import ALLOWED_IMPORTS
25
+ from agent_evolve.policies.llm_surrogate import AuthorTelemetry, gate_source
26
+
27
+ __all__ = ["author_operators", "OPERATOR_PROMPT"]
28
+
29
+
30
+ OPERATOR_PROMPT = """You are writing VARIATION OPERATORS for a genetic \
31
+ optimizer over a structured configuration space. An operator constructs one \
32
+ child from two parents; good operators exploit what the parameters MEAN --
33
+ co-move parameters that are physically coupled, preserve fragments that only \
34
+ work together, reorder adjacent actions, move along known trade-offs.
35
+
36
+ OBJECTIVES (name and direction):
37
+ {goals}
38
+
39
+ SEARCH SPACE:
40
+ {schema}
41
+
42
+ Write up to {max_operators} DIFFERENT operators. Each must be one Python \
43
+ function with EXACTLY this signature:
44
+
45
+ {contract}
46
+
47
+ Rules:
48
+ - `loci` lists the heritable positions in order (sequence fields appear as
49
+ `name[i]`); `domains` maps each locus to its allowed values under the
50
+ current sampling prior. Every value you place must come from a parent at
51
+ that locus or from `domains` -- anything else is rejected and wastes the
52
+ slot.
53
+ - Derive all randomness from `seed` (e.g. `random.Random(seed)`), so a child
54
+ is reproducible.
55
+ - Standard library only; imports limited to: {imports}.
56
+ - Each operator in its OWN fenced Python block, each defining `vary`.
57
+ - Do not write candidates, wrappers, or commentary between blocks.
58
+
59
+ Reply with ONLY the fenced code blocks."""
60
+
61
+
62
+ _FENCE = re.compile(r"```(?:python)?\s*\n(.*?)```", re.S)
63
+
64
+
65
+ def author_operators(
66
+ complete: Callable[[str], str],
67
+ *,
68
+ objectives: Sequence[ObjectiveSpec],
69
+ schema_text: str,
70
+ max_operators: int = 3,
71
+ attempts: int = 2,
72
+ telemetry: Optional[AuthorTelemetry] = None,
73
+ ) -> List[AuthoredArtifact]:
74
+ """Ask for up to *max_operators* ``vary`` functions; gate each block whole."""
75
+
76
+ tel = telemetry if telemetry is not None else AuthorTelemetry()
77
+ contract = CONTRACTS["operator"]
78
+ prompt = OPERATOR_PROMPT.format(
79
+ goals="\n".join(f" {s.name}: {s.goal}imise" for s in objectives),
80
+ schema=schema_text,
81
+ max_operators=max_operators,
82
+ contract=contract.description,
83
+ imports=", ".join(sorted(ALLOWED_IMPORTS)),
84
+ )
85
+ for _attempt in range(max(1, attempts)):
86
+ tel.calls += 1
87
+ try:
88
+ text = complete(prompt)
89
+ except Exception:
90
+ tel.errors += 1
91
+ continue
92
+ blocks = _FENCE.findall(text)
93
+ if not blocks:
94
+ tel.no_code_block += 1
95
+ continue
96
+ artifacts: List[AuthoredArtifact] = []
97
+ for index, block in enumerate(blocks[:max_operators]):
98
+ source = gate_source(block, contract=contract, telemetry=tel)
99
+ if source is None:
100
+ continue
101
+ tel.accepted += 1
102
+ tel.sources.append(source)
103
+ artifacts.append(authored_artifact(
104
+ "operator", source,
105
+ name=f"llm_op{index + 1}", authored_by="llm",
106
+ ))
107
+ if artifacts:
108
+ return artifacts
109
+ return []
@@ -0,0 +1,194 @@
1
+ """A model reading a screen and proposing where to sample.
2
+
3
+ The blind version of this does not work and the reason is worth stating: asked
4
+ from the schema alone, a model reasons about a *plausible* instance of the
5
+ domain rather than the one in front of it. Measured on an accelerator venue, it
6
+ declined to exclude anything, arguing that registers trade latency against area
7
+ -- sound in general, and false there, where latency was a function of one other
8
+ locus entirely. What it lacked was a model of the evaluator, not domain
9
+ knowledge. So this proposer never runs blind: it reads a screen.
10
+
11
+ What it returns is a restriction over declared domains -- never a candidate,
12
+ never a value the schema does not declare. That is the same choice-not-authoring
13
+ line the chooser holds, applied to the generator rather than to the pair.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import json
19
+ import re
20
+ from dataclasses import dataclass, field
21
+ from typing import Any, Callable, Mapping, Sequence
22
+
23
+ from agent_evolve.core.problem import ObjectiveSpec
24
+ from agent_evolve.policies.genetic import DomainRestriction, Locus, locus_domain
25
+ from agent_evolve.policies.structure import Attribution, render_attribution
26
+
27
+ __all__ = ["PriorTelemetry", "llm_prior_proposer", "PROMPT"]
28
+
29
+ PROMPT = """\
30
+ You are advising an optimizer that has already spent {n} of its evaluations on
31
+ a screening design. The rest of the budget remains.
32
+
33
+ OBJECTIVES ({goals}).
34
+
35
+ THE SEARCH SPACE:
36
+ {schema}
37
+
38
+ WHAT THE SCREEN MEASURED. Per parameter value: the mean of each objective over
39
+ the screened candidates carrying that value, and how many of them were
40
+ non-dominated within the screen.
41
+ {screen}
42
+
43
+ Read this as evidence about how THIS evaluator behaves -- it may or may not
44
+ match how such problems usually behave.
45
+
46
+ YOUR TASK. Propose a sampling prior: for each parameter, either restrict
47
+ sampling to a subset of its values, or leave it free. You are not choosing a
48
+ candidate and must not propose one; you are shaping the distribution the
49
+ optimizer draws from.
50
+
51
+ Restricting to a genuinely better region multiplies the remaining budget.
52
+ Restricting wrongly can put the best region out of reach. Over-restricting a
53
+ parameter that spreads candidates ALONG the frontier destroys the diversity a
54
+ multi-objective search needs. Leave a parameter free unless the screen gives
55
+ you a reason.
56
+
57
+ Reply with JSON only:
58
+ {{"restrictions": {{"<param>": [allowed values...]}}, "free": ["<param>", ...]}}
59
+ Every parameter appears exactly once, in "restrictions" or in "free".
60
+ """
61
+
62
+
63
+ @dataclass
64
+ class PriorTelemetry:
65
+ """What the proposer's replies did. Counted, never inferred."""
66
+
67
+ calls: int = 0
68
+ unparseable: int = 0
69
+ wrote_candidate: int = 0
70
+ out_of_domain: int = 0
71
+ empty: int = 0
72
+ restricted_loci: int = 0
73
+ errors: int = 0
74
+ proposals: list = field(default_factory=list)
75
+
76
+ def as_dict(self) -> dict[str, int]:
77
+ return {
78
+ "calls": self.calls,
79
+ "unparseable": self.unparseable,
80
+ "wrote_candidate": self.wrote_candidate,
81
+ "out_of_domain": self.out_of_domain,
82
+ "empty": self.empty,
83
+ "restricted_loci": self.restricted_loci,
84
+ "errors": self.errors,
85
+ "proposals": len(self.proposals),
86
+ }
87
+
88
+
89
+ def _domains(candidate_model: Any, attr: Attribution) -> dict[str, tuple]:
90
+ names = list(dict.fromkeys(s.locus for s in attr.levels))
91
+ out: dict[str, tuple] = {}
92
+ for name in names:
93
+ base = name.split("[")[0]
94
+ domain = locus_domain(candidate_model, Locus(base))
95
+ if not domain: # a sequence element's own domain
96
+ index = name[name.find("[") + 1:-1] if "[" in name else None
97
+ domain = locus_domain(
98
+ candidate_model,
99
+ Locus(base, int(index)) if index is not None else Locus(base))
100
+ if domain:
101
+ out[base] = domain
102
+ return out
103
+
104
+
105
+ def llm_prior_proposer(
106
+ complete: Callable[[str], str],
107
+ *,
108
+ objectives: Sequence[ObjectiveSpec],
109
+ telemetry: PriorTelemetry | None = None,
110
+ domain_context: str = "",
111
+ ) -> Callable[[Attribution, Any], DomainRestriction]:
112
+ """A :data:`~agent_evolve.policies.structure.PriorProposer` backed by *complete*.
113
+
114
+ A reply naming values the schema never declared is REJECTED whole, not
115
+ repaired: a repaired prior is the harness's prior wearing the model's name,
116
+ and the measurement it feeds would be attributing someone else's decision.
117
+ An unusable reply yields an empty restriction, which is exactly the
118
+ unguided sampling distribution -- the safe direction to fail in.
119
+ """
120
+
121
+ from agent_evolve.policies.semantics import objective_lines, parameter_lines
122
+
123
+ tel = telemetry if telemetry is not None else PriorTelemetry()
124
+ goals = ", ".join(objective_lines(objectives))
125
+ # An empty context contributes nothing to the prompt, so a caller that
126
+ # supplies no card gets the pre-semantics prompt byte-for-byte.
127
+ preamble = f"{domain_context.strip()}\n\n" if domain_context.strip() else ""
128
+
129
+ def propose(attr: Attribution, candidate_model: Any) -> DomainRestriction:
130
+ domains = _domains(candidate_model, attr)
131
+ if not domains:
132
+ return DomainRestriction({})
133
+ described = parameter_lines(candidate_model, fields=list(domains))
134
+ prompt = preamble + PROMPT.format(
135
+ n=attr.n_evaluated, goals=goals,
136
+ schema="\n".join(f" {line}" for line in described)
137
+ if described else
138
+ "\n".join(f" {k}: one of {list(v)}" for k, v in domains.items()),
139
+ screen=render_attribution(attr))
140
+ tel.calls += 1
141
+ try:
142
+ reply = complete(prompt)
143
+ except Exception:
144
+ tel.errors += 1
145
+ return DomainRestriction({})
146
+
147
+ match = re.search(r"\{.*\}", reply or "", re.S)
148
+ if not match:
149
+ tel.unparseable += 1
150
+ return DomainRestriction({})
151
+ try:
152
+ doc = json.loads(match.group(0))
153
+ except json.JSONDecodeError:
154
+ tel.unparseable += 1
155
+ return DomainRestriction({})
156
+ if not isinstance(doc, dict):
157
+ tel.unparseable += 1
158
+ return DomainRestriction({})
159
+
160
+ restrictions = doc.get("restrictions")
161
+ if not isinstance(restrictions, dict):
162
+ tel.unparseable += 1
163
+ return DomainRestriction({})
164
+ # A reply that hands back whole configurations is authoring, which this
165
+ # channel exists not to do. Detect it by shape: a mapping of parameter
166
+ # to a single scalar rather than to a list of allowed values.
167
+ if restrictions and all(
168
+ not isinstance(v, list) for v in restrictions.values()):
169
+ tel.wrote_candidate += 1
170
+ return DomainRestriction({})
171
+
172
+ allowed: dict[str, list] = {}
173
+ for key, values in restrictions.items():
174
+ domain = domains.get(key)
175
+ if domain is None or not isinstance(values, list) or not values:
176
+ tel.out_of_domain += 1
177
+ return DomainRestriction({})
178
+ kept = [v for v in values if v in domain]
179
+ if len(kept) != len(values):
180
+ tel.out_of_domain += 1
181
+ return DomainRestriction({})
182
+ if len(kept) < len(domain):
183
+ allowed[key] = kept
184
+
185
+ if not allowed:
186
+ tel.empty += 1
187
+ tel.restricted_loci += len(allowed)
188
+ tel.proposals.append(dict(allowed))
189
+ return DomainRestriction(allowed)
190
+
191
+ propose.telemetry = tel # type: ignore[attr-defined]
192
+ propose.mechanism = "prior" # type: ignore[attr-defined]
193
+ propose.authored_by = "llm" # type: ignore[attr-defined]
194
+ return propose