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,571 @@
1
+ """Provider-neutral orchestration strategies for structured reflection calls.
2
+
3
+ The evolutionary engine owns evidence construction and memory publication.
4
+ This module owns only how an already-frozen reflection batch is divided into
5
+ logical model calls. Keeping that seam in the application layer lets an
6
+ experiment change reflection topology without teaching the provider adapter or
7
+ any benchmark about the change.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import asyncio
13
+ import math
14
+ import re
15
+ from collections.abc import Callable
16
+ from dataclasses import dataclass
17
+ from typing import Protocol, runtime_checkable
18
+
19
+ from agent_evolve.domain.ids import LLMCallId
20
+ from agent_evolve.ports.agentic_generator import (
21
+ AgenticGenerator,
22
+ InsightDraft,
23
+ ReflectionGenerationRequest,
24
+ ReflectionGenerationResult,
25
+ ReflectionInsightContract,
26
+ validate_reflection_insight_draft,
27
+ )
28
+ from agent_evolve.ports.generation_failure import (
29
+ GenerationFailureDisposition,
30
+ classify_generation_failure,
31
+ )
32
+ from agent_evolve.ports.id_factory import IdFactory
33
+
34
+
35
+ _LOWER_SHA256 = re.compile(r"^[0-9a-f]{64}$")
36
+ _SPACE = re.compile(r"\s+")
37
+ ReflectionCallPlannedSink = Callable[
38
+ ["PlannedReflectionCall | PlannedReflectionBatchCall"], None
39
+ ]
40
+
41
+
42
+ @dataclass(frozen=True, slots=True)
43
+ class ReflectionPromptShard:
44
+ """One exact engine-derived contrast and its self-contained prompt."""
45
+
46
+ contrast_id: str
47
+ prompt: str
48
+
49
+ def __post_init__(self) -> None:
50
+ if (
51
+ type(self.contrast_id) is not str
52
+ or _LOWER_SHA256.fullmatch(self.contrast_id) is None
53
+ ):
54
+ raise ValueError("contrast_id must be a lowercase SHA-256 digest")
55
+ if type(self.prompt) is not str or not self.prompt.strip():
56
+ raise ValueError("reflection shard prompt must be non-empty")
57
+
58
+
59
+ @dataclass(frozen=True, slots=True)
60
+ class ReflectionWorkflowRequest:
61
+ """A complete staged reflection batch before any call ID is allocated."""
62
+
63
+ operation: str
64
+ shards: tuple[ReflectionPromptShard, ...]
65
+ max_output_tokens: int
66
+ temperature: float | None = None
67
+ insight_contract: ReflectionInsightContract | None = None
68
+ batch_prompt: str | None = None
69
+
70
+ def __post_init__(self) -> None:
71
+ if type(self.operation) is not str or not self.operation.strip():
72
+ raise ValueError("reflection operation must be non-empty")
73
+ if type(self.shards) is not tuple or not self.shards:
74
+ raise ValueError("reflection workflow requires at least one shard")
75
+ for shard in self.shards:
76
+ if type(shard) is not ReflectionPromptShard:
77
+ raise TypeError("shards must contain exact ReflectionPromptShard values")
78
+ ReflectionPromptShard.__post_init__(shard)
79
+ contrast_ids = tuple(shard.contrast_id for shard in self.shards)
80
+ if len(set(contrast_ids)) != len(contrast_ids):
81
+ raise ValueError("reflection workflow contrast IDs must be unique")
82
+ if type(self.max_output_tokens) is not int or self.max_output_tokens <= 0:
83
+ raise ValueError("max_output_tokens must be positive")
84
+ if self.temperature is not None and (
85
+ isinstance(self.temperature, bool)
86
+ or not isinstance(self.temperature, (int, float))
87
+ or not math.isfinite(float(self.temperature))
88
+ or float(self.temperature) < 0
89
+ ):
90
+ raise ValueError("temperature must be finite and non-negative or None")
91
+ if self.insight_contract is not None:
92
+ if type(self.insight_contract) is not ReflectionInsightContract:
93
+ raise TypeError(
94
+ "insight_contract must be an exact ReflectionInsightContract"
95
+ )
96
+ ReflectionInsightContract.__post_init__(self.insight_contract)
97
+ if self.batch_prompt is not None and (
98
+ type(self.batch_prompt) is not str or not self.batch_prompt.strip()
99
+ ):
100
+ raise ValueError("batch_prompt must be non-empty exact text or None")
101
+
102
+
103
+ @dataclass(frozen=True, slots=True)
104
+ class PlannedReflectionCall:
105
+ """One deterministic logical call allocated before concurrent execution."""
106
+
107
+ contrast_id: str
108
+ request: ReflectionGenerationRequest
109
+
110
+ def __post_init__(self) -> None:
111
+ if (
112
+ type(self.contrast_id) is not str
113
+ or _LOWER_SHA256.fullmatch(self.contrast_id) is None
114
+ ):
115
+ raise ValueError("contrast_id must be a lowercase SHA-256 digest")
116
+ if type(self.request) is not ReflectionGenerationRequest:
117
+ raise TypeError("request must be an exact ReflectionGenerationRequest")
118
+ ReflectionGenerationRequest.__post_init__(self.request)
119
+ if self.request.available_contrast_ids != (self.contrast_id,):
120
+ raise ValueError("a sharded call must expose exactly its assigned contrast")
121
+ if self.request.min_insights != 1 or self.request.max_insights != 1:
122
+ raise ValueError("a sharded call must require exactly one insight")
123
+
124
+ @property
125
+ def call_id(self) -> LLMCallId:
126
+ return self.request.call_id
127
+
128
+
129
+ @dataclass(frozen=True, slots=True)
130
+ class PlannedReflectionBatchCall:
131
+ """One deterministic logical call covering an exact contrast batch."""
132
+
133
+ contrast_ids: tuple[str, ...]
134
+ request: ReflectionGenerationRequest
135
+
136
+ def __post_init__(self) -> None:
137
+ if type(self.contrast_ids) is not tuple or not self.contrast_ids:
138
+ raise ValueError("a batched reflection call requires contrast IDs")
139
+ if self.contrast_ids != tuple(sorted(set(self.contrast_ids))):
140
+ raise ValueError("batched contrast IDs must be unique and canonical")
141
+ if any(_LOWER_SHA256.fullmatch(item) is None for item in self.contrast_ids):
142
+ raise ValueError("batched contrast IDs must be lowercase SHA-256 digests")
143
+ if type(self.request) is not ReflectionGenerationRequest:
144
+ raise TypeError("request must be an exact ReflectionGenerationRequest")
145
+ ReflectionGenerationRequest.__post_init__(self.request)
146
+ if self.request.available_contrast_ids != self.contrast_ids:
147
+ raise ValueError("batched request exposes the wrong contrast set")
148
+ expected_count = len(self.contrast_ids)
149
+ if (
150
+ self.request.min_insights != expected_count
151
+ or self.request.max_insights != expected_count
152
+ ):
153
+ raise ValueError("batched request must require one card per contrast")
154
+
155
+ @property
156
+ def call_id(self) -> LLMCallId:
157
+ return self.request.call_id
158
+
159
+
160
+ @dataclass(frozen=True, slots=True)
161
+ class ReflectionShardResult:
162
+ """One contrast-bound card and the logical call that produced it.
163
+
164
+ A contrast-sharded workflow has one singleton generation result per card.
165
+ A strict batched workflow deliberately shares one multi-card generation
166
+ result across every returned card. In both cases the exact draft must be
167
+ present in the bound result and must cite only this contrast.
168
+ """
169
+
170
+ contrast_id: str
171
+ call_id: LLMCallId
172
+ draft: InsightDraft
173
+ generation_result: ReflectionGenerationResult
174
+
175
+ def __post_init__(self) -> None:
176
+ if (
177
+ type(self.contrast_id) is not str
178
+ or _LOWER_SHA256.fullmatch(self.contrast_id) is None
179
+ ):
180
+ raise ValueError("contrast_id must be a lowercase SHA-256 digest")
181
+ if not isinstance(self.call_id, LLMCallId):
182
+ raise TypeError("call_id must be an LLMCallId")
183
+ if type(self.draft) is not InsightDraft:
184
+ raise TypeError("draft must be an exact InsightDraft")
185
+ InsightDraft.__post_init__(self.draft)
186
+ if self.draft.evidence_contrast_ids != (self.contrast_id,):
187
+ raise ValueError("accepted shard card must cite exactly its origin contrast")
188
+ if type(self.generation_result) is not ReflectionGenerationResult:
189
+ raise TypeError(
190
+ "generation_result must be an exact ReflectionGenerationResult"
191
+ )
192
+ if self.draft not in self.generation_result.insights:
193
+ raise ValueError("generation result does not contain its accepted card")
194
+
195
+
196
+ @dataclass(frozen=True, slots=True)
197
+ class ReflectionWorkflowResult:
198
+ """A complete validated batch, still staged outside durable memory."""
199
+
200
+ shards: tuple[ReflectionShardResult, ...]
201
+
202
+ def __post_init__(self) -> None:
203
+ if type(self.shards) is not tuple or not self.shards:
204
+ raise ValueError("reflection workflow result requires accepted shards")
205
+ if any(type(shard) is not ReflectionShardResult for shard in self.shards):
206
+ raise TypeError("shards must contain exact ReflectionShardResult values")
207
+ for shard in self.shards:
208
+ ReflectionShardResult.__post_init__(shard)
209
+ contrast_ids = tuple(shard.contrast_id for shard in self.shards)
210
+ if contrast_ids != tuple(sorted(set(contrast_ids))):
211
+ raise ValueError("accepted shards must use unique canonical contrast order")
212
+
213
+ @property
214
+ def logical_llm_calls_used(self) -> int:
215
+ return len({shard.call_id for shard in self.shards})
216
+
217
+ @property
218
+ def call_ids(self) -> tuple[LLMCallId, ...]:
219
+ """Return unique call identities in first-card canonical order."""
220
+
221
+ return tuple(dict.fromkeys(shard.call_id for shard in self.shards))
222
+
223
+
224
+ @dataclass(frozen=True, slots=True)
225
+ class ReflectionShardFailure:
226
+ """Content-free terminal status retained after all sibling calls settle."""
227
+
228
+ contrast_id: str
229
+ call_id: LLMCallId
230
+ error_type: str
231
+ disposition: GenerationFailureDisposition
232
+
233
+ def __post_init__(self) -> None:
234
+ if (
235
+ type(self.contrast_id) is not str
236
+ or _LOWER_SHA256.fullmatch(self.contrast_id) is None
237
+ ):
238
+ raise ValueError("contrast_id must be a lowercase SHA-256 digest")
239
+ if not isinstance(self.call_id, LLMCallId):
240
+ raise TypeError("call_id must be an LLMCallId")
241
+ if type(self.error_type) is not str or not self.error_type:
242
+ raise ValueError("error_type must be non-empty")
243
+ if type(self.disposition) is not GenerationFailureDisposition:
244
+ raise TypeError("disposition must be a GenerationFailureDisposition")
245
+
246
+
247
+ class ReflectionCardContractError(ValueError):
248
+ """A terminal model card escaped a shard's exact typed contract."""
249
+
250
+ @property
251
+ def generation_failure_disposition(self) -> GenerationFailureDisposition:
252
+ return GenerationFailureDisposition.MODEL_OR_SCHEMA_FAILURE
253
+
254
+
255
+ class ReflectionWorkflowExecutionError(RuntimeError):
256
+ """One or more calls failed after every concurrently submitted shard settled."""
257
+
258
+ def __init__(
259
+ self,
260
+ *,
261
+ failures: tuple[ReflectionShardFailure, ...],
262
+ completed: tuple[ReflectionShardResult, ...],
263
+ ) -> None:
264
+ if not failures:
265
+ raise ValueError("workflow execution error requires at least one failure")
266
+ self.failures = failures
267
+ self.completed = completed
268
+ super().__init__("contrast-sharded reflection did not yield a complete batch")
269
+
270
+ @property
271
+ def generation_failure_disposition(self) -> GenerationFailureDisposition:
272
+ if all(
273
+ failure.disposition
274
+ is GenerationFailureDisposition.MODEL_OR_SCHEMA_FAILURE
275
+ for failure in self.failures
276
+ ):
277
+ return GenerationFailureDisposition.MODEL_OR_SCHEMA_FAILURE
278
+ return GenerationFailureDisposition.INFRASTRUCTURE_FAILURE
279
+
280
+
281
+ @runtime_checkable
282
+ class ReflectionWorkflow(Protocol):
283
+ """Application seam for changing reflection topology independently of a domain."""
284
+
285
+ async def run(
286
+ self,
287
+ request: ReflectionWorkflowRequest,
288
+ *,
289
+ generator: AgenticGenerator,
290
+ id_factory: IdFactory,
291
+ call_planned_sink: ReflectionCallPlannedSink | None = None,
292
+ ) -> ReflectionWorkflowResult: ...
293
+
294
+
295
+ class ContrastShardedReflectionWorkflow:
296
+ """Generate one strict card per contrast with deterministic concurrent fan-out."""
297
+
298
+ policy_id = "contrast_sharded_reflection"
299
+ policy_version = 1
300
+
301
+ async def run(
302
+ self,
303
+ request: ReflectionWorkflowRequest,
304
+ *,
305
+ generator: AgenticGenerator,
306
+ id_factory: IdFactory,
307
+ call_planned_sink: ReflectionCallPlannedSink | None = None,
308
+ ) -> ReflectionWorkflowResult:
309
+ if type(request) is not ReflectionWorkflowRequest:
310
+ raise TypeError("request must be an exact ReflectionWorkflowRequest")
311
+ ReflectionWorkflowRequest.__post_init__(request)
312
+ if not isinstance(generator, AgenticGenerator):
313
+ raise TypeError("generator must implement AgenticGenerator")
314
+ if not isinstance(id_factory, IdFactory):
315
+ raise TypeError("id_factory must implement IdFactory")
316
+ if call_planned_sink is not None and not callable(call_planned_sink):
317
+ raise TypeError("call_planned_sink must be callable or None")
318
+
319
+ planned: list[PlannedReflectionCall] = []
320
+ for shard in sorted(request.shards, key=lambda value: value.contrast_id):
321
+ call = PlannedReflectionCall(
322
+ contrast_id=shard.contrast_id,
323
+ request=ReflectionGenerationRequest(
324
+ call_id=id_factory.new_llm_call_id(),
325
+ operation=request.operation,
326
+ prompt=shard.prompt,
327
+ max_insights=1,
328
+ min_insights=1,
329
+ max_output_tokens=request.max_output_tokens,
330
+ temperature=request.temperature,
331
+ available_contrast_ids=(shard.contrast_id,),
332
+ insight_contract=request.insight_contract,
333
+ ),
334
+ )
335
+ planned.append(call)
336
+ if call_planned_sink is not None:
337
+ call_planned_sink(call)
338
+
339
+ raw_results = await asyncio.gather(
340
+ *(generator.reflect(call.request) for call in planned),
341
+ return_exceptions=True,
342
+ )
343
+ completed: list[ReflectionShardResult] = []
344
+ failures: list[ReflectionShardFailure] = []
345
+ for call, raw in zip(planned, raw_results, strict=True):
346
+ if isinstance(raw, asyncio.CancelledError):
347
+ raise raw
348
+ if isinstance(raw, BaseException):
349
+ failures.append(
350
+ ReflectionShardFailure(
351
+ contrast_id=call.contrast_id,
352
+ call_id=call.call_id,
353
+ error_type=type(raw).__name__,
354
+ disposition=classify_generation_failure(raw),
355
+ )
356
+ )
357
+ continue
358
+ try:
359
+ if type(raw) is not ReflectionGenerationResult:
360
+ raise TypeError(
361
+ "generator returned a non-reflection result for a shard"
362
+ )
363
+ if len(raw.insights) != 1:
364
+ raise ReflectionCardContractError(
365
+ "a contrast shard must return exactly one insight"
366
+ )
367
+ draft = raw.insights[0]
368
+ if type(draft) is not InsightDraft:
369
+ raise TypeError("generator returned a non-InsightDraft card")
370
+ InsightDraft.__post_init__(draft)
371
+ if draft.evidence_contrast_ids != (call.contrast_id,):
372
+ raise ReflectionCardContractError(
373
+ "a contrast shard must cite exactly its assigned contrast"
374
+ )
375
+ if request.insight_contract is not None:
376
+ try:
377
+ validate_reflection_insight_draft(
378
+ draft,
379
+ request.insight_contract,
380
+ )
381
+ except (TypeError, ValueError) as exc:
382
+ raise ReflectionCardContractError(
383
+ "a contrast shard violated the insight contract"
384
+ ) from exc
385
+ completed.append(
386
+ ReflectionShardResult(
387
+ contrast_id=call.contrast_id,
388
+ call_id=call.call_id,
389
+ draft=draft,
390
+ generation_result=raw,
391
+ )
392
+ )
393
+ except BaseException as error:
394
+ if isinstance(error, asyncio.CancelledError):
395
+ raise
396
+ failures.append(
397
+ ReflectionShardFailure(
398
+ contrast_id=call.contrast_id,
399
+ call_id=call.call_id,
400
+ error_type=type(error).__name__,
401
+ disposition=classify_generation_failure(error),
402
+ )
403
+ )
404
+
405
+ canonical_completed = tuple(
406
+ sorted(completed, key=lambda value: value.contrast_id)
407
+ )
408
+ if failures:
409
+ raise ReflectionWorkflowExecutionError(
410
+ failures=tuple(sorted(failures, key=lambda value: value.contrast_id)),
411
+ completed=canonical_completed,
412
+ )
413
+ normalized_claims = tuple(
414
+ _SPACE.sub(" ", shard.draft.claim.strip().casefold())
415
+ for shard in canonical_completed
416
+ )
417
+ if len(set(normalized_claims)) != len(normalized_claims):
418
+ raise ReflectionCardContractError(
419
+ "contrast shards produced duplicate normalized claims"
420
+ )
421
+ return ReflectionWorkflowResult(canonical_completed)
422
+
423
+
424
+ class StrictBatchedReflectionWorkflow:
425
+ """Generate one exact card per contrast in one atomic logical call.
426
+
427
+ This topology is intended for evaluator-limited loops where a separate
428
+ provider call per contrast would dominate the resource budget. It accepts
429
+ a batch only when the model returns exactly one card for every contrast,
430
+ every card cites exactly one distinct available contrast, all cards satisfy
431
+ the shared insight contract, and normalized claims are unique. Nothing is
432
+ returned to durable memory on partial coverage.
433
+ """
434
+
435
+ policy_id = "strict_batched_reflection"
436
+ policy_version = 1
437
+
438
+ async def run(
439
+ self,
440
+ request: ReflectionWorkflowRequest,
441
+ *,
442
+ generator: AgenticGenerator,
443
+ id_factory: IdFactory,
444
+ call_planned_sink: ReflectionCallPlannedSink | None = None,
445
+ ) -> ReflectionWorkflowResult:
446
+ if type(request) is not ReflectionWorkflowRequest:
447
+ raise TypeError("request must be an exact ReflectionWorkflowRequest")
448
+ ReflectionWorkflowRequest.__post_init__(request)
449
+ if not isinstance(generator, AgenticGenerator):
450
+ raise TypeError("generator must implement AgenticGenerator")
451
+ if not isinstance(id_factory, IdFactory):
452
+ raise TypeError("id_factory must implement IdFactory")
453
+ if call_planned_sink is not None and not callable(call_planned_sink):
454
+ raise TypeError("call_planned_sink must be callable or None")
455
+ if request.batch_prompt is None:
456
+ raise ValueError("strict batched reflection requires batch_prompt")
457
+
458
+ contrast_ids = tuple(sorted(shard.contrast_id for shard in request.shards))
459
+ batched_request = ReflectionGenerationRequest(
460
+ call_id=id_factory.new_llm_call_id(),
461
+ operation=request.operation,
462
+ prompt=request.batch_prompt,
463
+ max_insights=len(contrast_ids),
464
+ min_insights=len(contrast_ids),
465
+ max_output_tokens=request.max_output_tokens,
466
+ temperature=request.temperature,
467
+ available_contrast_ids=contrast_ids,
468
+ insight_contract=request.insight_contract,
469
+ )
470
+ call = PlannedReflectionBatchCall(
471
+ contrast_ids=contrast_ids,
472
+ request=batched_request,
473
+ )
474
+ if call_planned_sink is not None:
475
+ call_planned_sink(call)
476
+
477
+ try:
478
+ raw = await generator.reflect(batched_request)
479
+ except asyncio.CancelledError:
480
+ raise
481
+ except BaseException as error:
482
+ raise ReflectionWorkflowExecutionError(
483
+ failures=tuple(
484
+ ReflectionShardFailure(
485
+ contrast_id=contrast_id,
486
+ call_id=batched_request.call_id,
487
+ error_type=type(error).__name__,
488
+ disposition=classify_generation_failure(error),
489
+ )
490
+ for contrast_id in contrast_ids
491
+ ),
492
+ completed=(),
493
+ ) from error
494
+
495
+ if type(raw) is not ReflectionGenerationResult:
496
+ raise ReflectionCardContractError(
497
+ "generator returned a non-reflection batched result"
498
+ )
499
+ if len(raw.insights) != len(contrast_ids):
500
+ raise ReflectionCardContractError(
501
+ "batched reflection must return exactly one card per contrast"
502
+ )
503
+
504
+ by_contrast: dict[str, InsightDraft] = {}
505
+ for draft in raw.insights:
506
+ if type(draft) is not InsightDraft:
507
+ raise ReflectionCardContractError(
508
+ "batched reflection returned a non-InsightDraft card"
509
+ )
510
+ InsightDraft.__post_init__(draft)
511
+ if len(draft.evidence_contrast_ids) != 1:
512
+ raise ReflectionCardContractError(
513
+ "every batched card must cite exactly one contrast"
514
+ )
515
+ contrast_id = draft.evidence_contrast_ids[0]
516
+ if contrast_id not in contrast_ids or contrast_id in by_contrast:
517
+ raise ReflectionCardContractError(
518
+ "batched reflection has foreign or duplicate contrast coverage"
519
+ )
520
+ if request.insight_contract is not None:
521
+ try:
522
+ validate_reflection_insight_draft(
523
+ draft,
524
+ request.insight_contract,
525
+ )
526
+ except (TypeError, ValueError) as exc:
527
+ raise ReflectionCardContractError(
528
+ "a batched card violated the insight contract"
529
+ ) from exc
530
+ by_contrast[contrast_id] = draft
531
+
532
+ if tuple(sorted(by_contrast)) != contrast_ids:
533
+ raise ReflectionCardContractError(
534
+ "batched reflection did not cover the exact contrast set"
535
+ )
536
+ normalized_claims = tuple(
537
+ _SPACE.sub(" ", by_contrast[item].claim.strip().casefold())
538
+ for item in contrast_ids
539
+ )
540
+ if len(set(normalized_claims)) != len(normalized_claims):
541
+ raise ReflectionCardContractError(
542
+ "batched reflection produced duplicate normalized claims"
543
+ )
544
+ return ReflectionWorkflowResult(
545
+ tuple(
546
+ ReflectionShardResult(
547
+ contrast_id=contrast_id,
548
+ call_id=batched_request.call_id,
549
+ draft=by_contrast[contrast_id],
550
+ generation_result=raw,
551
+ )
552
+ for contrast_id in contrast_ids
553
+ )
554
+ )
555
+
556
+
557
+ __all__ = [
558
+ "ContrastShardedReflectionWorkflow",
559
+ "PlannedReflectionCall",
560
+ "PlannedReflectionBatchCall",
561
+ "ReflectionCallPlannedSink",
562
+ "ReflectionCardContractError",
563
+ "ReflectionPromptShard",
564
+ "ReflectionShardFailure",
565
+ "ReflectionShardResult",
566
+ "ReflectionWorkflow",
567
+ "ReflectionWorkflowExecutionError",
568
+ "ReflectionWorkflowRequest",
569
+ "ReflectionWorkflowResult",
570
+ "StrictBatchedReflectionWorkflow",
571
+ ]