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,343 @@
1
+ """Atomic, durable filesystem implementation of the artifact-store port."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ import tempfile
7
+ import threading
8
+ from contextlib import contextmanager
9
+ from pathlib import Path
10
+ from typing import Any, Iterator
11
+
12
+ import agent_evolve.domain.artifact as artifact_domain
13
+ from agent_evolve.domain.artifact import ArtifactRef
14
+ from agent_evolve.domain.ids import ArtifactId
15
+ from agent_evolve.infrastructure.artifacts._verification import (
16
+ require_artifact_id,
17
+ require_content_and_media_type,
18
+ verify_content,
19
+ verify_expected_media_type,
20
+ )
21
+ from agent_evolve.ports.artifact_store import (
22
+ ArtifactCollisionError,
23
+ ArtifactNotFoundError,
24
+ ArtifactSerializationError,
25
+ ArtifactTypeError,
26
+ CorruptArtifactError,
27
+ canonical_json_bytes,
28
+ decode_json_bytes,
29
+ )
30
+
31
+ try: # pragma: no cover - exercised on Unix CI.
32
+ import fcntl
33
+ except ImportError: # pragma: no cover
34
+ fcntl = None
35
+
36
+ _ARTIFACT_SCHEMA_VERSION = 2
37
+ _MAGIC_LINE = b"AGENT_EVOLVE_ARTIFACT_V2"
38
+ _FILE_SUFFIX = ".artifact"
39
+ _METADATA_KEYS = {
40
+ "artifact_id",
41
+ "media_type",
42
+ "schema_version",
43
+ "sha256_hex",
44
+ "size_bytes",
45
+ }
46
+ _ROOT_LOCKS_GUARD = threading.Lock()
47
+ _ROOT_LOCKS: dict[str, threading.RLock] = {}
48
+
49
+
50
+ def _process_lock_for_root(root: Path) -> threading.RLock:
51
+ """Return one process-global lock for a canonical artifact-store root."""
52
+
53
+ lock_key = os.path.normcase(os.fspath(root))
54
+ with _ROOT_LOCKS_GUARD:
55
+ lock = _ROOT_LOCKS.get(lock_key)
56
+ if lock is None:
57
+ lock = threading.RLock()
58
+ _ROOT_LOCKS[lock_key] = lock
59
+ return lock
60
+
61
+
62
+ class FileSystemArtifactStore:
63
+ """Store one self-verifying ``<artifact_id>.artifact`` file per payload."""
64
+
65
+ def __init__(self, root: str | os.PathLike[str]) -> None:
66
+ requested_root = Path(root).absolute()
67
+ try:
68
+ canonical_parent = requested_root.parent.resolve(strict=True)
69
+ except FileNotFoundError as exc:
70
+ raise FileNotFoundError(
71
+ "Artifact-store parent directory must already exist: "
72
+ f"{requested_root.parent}"
73
+ ) from exc
74
+ if not canonical_parent.is_dir():
75
+ raise NotADirectoryError(
76
+ f"Artifact-store parent is not a directory: {canonical_parent}"
77
+ )
78
+ canonical_root = canonical_parent / requested_root.name
79
+ self._process_lock = _process_lock_for_root(canonical_root)
80
+ with self._process_lock:
81
+ if canonical_root.is_symlink():
82
+ raise ValueError(
83
+ f"Artifact-store root must not be a symlink: {canonical_root}"
84
+ )
85
+ try:
86
+ canonical_root.mkdir(mode=0o700)
87
+ except FileExistsError:
88
+ if canonical_root.is_symlink():
89
+ raise ValueError(
90
+ f"Artifact-store root must not be a symlink: {canonical_root}"
91
+ )
92
+ if not canonical_root.is_dir():
93
+ raise NotADirectoryError(
94
+ f"Artifact-store root is not a directory: {canonical_root}"
95
+ )
96
+ # This is deliberately unconditional: if another process won a
97
+ # concurrent mkdir race, this constructor still establishes that the
98
+ # directory entry is durable before returning.
99
+ self._fsync_directory_path(canonical_parent)
100
+
101
+ resolved_root = canonical_root.resolve(strict=True)
102
+ if resolved_root != canonical_root:
103
+ raise ValueError(
104
+ f"Artifact-store root must resolve to itself: {canonical_root}"
105
+ )
106
+ self.root = resolved_root
107
+ self._lock_path = self.root / ".artifact-store.lock"
108
+ with self._locked():
109
+ self._verify_all_unlocked()
110
+
111
+ def path_for_artifact(self, artifact_id: ArtifactId) -> Path:
112
+ require_artifact_id(artifact_id)
113
+ return self.root / f"{artifact_id.value}{_FILE_SUFFIX}"
114
+
115
+ @contextmanager
116
+ def _locked(self) -> Iterator[None]:
117
+ with self._process_lock:
118
+ if fcntl is None:
119
+ # This remains safe between store instances and threads in this
120
+ # process. Cross-process use requires an available ``flock``.
121
+ yield
122
+ return
123
+ lock_fd = os.open(self._lock_path, os.O_RDWR | os.O_CREAT, 0o600)
124
+ locked = False
125
+ try:
126
+ # Failure is intentionally fail-closed: silently degrading here
127
+ # would make a cross-process deployment appear durable when the
128
+ # underlying filesystem does not support advisory locking.
129
+ fcntl.flock(lock_fd, fcntl.LOCK_EX)
130
+ locked = True
131
+ yield
132
+ finally:
133
+ try:
134
+ if locked:
135
+ fcntl.flock(lock_fd, fcntl.LOCK_UN)
136
+ finally:
137
+ os.close(lock_fd)
138
+
139
+ @staticmethod
140
+ def _metadata_record(ref: ArtifactRef) -> dict[str, Any]:
141
+ return {
142
+ "artifact_id": ref.artifact_id.value,
143
+ "media_type": ref.media_type,
144
+ "schema_version": _ARTIFACT_SCHEMA_VERSION,
145
+ "sha256_hex": ref.sha256_hex,
146
+ "size_bytes": ref.size_bytes,
147
+ }
148
+
149
+ @classmethod
150
+ def _encode_container(cls, ref: ArtifactRef, content: bytes) -> bytes:
151
+ metadata = canonical_json_bytes(cls._metadata_record(ref))
152
+ return _MAGIC_LINE + b"\n" + metadata + b"\n" + content
153
+
154
+ @classmethod
155
+ def _decode_container(
156
+ cls,
157
+ encoded: bytes,
158
+ *,
159
+ path: Path,
160
+ expected_artifact_id: ArtifactId,
161
+ ) -> tuple[ArtifactRef, bytes]:
162
+ parts = encoded.split(b"\n", 2)
163
+ if len(parts) != 3 or parts[0] != _MAGIC_LINE:
164
+ raise CorruptArtifactError(f"Artifact file has an invalid header: {path}")
165
+ raw_metadata, content = parts[1], parts[2]
166
+ try:
167
+ record = decode_json_bytes(raw_metadata)
168
+ except (ArtifactSerializationError, ArtifactTypeError) as exc:
169
+ raise CorruptArtifactError(
170
+ f"Artifact file has malformed metadata: {path}"
171
+ ) from exc
172
+ if not isinstance(record, dict) or set(record) != _METADATA_KEYS:
173
+ raise CorruptArtifactError(
174
+ f"Artifact file has unsupported metadata fields: {path}"
175
+ )
176
+ try:
177
+ canonical_metadata = canonical_json_bytes(record)
178
+ except (ArtifactSerializationError, ArtifactTypeError) as exc:
179
+ raise CorruptArtifactError(
180
+ f"Artifact file metadata cannot be encoded canonically: {path}"
181
+ ) from exc
182
+ if canonical_metadata != raw_metadata:
183
+ raise CorruptArtifactError(
184
+ f"Artifact file metadata is not canonical JSON: {path}"
185
+ )
186
+ schema_version = record["schema_version"]
187
+ if (
188
+ isinstance(schema_version, bool)
189
+ or not isinstance(schema_version, int)
190
+ or schema_version != _ARTIFACT_SCHEMA_VERSION
191
+ ):
192
+ raise CorruptArtifactError(
193
+ f"Artifact file has an unsupported schema version: {path}"
194
+ )
195
+ try:
196
+ ref = ArtifactRef(
197
+ artifact_id=ArtifactId(record["artifact_id"]),
198
+ sha256_hex=record["sha256_hex"],
199
+ size_bytes=record["size_bytes"],
200
+ media_type=record["media_type"],
201
+ )
202
+ except (TypeError, ValueError) as exc:
203
+ raise CorruptArtifactError(
204
+ f"Artifact file metadata violates the schema: {path}"
205
+ ) from exc
206
+ if ref.artifact_id != expected_artifact_id:
207
+ raise CorruptArtifactError(
208
+ f"Artifact file name does not match its metadata: {path}"
209
+ )
210
+ verify_content(ref, content)
211
+ return ref, content
212
+
213
+ def _read_path_unlocked(
214
+ self,
215
+ path: Path,
216
+ *,
217
+ expected_artifact_id: ArtifactId,
218
+ ) -> tuple[ArtifactRef, bytes]:
219
+ if path.is_symlink() or not path.is_file():
220
+ raise CorruptArtifactError(f"Artifact path is not a regular file: {path}")
221
+ try:
222
+ encoded = path.read_bytes()
223
+ except OSError as exc:
224
+ raise CorruptArtifactError(f"Artifact file cannot be read: {path}") from exc
225
+ return self._decode_container(
226
+ encoded,
227
+ path=path,
228
+ expected_artifact_id=expected_artifact_id,
229
+ )
230
+
231
+ def _verified_unlocked(self, artifact_id: ArtifactId) -> tuple[ArtifactRef, bytes]:
232
+ require_artifact_id(artifact_id)
233
+ path = self.path_for_artifact(artifact_id)
234
+ if not path.exists() and not path.is_symlink():
235
+ raise ArtifactNotFoundError(f"Artifact {artifact_id} was not found")
236
+ return self._read_path_unlocked(path, expected_artifact_id=artifact_id)
237
+
238
+ def _verify_all_unlocked(self) -> None:
239
+ for path in sorted(self.root.glob(f"*{_FILE_SUFFIX}")):
240
+ serialized_id = path.name[: -len(_FILE_SUFFIX)]
241
+ try:
242
+ artifact_id = ArtifactId(serialized_id)
243
+ except (TypeError, ValueError) as exc:
244
+ raise CorruptArtifactError(
245
+ f"Artifact file has an invalid content-addressed name: {path}"
246
+ ) from exc
247
+ self._read_path_unlocked(path, expected_artifact_id=artifact_id)
248
+
249
+ @staticmethod
250
+ def _write_all(fd: int, content: bytes) -> None:
251
+ view = memoryview(content)
252
+ while view:
253
+ written = os.write(fd, view)
254
+ if written <= 0: # pragma: no cover - defensive OS failure guard.
255
+ raise OSError("zero-byte write while persisting artifact")
256
+ view = view[written:]
257
+
258
+ @staticmethod
259
+ def _fsync_directory_path(path: Path) -> None:
260
+ if os.name != "posix": # pragma: no cover - directory fsync is POSIX-only.
261
+ return
262
+ flags = os.O_RDONLY | getattr(os, "O_DIRECTORY", 0)
263
+ fd = os.open(path, flags)
264
+ try:
265
+ os.fsync(fd)
266
+ finally:
267
+ os.close(fd)
268
+
269
+ def _fsync_root_directory(self) -> None:
270
+ self._fsync_directory_path(self.root)
271
+
272
+ def _atomic_write_unlocked(self, path: Path, encoded: bytes) -> None:
273
+ fd, temporary_name = tempfile.mkstemp(
274
+ dir=self.root,
275
+ prefix=".artifact-write-",
276
+ suffix=".tmp",
277
+ )
278
+ temporary_path = Path(temporary_name)
279
+ try:
280
+ self._write_all(fd, encoded)
281
+ os.fsync(fd)
282
+ os.close(fd)
283
+ fd = -1
284
+ os.replace(temporary_path, path)
285
+ self._fsync_root_directory()
286
+ finally:
287
+ if fd >= 0:
288
+ os.close(fd)
289
+ try:
290
+ temporary_path.unlink()
291
+ except FileNotFoundError:
292
+ pass
293
+
294
+ def put_bytes(self, content: bytes, *, media_type: str) -> ArtifactRef:
295
+ require_content_and_media_type(content, media_type)
296
+ ref = artifact_domain.artifact_ref_for_bytes(content, media_type=media_type)
297
+ path = self.path_for_artifact(ref.artifact_id)
298
+ with self._locked():
299
+ if path.exists() or path.is_symlink():
300
+ existing_ref, existing_content = self._read_path_unlocked(
301
+ path,
302
+ expected_artifact_id=ref.artifact_id,
303
+ )
304
+ if existing_content != content:
305
+ raise ArtifactCollisionError(
306
+ f"Different payload bytes resolved to {ref.artifact_id}"
307
+ )
308
+ if existing_ref.media_type != media_type:
309
+ raise ArtifactCollisionError(
310
+ f"Different media types resolved to {ref.artifact_id}"
311
+ )
312
+ # A previous attempt may have completed its atomic rename but
313
+ # reported failure while syncing the directory. Re-syncing here
314
+ # makes an idempotent retry a durability-recovery operation.
315
+ self._fsync_root_directory()
316
+ return existing_ref
317
+
318
+ self._atomic_write_unlocked(path, self._encode_container(ref, content))
319
+ persisted_ref, persisted_content = self._read_path_unlocked(
320
+ path,
321
+ expected_artifact_id=ref.artifact_id,
322
+ )
323
+ if persisted_ref != ref or persisted_content != content:
324
+ raise CorruptArtifactError(
325
+ f"Artifact {ref.artifact_id} did not verify after persistence"
326
+ )
327
+ return persisted_ref
328
+
329
+ def stat(self, artifact_id: ArtifactId) -> ArtifactRef:
330
+ with self._locked():
331
+ ref, _ = self._verified_unlocked(artifact_id)
332
+ return ref
333
+
334
+ def read_bytes(
335
+ self,
336
+ artifact_id: ArtifactId,
337
+ *,
338
+ expected_media_type: str | None = None,
339
+ ) -> bytes:
340
+ with self._locked():
341
+ ref, content = self._verified_unlocked(artifact_id)
342
+ verify_expected_media_type(ref, expected_media_type)
343
+ return content
@@ -0,0 +1,73 @@
1
+ """Thread-safe in-memory content-addressed artifact store."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import threading
6
+
7
+ import agent_evolve.domain.artifact as artifact_domain
8
+ from agent_evolve.domain.artifact import ArtifactRef
9
+ from agent_evolve.domain.ids import ArtifactId
10
+ from agent_evolve.infrastructure.artifacts._verification import (
11
+ require_artifact_id,
12
+ require_content_and_media_type,
13
+ verify_content,
14
+ verify_expected_media_type,
15
+ )
16
+ from agent_evolve.ports.artifact_store import (
17
+ ArtifactCollisionError,
18
+ ArtifactNotFoundError,
19
+ )
20
+
21
+
22
+ class InMemoryArtifactStore:
23
+ """Verified ephemeral store used by tests and non-durable runs."""
24
+
25
+ def __init__(self) -> None:
26
+ self._artifacts: dict[ArtifactId, tuple[ArtifactRef, bytes]] = {}
27
+ self._lock = threading.RLock()
28
+
29
+ def put_bytes(self, content: bytes, *, media_type: str) -> ArtifactRef:
30
+ require_content_and_media_type(content, media_type)
31
+ ref = artifact_domain.artifact_ref_for_bytes(content, media_type=media_type)
32
+ with self._lock:
33
+ existing = self._artifacts.get(ref.artifact_id)
34
+ if existing is None:
35
+ self._artifacts[ref.artifact_id] = (ref, content)
36
+ return ref
37
+
38
+ existing_ref, existing_content = existing
39
+ verify_content(existing_ref, existing_content)
40
+ if existing_content != content:
41
+ raise ArtifactCollisionError(
42
+ f"Different payload bytes resolved to {ref.artifact_id}"
43
+ )
44
+ if existing_ref.media_type != media_type:
45
+ raise ArtifactCollisionError(
46
+ f"Different media types resolved to {ref.artifact_id}"
47
+ )
48
+ return existing_ref
49
+
50
+ def _verified(self, artifact_id: ArtifactId) -> tuple[ArtifactRef, bytes]:
51
+ require_artifact_id(artifact_id)
52
+ existing = self._artifacts.get(artifact_id)
53
+ if existing is None:
54
+ raise ArtifactNotFoundError(f"Artifact {artifact_id} was not found")
55
+ ref, content = existing
56
+ verify_content(ref, content)
57
+ return ref, content
58
+
59
+ def stat(self, artifact_id: ArtifactId) -> ArtifactRef:
60
+ with self._lock:
61
+ ref, _ = self._verified(artifact_id)
62
+ return ref
63
+
64
+ def read_bytes(
65
+ self,
66
+ artifact_id: ArtifactId,
67
+ *,
68
+ expected_media_type: str | None = None,
69
+ ) -> bytes:
70
+ with self._lock:
71
+ ref, content = self._verified(artifact_id)
72
+ verify_expected_media_type(ref, expected_media_type)
73
+ return content
@@ -0,0 +1,109 @@
1
+ """Asyncio timing adapter for the provider-neutral LLM task queue."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ from collections.abc import Awaitable, Callable
7
+ from contextlib import suppress
8
+ from typing import TypeVar
9
+
10
+ from agent_evolve.domain.llm_task_queue import NANOSECONDS_PER_SECOND
11
+ from agent_evolve.ports.llm_task_queue import ExecutorRetiredError
12
+
13
+
14
+ AwaitedT = TypeVar("AwaitedT")
15
+
16
+
17
+ class TransportAbortedTimeoutError(TimeoutError, ExecutorRetiredError):
18
+ """The deadline expired and the owned transport was retired cleanly.
19
+
20
+ Unlike a plain ``TimeoutError``, this condition cannot be retried on the
21
+ same provider executor: its transport has deliberately been closed to
22
+ guarantee that the timed-out request is no longer live.
23
+ """
24
+
25
+
26
+ class AsyncioRuntime:
27
+ """Own real sleeps and timeout containment outside provider adapters.
28
+
29
+ ``asyncio.wait_for`` is not a hard wall-clock bound: after its deadline it
30
+ cancels the child and waits indefinitely for cancellation cleanup. A
31
+ provider stack may legitimately shield transport cleanup, which leaves the
32
+ queue unable to publish a timeout. When an owned ``timeout_abort`` is
33
+ supplied, this runtime instead observes the deadline, cancels the attempt,
34
+ closes its transport, and drains the attempt before returning a terminal
35
+ :class:`TransportAbortedTimeoutError`.
36
+
37
+ The abort callback must be idempotent and must retire every external
38
+ operation reachable from the awaitable. Production composition binds it
39
+ to the owned provider client's asynchronous close operation.
40
+ """
41
+
42
+ def __init__(
43
+ self,
44
+ *,
45
+ timeout_abort: Callable[[], Awaitable[None]] | None = None,
46
+ ) -> None:
47
+ if timeout_abort is not None and not callable(timeout_abort):
48
+ raise TypeError("timeout_abort must be callable or None")
49
+ self._timeout_abort = timeout_abort
50
+
51
+ async def sleep(self, delay_ns: int) -> None:
52
+ if type(delay_ns) is not int or delay_ns < 0:
53
+ raise ValueError("delay_ns must be a non-negative integer")
54
+ await asyncio.sleep(delay_ns / NANOSECONDS_PER_SECOND)
55
+
56
+ async def wait_for(
57
+ self,
58
+ awaitable: Awaitable[AwaitedT],
59
+ timeout_ns: int | None,
60
+ ) -> AwaitedT:
61
+ if timeout_ns is not None and (
62
+ type(timeout_ns) is not int or timeout_ns <= 0
63
+ ):
64
+ raise ValueError("timeout_ns must be a positive integer or None")
65
+ if self._timeout_abort is None:
66
+ if timeout_ns is None:
67
+ return await awaitable
68
+ return await asyncio.wait_for(
69
+ awaitable,
70
+ timeout=timeout_ns / NANOSECONDS_PER_SECOND,
71
+ )
72
+
73
+ attempt = asyncio.ensure_future(awaitable)
74
+ try:
75
+ if timeout_ns is None:
76
+ return await attempt
77
+ done, _ = await asyncio.wait(
78
+ (attempt,),
79
+ timeout=timeout_ns / NANOSECONDS_PER_SECOND,
80
+ return_when=asyncio.ALL_COMPLETED,
81
+ )
82
+ except asyncio.CancelledError:
83
+ await self._abort_and_drain(attempt)
84
+ raise
85
+
86
+ if done:
87
+ return attempt.result()
88
+
89
+ await self._abort_and_drain(attempt)
90
+ raise TransportAbortedTimeoutError from None
91
+
92
+ async def _abort_and_drain(self, attempt: "asyncio.Future[object]") -> None:
93
+ """Retire external I/O and leave no child attempt behind."""
94
+
95
+ attempt.cancel()
96
+ abort_error: BaseException | None = None
97
+ try:
98
+ assert self._timeout_abort is not None
99
+ await self._timeout_abort()
100
+ except BaseException as error: # retain cleanup, never provider text
101
+ abort_error = error
102
+
103
+ with suppress(BaseException):
104
+ await attempt
105
+
106
+ if not attempt.done(): # defensive: awaited futures must be terminal
107
+ raise RuntimeError("timed-out attempt did not reach a terminal state")
108
+ if abort_error is not None:
109
+ raise RuntimeError("timed-out attempt transport abort failed") from None