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.
- agent_evolve/__init__.py +722 -0
- agent_evolve/agentic.py +2800 -0
- agent_evolve/api.py +767 -0
- agent_evolve/application/__init__.py +1580 -0
- agent_evolve/application/action_allocation.py +744 -0
- agent_evolve/application/action_allocation_frame.py +347 -0
- agent_evolve/application/action_allocation_frame_commit.py +185 -0
- agent_evolve/application/action_allocation_frame_commit_v3.py +184 -0
- agent_evolve/application/action_allocation_frame_v3.py +338 -0
- agent_evolve/application/action_archive_value.py +497 -0
- agent_evolve/application/action_evidence_consistency.py +455 -0
- agent_evolve/application/action_forecast_partitioning.py +1471 -0
- agent_evolve/application/action_metric_projection.py +211 -0
- agent_evolve/application/action_role_value.py +680 -0
- agent_evolve/application/action_score_authorities.py +363 -0
- agent_evolve/application/action_structural_signature.py +116 -0
- agent_evolve/application/action_target_realization.py +402 -0
- agent_evolve/application/agentic_evolution.py +7734 -0
- agent_evolve/application/agentic_portfolio_residual_expert.py +835 -0
- agent_evolve/application/anchor_residual_identification.py +463 -0
- agent_evolve/application/archive_conditioned_action_target.py +208 -0
- agent_evolve/application/artifact_journal.py +246 -0
- agent_evolve/application/artifact_replay.py +347 -0
- agent_evolve/application/budgeted_optimizer.py +1828 -0
- agent_evolve/application/calibrated_campaign.py +485 -0
- agent_evolve/application/calibrated_current_prefix_forecast_opportunity.py +322 -0
- agent_evolve/application/calibrated_positive_gain_opportunity.py +1581 -0
- agent_evolve/application/campaign_capacity_recourse.py +254 -0
- agent_evolve/application/campaign_contextual_outcomes.py +119 -0
- agent_evolve/application/campaign_diagnostic_blocks.py +930 -0
- agent_evolve/application/campaign_evidence_registry.py +262 -0
- agent_evolve/application/campaign_execution.py +2537 -0
- agent_evolve/application/campaign_generation_audit.py +942 -0
- agent_evolve/application/campaign_learning.py +1812 -0
- agent_evolve/application/campaign_learning_runtime.py +1977 -0
- agent_evolve/application/campaign_search_phase.py +227 -0
- agent_evolve/application/campaign_selector_context_extension.py +220 -0
- agent_evolve/application/campaign_variation_envelope.py +649 -0
- agent_evolve/application/campaign_variation_trace.py +451 -0
- agent_evolve/application/candidate_archive_consequence.py +128 -0
- agent_evolve/application/causal_opportunity_portfolio_gate.py +385 -0
- agent_evolve/application/composite_outcome_updater.py +145 -0
- agent_evolve/application/composition_portfolio_selection.py +363 -0
- agent_evolve/application/concurrent_stage.py +144 -0
- agent_evolve/application/contextual_action_allocation.py +181 -0
- agent_evolve/application/contextual_campaign_outcomes.py +267 -0
- agent_evolve/application/contextual_campaign_planning.py +1366 -0
- agent_evolve/application/contextual_delayed_credit.py +651 -0
- agent_evolve/application/contextual_search_controller.py +2374 -0
- agent_evolve/application/current_prefix_forecast_opportunity.py +714 -0
- agent_evolve/application/decision_metric_projection.py +112 -0
- agent_evolve/application/derived_action_semantics.py +129 -0
- agent_evolve/application/detailed_evaluation.py +449 -0
- agent_evolve/application/earned_lineage.py +1011 -0
- agent_evolve/application/effective_choice_audit.py +484 -0
- agent_evolve/application/empirical_consequence_calibration.py +908 -0
- agent_evolve/application/evaluation_accounting.py +325 -0
- agent_evolve/application/evaluation_cache.py +199 -0
- agent_evolve/application/evaluation_escrow.py +547 -0
- agent_evolve/application/evaluation_recourse.py +253 -0
- agent_evolve/application/event_recorder.py +151 -0
- agent_evolve/application/evolution_campaign.py +1840 -0
- agent_evolve/application/executable_hypothesis.py +323 -0
- agent_evolve/application/factorial_branch_pilot.py +772 -0
- agent_evolve/application/finite_acquisition_capacity_recourse.py +672 -0
- agent_evolve/application/finite_acquisition_residual_expert.py +373 -0
- agent_evolve/application/finite_acquisition_variation_envelope.py +802 -0
- agent_evolve/application/finite_action_hypothesis_semantics.py +446 -0
- agent_evolve/application/finite_action_selection.py +188 -0
- agent_evolve/application/finite_action_set.py +306 -0
- agent_evolve/application/finite_action_transition.py +537 -0
- agent_evolve/application/finite_variation_eligibility.py +296 -0
- agent_evolve/application/forecast_geometry_portfolio.py +799 -0
- agent_evolve/application/forecast_opportunity_shadow_calibration.py +316 -0
- agent_evolve/application/front_proximity_admission.py +311 -0
- agent_evolve/application/front_proximity_parent_basis.py +458 -0
- agent_evolve/application/frozen_hurdle_score.py +659 -0
- agent_evolve/application/g3_causal_screen.py +2257 -0
- agent_evolve/application/g3_causal_validation.py +1046 -0
- agent_evolve/application/g3_postseal_curation.py +818 -0
- agent_evolve/application/gated_agentic_generator.py +205 -0
- agent_evolve/application/generation_feedback.py +293 -0
- agent_evolve/application/generative_proposal_journal.py +185 -0
- agent_evolve/application/geometry_conditional_elasticity.py +453 -0
- agent_evolve/application/global_wave_action_allocation.py +1151 -0
- agent_evolve/application/head_mass_conditional_seat.py +268 -0
- agent_evolve/application/identifiable_reflection_evidence.py +1147 -0
- agent_evolve/application/identifiable_reflection_learning.py +395 -0
- agent_evolve/application/identifiable_reflection_request.py +364 -0
- agent_evolve/application/in_memory_residual_archive.py +341 -0
- agent_evolve/application/insight_memory.py +1804 -0
- agent_evolve/application/live_runtime_manifest.py +758 -0
- agent_evolve/application/llm_task_queue.py +769 -0
- agent_evolve/application/matched_finite_action_block.py +409 -0
- agent_evolve/application/materialized_action_broker.py +2328 -0
- agent_evolve/application/materialized_action_constraints.py +83 -0
- agent_evolve/application/materialized_variation.py +211 -0
- agent_evolve/application/multi_option_evolution.py +1536 -0
- agent_evolve/application/outcome_adaptive_action_racing.py +2827 -0
- agent_evolve/application/outcome_adaptive_residual_campaign_runtime.py +580 -0
- agent_evolve/application/outcome_adaptive_residual_portfolio_evolution.py +3671 -0
- agent_evolve/application/outcome_conditioned_portfolio_selection.py +1374 -0
- agent_evolve/application/outcome_relation.py +193 -0
- agent_evolve/application/paired_allocation_comparison.py +241 -0
- agent_evolve/application/paired_block_schedule.py +127 -0
- agent_evolve/application/parent_measurement.py +226 -0
- agent_evolve/application/pareto_archive.py +811 -0
- agent_evolve/application/portfolio_campaign_runtime.py +4739 -0
- agent_evolve/application/portfolio_evolution.py +2950 -0
- agent_evolve/application/portfolio_hypothesis_observations.py +814 -0
- agent_evolve/application/portfolio_memory_attribution.py +581 -0
- agent_evolve/application/portfolio_memory_dose.py +788 -0
- agent_evolve/application/portfolio_memory_matched_control.py +938 -0
- agent_evolve/application/portfolio_memory_transfer.py +297 -0
- agent_evolve/application/portfolio_optimization_memory.py +363 -0
- agent_evolve/application/portfolio_outcome_feedback.py +1613 -0
- agent_evolve/application/portfolio_projection.py +335 -0
- agent_evolve/application/portfolio_recombination.py +2032 -0
- agent_evolve/application/post_evolution_reflection.py +834 -0
- agent_evolve/application/postcommit_rank_authority.py +245 -0
- agent_evolve/application/precommitted_portfolio_racing.py +2762 -0
- agent_evolve/application/prequential_archive_opportunity_calibration.py +1154 -0
- agent_evolve/application/prequential_residual_exploration.py +343 -0
- agent_evolve/application/prequential_score_portfolio.py +954 -0
- agent_evolve/application/projections.py +292 -0
- agent_evolve/application/protected_action_committee.py +1027 -0
- agent_evolve/application/protected_branch_pilot.py +376 -0
- agent_evolve/application/protected_current_prefix_forecast_opportunity.py +552 -0
- agent_evolve/application/provider_replay.py +910 -0
- agent_evolve/application/rank_balanced_causal_pilot.py +1372 -0
- agent_evolve/application/recombination_residual_expert.py +403 -0
- agent_evolve/application/reflection_workflow.py +571 -0
- agent_evolve/application/region_conditional_credit.py +911 -0
- agent_evolve/application/residual_campaign_runtime.py +531 -0
- agent_evolve/application/residual_headroom_campaign_runtime.py +459 -0
- agent_evolve/application/residual_headroom_ledger.py +1544 -0
- agent_evolve/application/residual_learning_transaction.py +396 -0
- agent_evolve/application/residual_portfolio_evolution.py +1228 -0
- agent_evolve/application/residual_reachability.py +749 -0
- agent_evolve/application/residual_stage_credit.py +499 -0
- agent_evolve/application/same_prefix_paired_audit.py +1580 -0
- agent_evolve/application/semantic_coverage_score_portfolio.py +838 -0
- agent_evolve/application/sequential_lineage_allocation.py +1017 -0
- agent_evolve/application/sequential_market_replay.py +1395 -0
- agent_evolve/application/sequential_residual_campaign_runtime.py +305 -0
- agent_evolve/application/sequential_residual_portfolio_evolution.py +940 -0
- agent_evolve/application/single_score_action_allocation.py +299 -0
- agent_evolve/application/source_exposure_allocation.py +906 -0
- agent_evolve/application/staged_memory.py +210 -0
- agent_evolve/application/stratified_cold_start_allocation.py +732 -0
- agent_evolve/application/support_guarded_hurdle_score.py +549 -0
- agent_evolve/application/target_conditioned_action_forecast.py +595 -0
- agent_evolve/application/target_conditioned_campaign.py +566 -0
- agent_evolve/application/treatment_assignment.py +201 -0
- agent_evolve/application/trusted_objective_evidence.py +217 -0
- agent_evolve/application/two_stage_action_evolution.py +1131 -0
- agent_evolve/application/v8lite_allocation_policy.py +1083 -0
- agent_evolve/application/v9_candidate_policy.py +1303 -0
- agent_evolve/bootstrap.py +108 -0
- agent_evolve/campaign_presets.py +517 -0
- agent_evolve/campaign_profiles.py +452 -0
- agent_evolve/campaign_variation_topology.py +288 -0
- agent_evolve/campaign_workload.py +950 -0
- agent_evolve/cli.py +797 -0
- agent_evolve/contract.py +241 -0
- agent_evolve/core/__init__.py +91 -0
- agent_evolve/core/action_semantics.py +411 -0
- agent_evolve/core/authored.py +105 -0
- agent_evolve/core/formatting.py +286 -0
- agent_evolve/core/optimization_semantics.py +324 -0
- agent_evolve/core/problem.py +167 -0
- agent_evolve/core/results.py +323 -0
- agent_evolve/core/stats.py +70 -0
- agent_evolve/core/telemetry.py +100 -0
- agent_evolve/domain/__init__.py +89 -0
- agent_evolve/domain/artifact.py +162 -0
- agent_evolve/domain/durable_text.py +68 -0
- agent_evolve/domain/event.py +1454 -0
- agent_evolve/domain/finite_action_set.py +426 -0
- agent_evolve/domain/finite_variation.py +526 -0
- agent_evolve/domain/generative_emission.py +559 -0
- agent_evolve/domain/ids.py +163 -0
- agent_evolve/domain/inline_text.py +106 -0
- agent_evolve/domain/insight.py +27 -0
- agent_evolve/domain/lineage.py +737 -0
- agent_evolve/domain/llm_task_queue.py +960 -0
- agent_evolve/domain/outcome.py +96 -0
- agent_evolve/domain/patch.py +854 -0
- agent_evolve/domain/typed_json.py +542 -0
- agent_evolve/domain/variation_space.py +158 -0
- agent_evolve/driver.py +1014 -0
- agent_evolve/harness/__init__.py +29 -0
- agent_evolve/harness/base.py +242 -0
- agent_evolve/harness/directives.py +163 -0
- agent_evolve/harness/generative_seal.py +479 -0
- agent_evolve/harness/registry.py +41 -0
- agent_evolve/infrastructure/__init__.py +39 -0
- agent_evolve/infrastructure/artifacts/__init__.py +6 -0
- agent_evolve/infrastructure/artifacts/_verification.py +67 -0
- agent_evolve/infrastructure/artifacts/filesystem.py +343 -0
- agent_evolve/infrastructure/artifacts/in_memory.py +73 -0
- agent_evolve/infrastructure/asyncio_runtime.py +109 -0
- agent_evolve/infrastructure/authored_runtime.py +188 -0
- agent_evolve/infrastructure/authored_worker.py +171 -0
- agent_evolve/infrastructure/clock.py +53 -0
- agent_evolve/infrastructure/events/__init__.py +6 -0
- agent_evolve/infrastructure/events/_validation.py +89 -0
- agent_evolve/infrastructure/events/in_memory.py +56 -0
- agent_evolve/infrastructure/events/jsonl.py +193 -0
- agent_evolve/infrastructure/exception_provenance.py +215 -0
- agent_evolve/infrastructure/ids.py +118 -0
- agent_evolve/infrastructure/lineage_codec.py +1836 -0
- agent_evolve/infrastructure/outcome_adaptive_phase_journal.py +170 -0
- agent_evolve/infrastructure/residual_headroom_journal.py +221 -0
- agent_evolve/infrastructure/resource_lease.py +370 -0
- agent_evolve/infrastructure/sanitization/__init__.py +8 -0
- agent_evolve/infrastructure/sanitization/strict_json.py +484 -0
- agent_evolve/infrastructure/sequential_phase_journal.py +170 -0
- agent_evolve/infrastructure/stream_liveness.py +383 -0
- agent_evolve/infrastructure/subprocess_boundary.py +136 -0
- agent_evolve/integrations/__init__.py +1 -0
- agent_evolve/integrations/botorch/__init__.py +28 -0
- agent_evolve/integrations/botorch/finite_qlognehvi.py +190 -0
- agent_evolve/integrations/botorch/finite_qlognehvi_batch.py +155 -0
- agent_evolve/integrations/botorch/finite_qlognehvi_batch_identity.py +20 -0
- agent_evolve/integrations/botorch/finite_qlognehvi_batch_worker.py +55 -0
- agent_evolve/integrations/botorch/finite_qlognehvi_identity.py +22 -0
- agent_evolve/integrations/botorch/finite_qlognehvi_worker.py +55 -0
- agent_evolve/integrations/botorch/subprocess_qlognehvi.py +261 -0
- agent_evolve/integrations/botorch/subprocess_qlognehvi_batch.py +273 -0
- agent_evolve/integrations/completion.py +242 -0
- agent_evolve/integrations/pydantic_ai/__init__.py +441 -0
- agent_evolve/integrations/pydantic_ai/action_forecast.py +1068 -0
- agent_evolve/integrations/pydantic_ai/agentic_generator.py +2308 -0
- agent_evolve/integrations/pydantic_ai/async_generator.py +1604 -0
- agent_evolve/integrations/pydantic_ai/boundary_codec.py +1526 -0
- agent_evolve/integrations/pydantic_ai/calibrated_portfolio_campaign.py +756 -0
- agent_evolve/integrations/pydantic_ai/calibrated_portfolio_selection.py +7537 -0
- agent_evolve/integrations/pydantic_ai/campaign_acquisition.py +609 -0
- agent_evolve/integrations/pydantic_ai/execution_binding.py +138 -0
- agent_evolve/integrations/pydantic_ai/forecast_geometry_action_committee.py +217 -0
- agent_evolve/integrations/pydantic_ai/harness.py +159 -0
- agent_evolve/integrations/pydantic_ai/heterogeneous_model_execution.py +306 -0
- agent_evolve/integrations/pydantic_ai/hierarchical_residual_adaptive_semantic_view.py +179 -0
- agent_evolve/integrations/pydantic_ai/json_schema_dialect.py +108 -0
- agent_evolve/integrations/pydantic_ai/materialized_hierarchical_residual_expert.py +952 -0
- agent_evolve/integrations/pydantic_ai/materialized_portfolio_judge.py +520 -0
- agent_evolve/integrations/pydantic_ai/model_execution_profile.py +659 -0
- agent_evolve/integrations/pydantic_ai/outbound_request_manifest.py +1170 -0
- agent_evolve/integrations/pydantic_ai/portable_residual_consequence_features.py +575 -0
- agent_evolve/integrations/pydantic_ai/portfolio_selection.py +422 -0
- agent_evolve/integrations/pydantic_ai/progress_aware_openrouter.py +416 -0
- agent_evolve/integrations/pydantic_ai/provider_attempt_join.py +1523 -0
- agent_evolve/integrations/pydantic_ai/provider_free_calibrated_runner.py +607 -0
- agent_evolve/integrations/pydantic_ai/queued_runner.py +2634 -0
- agent_evolve/integrations/pydantic_ai/reconciled_residual_reachability.py +1417 -0
- agent_evolve/integrations/pydantic_ai/residual_forecast_geometry.py +445 -0
- agent_evolve/integrations/pydantic_ai/residual_reachability.py +674 -0
- agent_evolve/integrations/pydantic_ai/residual_semantic_cells.py +239 -0
- agent_evolve/integrations/pydantic_ai/sealed_output_replay.py +1068 -0
- agent_evolve/integrations/pydantic_ai/semantic_coverage_residual_portfolio.py +770 -0
- agent_evolve/integrations/pydantic_ai/semantic_decision_replay.py +383 -0
- agent_evolve/integrations/pydantic_ai/support_adaptive_residual_portfolio.py +135 -0
- agent_evolve/integrations/pydantic_ai/trusted_residual_prompt_context.py +143 -0
- agent_evolve/integrations/pydantic_ai/validated_openrouter_model.py +107 -0
- agent_evolve/integrations/pymoo_adapter.py +242 -0
- agent_evolve/policies/__init__.py +17 -0
- agent_evolve/policies/check.py +469 -0
- agent_evolve/policies/emit_scaffold.py +451 -0
- agent_evolve/policies/feedback/__init__.py +37 -0
- agent_evolve/policies/feedback/held_out_asn.py +1325 -0
- agent_evolve/policies/genetic.py +607 -0
- agent_evolve/policies/llm_backoff.py +183 -0
- agent_evolve/policies/llm_chooser.py +226 -0
- agent_evolve/policies/llm_generator.py +1760 -0
- agent_evolve/policies/llm_init.py +267 -0
- agent_evolve/policies/llm_operator.py +109 -0
- agent_evolve/policies/llm_prior.py +194 -0
- agent_evolve/policies/llm_surrogate.py +334 -0
- agent_evolve/policies/measurement_evidence.py +704 -0
- agent_evolve/policies/memory/__init__.py +223 -0
- agent_evolve/policies/memory/balanced_subset_blocks.py +707 -0
- agent_evolve/policies/memory/compatibility_matching.py +593 -0
- agent_evolve/policies/memory/global_falsification.py +1841 -0
- agent_evolve/policies/memory/prompt_shape.py +503 -0
- agent_evolve/policies/memory/randomized_subset.py +714 -0
- agent_evolve/policies/memory/staged_causal.py +1270 -0
- agent_evolve/policies/memory/treatment_compliance.py +759 -0
- agent_evolve/policies/objective_resolution/__init__.py +17 -0
- agent_evolve/policies/objective_resolution/fixed_grid.py +364 -0
- agent_evolve/policies/operator_portfolio.py +407 -0
- agent_evolve/policies/reguidance.py +1133 -0
- agent_evolve/policies/reward/__init__.py +83 -0
- agent_evolve/policies/reward/affine_candidate_consequence.py +156 -0
- agent_evolve/policies/reward/affine_candidate_consequence_3d.py +159 -0
- agent_evolve/policies/reward/affine_hypervolume.py +490 -0
- agent_evolve/policies/reward/affine_hypervolume_3d.py +567 -0
- agent_evolve/policies/reward/contextual_marginal_utility.py +318 -0
- agent_evolve/policies/reward/frozen_archive.py +360 -0
- agent_evolve/policies/reward/frozen_wave_archive.py +368 -0
- agent_evolve/policies/search_state.py +208 -0
- agent_evolve/policies/selection/__init__.py +345 -0
- agent_evolve/policies/selection/acquisition_certified_slate.py +684 -0
- agent_evolve/policies/selection/affine_frontier_context.py +330 -0
- agent_evolve/policies/selection/affine_frontier_target.py +473 -0
- agent_evolve/policies/selection/archive_elite.py +1346 -0
- agent_evolve/policies/selection/calibrated_portfolio_binding.py +640 -0
- agent_evolve/policies/selection/calibrated_slate.py +1394 -0
- agent_evolve/policies/selection/calibrated_slate_codec.py +579 -0
- agent_evolve/policies/selection/common_candidate_pool.py +685 -0
- agent_evolve/policies/selection/diagnostic_sampling.py +319 -0
- agent_evolve/policies/selection/disjoint_pairs.py +479 -0
- agent_evolve/policies/selection/elite_explorer.py +719 -0
- agent_evolve/policies/selection/finite_action.py +187 -0
- agent_evolve/policies/selection/finite_option_prompt_projection.py +377 -0
- agent_evolve/policies/selection/finite_palette_evidence.py +247 -0
- agent_evolve/policies/selection/forecast_calibration.py +922 -0
- agent_evolve/policies/selection/frontier_probe_slate.py +814 -0
- agent_evolve/policies/selection/frozen_archive_pairs.py +762 -0
- agent_evolve/policies/selection/full_support_slate.py +91 -0
- agent_evolve/policies/selection/meaningful_direction.py +240 -0
- agent_evolve/policies/selection/memory_dose_feasibility.py +259 -0
- agent_evolve/policies/selection/model_anchored_slate.py +826 -0
- agent_evolve/policies/selection/phenotype_recourse.py +979 -0
- agent_evolve/policies/selection/proposal_support.py +368 -0
- agent_evolve/policies/selection/random_portfolio.py +254 -0
- agent_evolve/policies/selection/regret_bounded_slate.py +1084 -0
- agent_evolve/policies/selection/residual_frontier.py +463 -0
- agent_evolve/policies/selection/residual_frontier_target.py +605 -0
- agent_evolve/policies/selection/structural_posterior_slate.py +1571 -0
- agent_evolve/policies/selection/target_conditioned_allocator.py +648 -0
- agent_evolve/policies/selection/target_conditioned_features.py +812 -0
- agent_evolve/policies/selection/target_conditioned_prequential.py +1527 -0
- agent_evolve/policies/selection/task_keyed_palette.py +906 -0
- agent_evolve/policies/semantics.py +147 -0
- agent_evolve/policies/structure.py +362 -0
- agent_evolve/policies/structured_output_budget.py +62 -0
- agent_evolve/policies/surrogate.py +696 -0
- agent_evolve/policies/variation/__init__.py +1 -0
- agent_evolve/policies/variation/compositional_finite_catalog.py +426 -0
- agent_evolve/policies/variation/crossover_inheritance.py +575 -0
- agent_evolve/policies/variation/disjoint_recombination.py +611 -0
- agent_evolve/policies/variation/exact_composition_capacity.py +214 -0
- agent_evolve/policies/variation/exact_parent_crossover.py +950 -0
- agent_evolve/policies/variation/multiscale_restart_catalog.py +372 -0
- agent_evolve/policies/variation/source_union_finite_catalog.py +403 -0
- agent_evolve/policies/variation/typed_patch.py +1981 -0
- agent_evolve/policies/weighted_prior.py +394 -0
- agent_evolve/ports/__init__.py +383 -0
- agent_evolve/ports/action_allocation.py +733 -0
- agent_evolve/ports/action_allocation_frame.py +1153 -0
- agent_evolve/ports/action_allocation_frame_commit.py +294 -0
- agent_evolve/ports/action_allocation_frame_commit_v3.py +432 -0
- agent_evolve/ports/action_allocation_frame_v3.py +995 -0
- agent_evolve/ports/action_forecast.py +1568 -0
- agent_evolve/ports/action_metric_projection.py +165 -0
- agent_evolve/ports/agentic_generator.py +1561 -0
- agent_evolve/ports/archive_context.py +136 -0
- agent_evolve/ports/artifact_sanitizer.py +44 -0
- agent_evolve/ports/artifact_store.py +225 -0
- agent_evolve/ports/clock.py +13 -0
- agent_evolve/ports/contextual_search_allocation.py +827 -0
- agent_evolve/ports/decision_metric_projection.py +258 -0
- agent_evolve/ports/event_store.py +55 -0
- agent_evolve/ports/executable_hypothesis.py +557 -0
- agent_evolve/ports/finite_acquisition.py +377 -0
- agent_evolve/ports/finite_acquisition_batch.py +296 -0
- agent_evolve/ports/finite_acquisition_batch_json.py +164 -0
- agent_evolve/ports/finite_acquisition_json.py +247 -0
- agent_evolve/ports/finite_acquisition_space.py +168 -0
- agent_evolve/ports/finite_action_selection.py +348 -0
- agent_evolve/ports/finite_action_set.py +256 -0
- agent_evolve/ports/frontier_target.py +396 -0
- agent_evolve/ports/generation_failure.py +43 -0
- agent_evolve/ports/hard_feasibility.py +233 -0
- agent_evolve/ports/id_factory.py +34 -0
- agent_evolve/ports/llm_task_queue.py +93 -0
- agent_evolve/ports/objective_resolution.py +419 -0
- agent_evolve/ports/paired_allocation_comparison.py +401 -0
- agent_evolve/ports/paired_block_schedule.py +475 -0
- agent_evolve/ports/parent_measurement.py +336 -0
- agent_evolve/ports/portfolio_memory_dose.py +643 -0
- agent_evolve/ports/portfolio_selection.py +3169 -0
- agent_evolve/ports/postcommit_rank_authority.py +467 -0
- agent_evolve/ports/presented_action_evidence.py +794 -0
- agent_evolve/ports/resource_lease.py +162 -0
- agent_evolve/ports/structured_generator.py +734 -0
- agent_evolve/ports/structured_output_budget.py +120 -0
- agent_evolve/ports/subprocess_boundary.py +138 -0
- agent_evolve/ports/treatment_assignment.py +466 -0
- agent_evolve/ports/variation_catalog.py +76 -0
- agent_evolve/ports/variation_source.py +226 -0
- agent_evolve/proposal_mode.py +157 -0
- agent_evolve/proposers/__init__.py +10 -0
- agent_evolve/proposers/random_proposer.py +188 -0
- agent_evolve/provider_accounting.py +163 -0
- agent_evolve/py.typed +0 -0
- agent_evolve/reference_method.py +1570 -0
- agent_evolve/session/__init__.py +11 -0
- agent_evolve/session/authorship.py +864 -0
- agent_evolve/session/evaluate.py +236 -0
- agent_evolve/session/fidelity.py +237 -0
- agent_evolve/session/genetic_loop.py +742 -0
- agent_evolve/session/loop.py +803 -0
- agent_evolve/session/screening.py +671 -0
- agent_evolve/settings.py +376 -0
- agent_evolve/workload_kit.py +368 -0
- agent_evolve/workload_prompt.py +398 -0
- agentevolve_optimizer-0.5.0.dist-info/METADATA +599 -0
- agentevolve_optimizer-0.5.0.dist-info/RECORD +414 -0
- agentevolve_optimizer-0.5.0.dist-info/WHEEL +5 -0
- agentevolve_optimizer-0.5.0.dist-info/entry_points.txt +2 -0
- agentevolve_optimizer-0.5.0.dist-info/licenses/LICENSE +21 -0
- agentevolve_optimizer-0.5.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
"""Workload-neutral ask/tell boundary for finite black-box acquisition.
|
|
2
|
+
|
|
3
|
+
The core optimizer owns no feature encoding and no configuration materializer.
|
|
4
|
+
A workload adapter exposes a finite set of already legal candidate identities
|
|
5
|
+
and normalized feature rows. An optional acquisition integration selects a
|
|
6
|
+
batch by identity; trusted adapter code maps those identities back to sealed
|
|
7
|
+
configurations. This permits Bayesian, evolutionary, and learned acquisition
|
|
8
|
+
experts to share one boundary without importing workload schemas into the
|
|
9
|
+
application layer.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import hashlib
|
|
15
|
+
import json
|
|
16
|
+
import math
|
|
17
|
+
import re
|
|
18
|
+
from dataclasses import dataclass, field
|
|
19
|
+
from typing import Protocol, runtime_checkable
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
_TOKEN = re.compile(r"^[A-Za-z0-9][A-Za-z0-9_.:/-]{0,511}$")
|
|
23
|
+
_REQUEST_DOMAIN = b"agent-evolve:finite-acquisition-request:v1\x00"
|
|
24
|
+
_DECISION_DOMAIN = b"agent-evolve:finite-acquisition-decision:v1\x00"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _canonical_json(value: object) -> bytes:
|
|
28
|
+
return json.dumps(
|
|
29
|
+
value,
|
|
30
|
+
allow_nan=False,
|
|
31
|
+
ensure_ascii=True,
|
|
32
|
+
separators=(",", ":"),
|
|
33
|
+
sort_keys=True,
|
|
34
|
+
).encode("ascii", errors="strict")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _require_token(value: str, *, name: str) -> None:
|
|
38
|
+
if type(value) is not str or _TOKEN.fullmatch(value) is None:
|
|
39
|
+
raise ValueError(f"{name} must use the closed token grammar")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _require_sha256(value: str, *, name: str) -> None:
|
|
43
|
+
if (
|
|
44
|
+
type(value) is not str
|
|
45
|
+
or len(value) != 64
|
|
46
|
+
or any(character not in "0123456789abcdef" for character in value)
|
|
47
|
+
):
|
|
48
|
+
raise ValueError(f"{name} must be a lowercase SHA-256")
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _finite(value: float, *, name: str) -> None:
|
|
52
|
+
if type(value) is not float or not math.isfinite(value):
|
|
53
|
+
raise TypeError(f"{name} must be a finite canonical float")
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@dataclass(frozen=True, slots=True)
|
|
57
|
+
class FiniteAcquisitionObjective:
|
|
58
|
+
"""One raw objective and the fixed affine frame used by acquisition."""
|
|
59
|
+
|
|
60
|
+
metric_id: str
|
|
61
|
+
sense: str
|
|
62
|
+
ideal: float
|
|
63
|
+
reference: float
|
|
64
|
+
|
|
65
|
+
def __post_init__(self) -> None:
|
|
66
|
+
_require_token(self.metric_id, name="metric_id")
|
|
67
|
+
if self.sense not in ("min", "max"):
|
|
68
|
+
raise ValueError("sense must be 'min' or 'max'")
|
|
69
|
+
_finite(self.ideal, name="ideal")
|
|
70
|
+
_finite(self.reference, name="reference")
|
|
71
|
+
if self.ideal == self.reference:
|
|
72
|
+
raise ValueError("ideal and reference must be distinct")
|
|
73
|
+
if self.sense == "min" and self.ideal >= self.reference:
|
|
74
|
+
raise ValueError("minimization ideal must be below reference")
|
|
75
|
+
if self.sense == "max" and self.ideal <= self.reference:
|
|
76
|
+
raise ValueError("maximization ideal must be above reference")
|
|
77
|
+
|
|
78
|
+
def maximize_value(self, raw_value: float) -> float:
|
|
79
|
+
"""Map the fixed reference to zero and the ideal to one."""
|
|
80
|
+
|
|
81
|
+
self.__post_init__()
|
|
82
|
+
_finite(raw_value, name="raw_value")
|
|
83
|
+
if self.sense == "min":
|
|
84
|
+
return (self.reference - raw_value) / (self.reference - self.ideal)
|
|
85
|
+
return (raw_value - self.reference) / (self.ideal - self.reference)
|
|
86
|
+
|
|
87
|
+
def to_record(self) -> dict[str, object]:
|
|
88
|
+
self.__post_init__()
|
|
89
|
+
return {
|
|
90
|
+
"metric_id": self.metric_id,
|
|
91
|
+
"sense": self.sense,
|
|
92
|
+
"ideal_hex": self.ideal.hex(),
|
|
93
|
+
"reference_hex": self.reference.hex(),
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@dataclass(frozen=True, slots=True)
|
|
98
|
+
class FiniteAcquisitionCandidate:
|
|
99
|
+
"""One legal candidate row; the configuration remains adapter-owned."""
|
|
100
|
+
|
|
101
|
+
candidate_id: str
|
|
102
|
+
configuration_sha256: str
|
|
103
|
+
features: tuple[float, ...]
|
|
104
|
+
|
|
105
|
+
def __post_init__(self) -> None:
|
|
106
|
+
_require_token(self.candidate_id, name="candidate_id")
|
|
107
|
+
_require_sha256(self.configuration_sha256, name="configuration_sha256")
|
|
108
|
+
if type(self.features) is not tuple or not self.features:
|
|
109
|
+
raise ValueError("features must be a non-empty exact tuple")
|
|
110
|
+
for value in self.features:
|
|
111
|
+
_finite(value, name="feature")
|
|
112
|
+
if not 0.0 <= value <= 1.0:
|
|
113
|
+
raise ValueError("features must lie in [0,1]")
|
|
114
|
+
|
|
115
|
+
def to_record(self) -> dict[str, object]:
|
|
116
|
+
self.__post_init__()
|
|
117
|
+
return {
|
|
118
|
+
"candidate_id": self.candidate_id,
|
|
119
|
+
"configuration_sha256": self.configuration_sha256,
|
|
120
|
+
"features_hex": [value.hex() for value in self.features],
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@dataclass(frozen=True, slots=True)
|
|
125
|
+
class FiniteAcquisitionObservation:
|
|
126
|
+
"""One prior real-evaluator result in the same feature frame."""
|
|
127
|
+
|
|
128
|
+
candidate_id: str
|
|
129
|
+
configuration_sha256: str
|
|
130
|
+
features: tuple[float, ...]
|
|
131
|
+
objectives: tuple[tuple[str, float], ...]
|
|
132
|
+
|
|
133
|
+
def __post_init__(self) -> None:
|
|
134
|
+
FiniteAcquisitionCandidate(
|
|
135
|
+
candidate_id=self.candidate_id,
|
|
136
|
+
configuration_sha256=self.configuration_sha256,
|
|
137
|
+
features=self.features,
|
|
138
|
+
)
|
|
139
|
+
if type(self.objectives) is not tuple or not self.objectives:
|
|
140
|
+
raise ValueError("objectives must be a non-empty exact tuple")
|
|
141
|
+
metric_ids: list[str] = []
|
|
142
|
+
for metric_id, value in self.objectives:
|
|
143
|
+
_require_token(metric_id, name="objective metric_id")
|
|
144
|
+
_finite(value, name="objective value")
|
|
145
|
+
metric_ids.append(metric_id)
|
|
146
|
+
if tuple(metric_ids) != tuple(sorted(set(metric_ids))):
|
|
147
|
+
raise ValueError("objectives must be unique and metric-sorted")
|
|
148
|
+
|
|
149
|
+
def to_record(self) -> dict[str, object]:
|
|
150
|
+
self.__post_init__()
|
|
151
|
+
return {
|
|
152
|
+
"candidate_id": self.candidate_id,
|
|
153
|
+
"configuration_sha256": self.configuration_sha256,
|
|
154
|
+
"features_hex": [value.hex() for value in self.features],
|
|
155
|
+
"objectives": [
|
|
156
|
+
{"metric_id": metric_id, "value_hex": value.hex()}
|
|
157
|
+
for metric_id, value in self.objectives
|
|
158
|
+
],
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
@dataclass(frozen=True, slots=True, eq=False)
|
|
163
|
+
class FiniteAcquisitionRequest:
|
|
164
|
+
"""Immutable finite-pool ask request at one authenticated cutoff."""
|
|
165
|
+
|
|
166
|
+
campaign_scope_sha256: str
|
|
167
|
+
cutoff_index: int
|
|
168
|
+
batch_size: int
|
|
169
|
+
seed: int
|
|
170
|
+
objectives: tuple[FiniteAcquisitionObjective, ...]
|
|
171
|
+
observations: tuple[FiniteAcquisitionObservation, ...]
|
|
172
|
+
candidates: tuple[FiniteAcquisitionCandidate, ...]
|
|
173
|
+
request_sha256: str = field(init=False, default="")
|
|
174
|
+
|
|
175
|
+
def __post_init__(self) -> None:
|
|
176
|
+
_require_sha256(self.campaign_scope_sha256, name="campaign_scope_sha256")
|
|
177
|
+
if type(self.cutoff_index) is not int or self.cutoff_index < 1:
|
|
178
|
+
raise ValueError("cutoff_index must be positive")
|
|
179
|
+
if type(self.batch_size) is not int or self.batch_size < 1:
|
|
180
|
+
raise ValueError("batch_size must be positive")
|
|
181
|
+
if type(self.seed) is not int or self.seed < 0:
|
|
182
|
+
raise ValueError("seed must be a non-negative exact integer")
|
|
183
|
+
if type(self.objectives) is not tuple or len(self.objectives) < 2:
|
|
184
|
+
raise ValueError("multi-objective acquisition requires at least two axes")
|
|
185
|
+
for axis in self.objectives:
|
|
186
|
+
if type(axis) is not FiniteAcquisitionObjective:
|
|
187
|
+
raise TypeError("objectives must contain exact axes")
|
|
188
|
+
axis.__post_init__()
|
|
189
|
+
metric_ids = tuple(axis.metric_id for axis in self.objectives)
|
|
190
|
+
if metric_ids != tuple(sorted(set(metric_ids))):
|
|
191
|
+
raise ValueError("objective axes must be unique and metric-sorted")
|
|
192
|
+
if type(self.observations) is not tuple or not self.observations:
|
|
193
|
+
raise ValueError("observations must be a non-empty exact tuple")
|
|
194
|
+
if type(self.candidates) is not tuple or len(self.candidates) < self.batch_size:
|
|
195
|
+
raise ValueError("candidate pool cannot underfill the requested batch")
|
|
196
|
+
dimensions: set[int] = set()
|
|
197
|
+
observed_ids: set[str] = set()
|
|
198
|
+
observed_hashes: set[str] = set()
|
|
199
|
+
for observation in self.observations:
|
|
200
|
+
if type(observation) is not FiniteAcquisitionObservation:
|
|
201
|
+
raise TypeError("observations must contain exact rows")
|
|
202
|
+
observation.__post_init__()
|
|
203
|
+
if tuple(value[0] for value in observation.objectives) != metric_ids:
|
|
204
|
+
raise ValueError("observation objective axes differ from request")
|
|
205
|
+
dimensions.add(len(observation.features))
|
|
206
|
+
if (
|
|
207
|
+
observation.candidate_id in observed_ids
|
|
208
|
+
or observation.configuration_sha256 in observed_hashes
|
|
209
|
+
):
|
|
210
|
+
raise ValueError("observations must have unique IDs and configurations")
|
|
211
|
+
observed_ids.add(observation.candidate_id)
|
|
212
|
+
observed_hashes.add(observation.configuration_sha256)
|
|
213
|
+
candidate_ids: set[str] = set()
|
|
214
|
+
candidate_hashes: set[str] = set()
|
|
215
|
+
candidate_features: set[tuple[float, ...]] = set()
|
|
216
|
+
for candidate in self.candidates:
|
|
217
|
+
if type(candidate) is not FiniteAcquisitionCandidate:
|
|
218
|
+
raise TypeError("candidates must contain exact rows")
|
|
219
|
+
candidate.__post_init__()
|
|
220
|
+
dimensions.add(len(candidate.features))
|
|
221
|
+
if (
|
|
222
|
+
candidate.candidate_id in candidate_ids
|
|
223
|
+
or candidate.configuration_sha256 in candidate_hashes
|
|
224
|
+
or candidate.features in candidate_features
|
|
225
|
+
):
|
|
226
|
+
raise ValueError("candidate IDs, configurations, and features must be unique")
|
|
227
|
+
if candidate.configuration_sha256 in observed_hashes:
|
|
228
|
+
raise ValueError("candidate pool repeats an evaluated configuration")
|
|
229
|
+
candidate_ids.add(candidate.candidate_id)
|
|
230
|
+
candidate_hashes.add(candidate.configuration_sha256)
|
|
231
|
+
candidate_features.add(candidate.features)
|
|
232
|
+
if len(dimensions) != 1:
|
|
233
|
+
raise ValueError("all feature rows must share one dimension")
|
|
234
|
+
computed = hashlib.sha256(
|
|
235
|
+
_REQUEST_DOMAIN + _canonical_json(self._unsigned_record())
|
|
236
|
+
).hexdigest()
|
|
237
|
+
if self.request_sha256 not in ("", computed):
|
|
238
|
+
raise ValueError("request_sha256 does not authenticate the request")
|
|
239
|
+
object.__setattr__(self, "request_sha256", computed)
|
|
240
|
+
|
|
241
|
+
def _unsigned_record(self) -> dict[str, object]:
|
|
242
|
+
return {
|
|
243
|
+
"schema_version": 1,
|
|
244
|
+
"campaign_scope_sha256": self.campaign_scope_sha256,
|
|
245
|
+
"cutoff_index": self.cutoff_index,
|
|
246
|
+
"batch_size": self.batch_size,
|
|
247
|
+
"seed": self.seed,
|
|
248
|
+
"objectives": [axis.to_record() for axis in self.objectives],
|
|
249
|
+
"observations": [value.to_record() for value in self.observations],
|
|
250
|
+
"candidates": [value.to_record() for value in self.candidates],
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
def to_record(self) -> dict[str, object]:
|
|
254
|
+
self.__post_init__()
|
|
255
|
+
return {**self._unsigned_record(), "request_sha256": self.request_sha256}
|
|
256
|
+
|
|
257
|
+
def __eq__(self, other: object) -> bool:
|
|
258
|
+
return (
|
|
259
|
+
type(other) is FiniteAcquisitionRequest
|
|
260
|
+
and self.request_sha256 == other.request_sha256
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
__hash__ = None
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
@dataclass(frozen=True, slots=True)
|
|
267
|
+
class FiniteAcquisitionSelection:
|
|
268
|
+
candidate_id: str
|
|
269
|
+
configuration_sha256: str
|
|
270
|
+
acquisition_value: float
|
|
271
|
+
|
|
272
|
+
def __post_init__(self) -> None:
|
|
273
|
+
_require_token(self.candidate_id, name="candidate_id")
|
|
274
|
+
_require_sha256(self.configuration_sha256, name="configuration_sha256")
|
|
275
|
+
_finite(self.acquisition_value, name="acquisition_value")
|
|
276
|
+
|
|
277
|
+
def to_record(self) -> dict[str, object]:
|
|
278
|
+
self.__post_init__()
|
|
279
|
+
return {
|
|
280
|
+
"candidate_id": self.candidate_id,
|
|
281
|
+
"configuration_sha256": self.configuration_sha256,
|
|
282
|
+
"acquisition_value_hex": self.acquisition_value.hex(),
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
@dataclass(frozen=True, slots=True, eq=False)
|
|
287
|
+
class FiniteAcquisitionDecision:
|
|
288
|
+
request_sha256: str
|
|
289
|
+
policy_id: str
|
|
290
|
+
policy_version: int
|
|
291
|
+
policy_definition_sha256: str
|
|
292
|
+
selected: tuple[FiniteAcquisitionSelection, ...]
|
|
293
|
+
diagnostics: tuple[tuple[str, str], ...] = ()
|
|
294
|
+
decision_sha256: str = field(init=False, default="")
|
|
295
|
+
|
|
296
|
+
def __post_init__(self) -> None:
|
|
297
|
+
_require_sha256(self.request_sha256, name="request_sha256")
|
|
298
|
+
_require_token(self.policy_id, name="policy_id")
|
|
299
|
+
if type(self.policy_version) is not int or self.policy_version < 1:
|
|
300
|
+
raise ValueError("policy_version must be positive")
|
|
301
|
+
_require_sha256(
|
|
302
|
+
self.policy_definition_sha256,
|
|
303
|
+
name="policy_definition_sha256",
|
|
304
|
+
)
|
|
305
|
+
if type(self.selected) is not tuple or not self.selected:
|
|
306
|
+
raise ValueError("selected must be a non-empty exact tuple")
|
|
307
|
+
for value in self.selected:
|
|
308
|
+
if type(value) is not FiniteAcquisitionSelection:
|
|
309
|
+
raise TypeError("selected must contain exact rows")
|
|
310
|
+
value.__post_init__()
|
|
311
|
+
if len({value.candidate_id for value in self.selected}) != len(self.selected):
|
|
312
|
+
raise ValueError("selected candidates must be unique")
|
|
313
|
+
if type(self.diagnostics) is not tuple:
|
|
314
|
+
raise TypeError("diagnostics must be an exact tuple")
|
|
315
|
+
diagnostic_keys: list[str] = []
|
|
316
|
+
for key, value in self.diagnostics:
|
|
317
|
+
_require_token(key, name="diagnostic key")
|
|
318
|
+
if type(value) is not str or not value.isascii():
|
|
319
|
+
raise ValueError("diagnostic values must be ASCII strings")
|
|
320
|
+
diagnostic_keys.append(key)
|
|
321
|
+
if tuple(diagnostic_keys) != tuple(sorted(set(diagnostic_keys))):
|
|
322
|
+
raise ValueError("diagnostics must be unique and key-sorted")
|
|
323
|
+
computed = hashlib.sha256(
|
|
324
|
+
_DECISION_DOMAIN + _canonical_json(self._unsigned_record())
|
|
325
|
+
).hexdigest()
|
|
326
|
+
if self.decision_sha256 not in ("", computed):
|
|
327
|
+
raise ValueError("decision_sha256 does not authenticate the decision")
|
|
328
|
+
object.__setattr__(self, "decision_sha256", computed)
|
|
329
|
+
|
|
330
|
+
def _unsigned_record(self) -> dict[str, object]:
|
|
331
|
+
return {
|
|
332
|
+
"schema_version": 1,
|
|
333
|
+
"request_sha256": self.request_sha256,
|
|
334
|
+
"policy": {
|
|
335
|
+
"policy_id": self.policy_id,
|
|
336
|
+
"policy_version": self.policy_version,
|
|
337
|
+
"definition_sha256": self.policy_definition_sha256,
|
|
338
|
+
},
|
|
339
|
+
"selected": [value.to_record() for value in self.selected],
|
|
340
|
+
"diagnostics": [
|
|
341
|
+
{"key": key, "value": value} for key, value in self.diagnostics
|
|
342
|
+
],
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
def to_record(self) -> dict[str, object]:
|
|
346
|
+
self.__post_init__()
|
|
347
|
+
return {**self._unsigned_record(), "decision_sha256": self.decision_sha256}
|
|
348
|
+
|
|
349
|
+
def __eq__(self, other: object) -> bool:
|
|
350
|
+
return (
|
|
351
|
+
type(other) is FiniteAcquisitionDecision
|
|
352
|
+
and self.decision_sha256 == other.decision_sha256
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
__hash__ = None
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
@runtime_checkable
|
|
359
|
+
class FiniteAcquisitionPolicy(Protocol):
|
|
360
|
+
"""Select identities from a sealed legal pool using prior observations."""
|
|
361
|
+
|
|
362
|
+
policy_id: str
|
|
363
|
+
policy_version: int
|
|
364
|
+
definition_sha256: str
|
|
365
|
+
|
|
366
|
+
def select(self, request: FiniteAcquisitionRequest) -> FiniteAcquisitionDecision: ...
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
__all__ = [
|
|
370
|
+
"FiniteAcquisitionCandidate",
|
|
371
|
+
"FiniteAcquisitionDecision",
|
|
372
|
+
"FiniteAcquisitionObjective",
|
|
373
|
+
"FiniteAcquisitionObservation",
|
|
374
|
+
"FiniteAcquisitionPolicy",
|
|
375
|
+
"FiniteAcquisitionRequest",
|
|
376
|
+
"FiniteAcquisitionSelection",
|
|
377
|
+
]
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
"""Workload-neutral scoring boundary for finite acquisition slates.
|
|
2
|
+
|
|
3
|
+
The ordinary finite-acquisition port asks a numerical optimizer to construct a
|
|
4
|
+
batch. AgentEvolve also needs a stricter comparison primitive: score several
|
|
5
|
+
already-enumerated, equally sized slates under one fitted model and one Monte
|
|
6
|
+
Carlo draw. Keeping that operation behind a port lets an application policy
|
|
7
|
+
retain an incumbent optimizer slate while testing agent-proposed alternatives
|
|
8
|
+
without importing BoTorch or a workload schema into the core.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import hashlib
|
|
14
|
+
import json
|
|
15
|
+
import math
|
|
16
|
+
import re
|
|
17
|
+
from dataclasses import dataclass, field
|
|
18
|
+
from typing import Protocol, runtime_checkable
|
|
19
|
+
|
|
20
|
+
from agent_evolve.domain.patch import require_sha256
|
|
21
|
+
from agent_evolve.ports.finite_acquisition import (
|
|
22
|
+
FiniteAcquisitionCandidate,
|
|
23
|
+
FiniteAcquisitionObjective,
|
|
24
|
+
FiniteAcquisitionObservation,
|
|
25
|
+
FiniteAcquisitionRequest,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
_TOKEN = re.compile(r"^[A-Za-z0-9][A-Za-z0-9_.:/-]{0,511}$")
|
|
30
|
+
_REQUEST_DOMAIN = b"agent-evolve:finite-acquisition-batch-score-request:v1\x00"
|
|
31
|
+
_DECISION_DOMAIN = b"agent-evolve:finite-acquisition-batch-score-decision:v1\x00"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _canonical_json(value: object) -> bytes:
|
|
35
|
+
return json.dumps(
|
|
36
|
+
value,
|
|
37
|
+
allow_nan=False,
|
|
38
|
+
ensure_ascii=True,
|
|
39
|
+
separators=(",", ":"),
|
|
40
|
+
sort_keys=True,
|
|
41
|
+
).encode("ascii", errors="strict")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _require_token(value: str, *, name: str) -> None:
|
|
45
|
+
if type(value) is not str or _TOKEN.fullmatch(value) is None:
|
|
46
|
+
raise ValueError(f"{name} must use the closed token grammar")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _finite(value: float, *, name: str) -> None:
|
|
50
|
+
if type(value) is not float or not math.isfinite(value):
|
|
51
|
+
raise TypeError(f"{name} must be a finite exact float")
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@dataclass(frozen=True, slots=True)
|
|
55
|
+
class FiniteAcquisitionSlate:
|
|
56
|
+
"""One unordered, canonical candidate-ID set to score jointly."""
|
|
57
|
+
|
|
58
|
+
candidate_ids: tuple[str, ...]
|
|
59
|
+
|
|
60
|
+
def __post_init__(self) -> None:
|
|
61
|
+
if type(self.candidate_ids) is not tuple or not self.candidate_ids:
|
|
62
|
+
raise ValueError("candidate_ids must be a non-empty exact tuple")
|
|
63
|
+
for value in self.candidate_ids:
|
|
64
|
+
_require_token(value, name="candidate_id")
|
|
65
|
+
if self.candidate_ids != tuple(sorted(set(self.candidate_ids))):
|
|
66
|
+
raise ValueError("candidate_ids must be unique and canonical")
|
|
67
|
+
|
|
68
|
+
def to_record(self) -> dict[str, object]:
|
|
69
|
+
self.__post_init__()
|
|
70
|
+
return {"candidate_ids": list(self.candidate_ids)}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@dataclass(frozen=True, slots=True, eq=False)
|
|
74
|
+
class FiniteAcquisitionBatchScoreRequest:
|
|
75
|
+
"""Score a sealed family of equal-cardinality finite slates."""
|
|
76
|
+
|
|
77
|
+
campaign_scope_sha256: str
|
|
78
|
+
cutoff_index: int
|
|
79
|
+
seed: int
|
|
80
|
+
objectives: tuple[FiniteAcquisitionObjective, ...]
|
|
81
|
+
observations: tuple[FiniteAcquisitionObservation, ...]
|
|
82
|
+
candidates: tuple[FiniteAcquisitionCandidate, ...]
|
|
83
|
+
slates: tuple[FiniteAcquisitionSlate, ...]
|
|
84
|
+
request_sha256: str = field(init=False, default="")
|
|
85
|
+
|
|
86
|
+
def __post_init__(self) -> None:
|
|
87
|
+
require_sha256(self.campaign_scope_sha256, "campaign_scope_sha256")
|
|
88
|
+
if type(self.cutoff_index) is not int or self.cutoff_index < 1:
|
|
89
|
+
raise ValueError("cutoff_index must be positive")
|
|
90
|
+
if type(self.seed) is not int or self.seed < 0:
|
|
91
|
+
raise ValueError("seed must be a non-negative exact integer")
|
|
92
|
+
if type(self.slates) is not tuple or not self.slates:
|
|
93
|
+
raise ValueError("slates must be a non-empty exact tuple")
|
|
94
|
+
for value in self.slates:
|
|
95
|
+
if type(value) is not FiniteAcquisitionSlate:
|
|
96
|
+
raise TypeError("slates must contain exact finite slates")
|
|
97
|
+
value.__post_init__()
|
|
98
|
+
if self.slates != tuple(
|
|
99
|
+
sorted(set(self.slates), key=lambda value: value.candidate_ids)
|
|
100
|
+
):
|
|
101
|
+
raise ValueError("slates must be unique and canonically ordered")
|
|
102
|
+
widths = {len(value.candidate_ids) for value in self.slates}
|
|
103
|
+
if len(widths) != 1:
|
|
104
|
+
raise ValueError("all acquisition slates must have one cardinality")
|
|
105
|
+
batch_size = next(iter(widths))
|
|
106
|
+
# Reuse the ordinary ask boundary as the single validation law for
|
|
107
|
+
# objectives, observations, features, and candidate uniqueness.
|
|
108
|
+
base = FiniteAcquisitionRequest(
|
|
109
|
+
campaign_scope_sha256=self.campaign_scope_sha256,
|
|
110
|
+
cutoff_index=self.cutoff_index,
|
|
111
|
+
batch_size=batch_size,
|
|
112
|
+
seed=self.seed,
|
|
113
|
+
objectives=self.objectives,
|
|
114
|
+
observations=self.observations,
|
|
115
|
+
candidates=self.candidates,
|
|
116
|
+
)
|
|
117
|
+
available = {value.candidate_id for value in base.candidates}
|
|
118
|
+
if any(not set(value.candidate_ids) <= available for value in self.slates):
|
|
119
|
+
raise ValueError("an acquisition slate escapes the sealed candidate pool")
|
|
120
|
+
computed = hashlib.sha256(
|
|
121
|
+
_REQUEST_DOMAIN + _canonical_json(self._unsigned_record())
|
|
122
|
+
).hexdigest()
|
|
123
|
+
if self.request_sha256 not in ("", computed):
|
|
124
|
+
raise ValueError("request_sha256 does not authenticate the request")
|
|
125
|
+
object.__setattr__(self, "request_sha256", computed)
|
|
126
|
+
|
|
127
|
+
@property
|
|
128
|
+
def batch_size(self) -> int:
|
|
129
|
+
return len(self.slates[0].candidate_ids)
|
|
130
|
+
|
|
131
|
+
@property
|
|
132
|
+
def base_request(self) -> FiniteAcquisitionRequest:
|
|
133
|
+
"""The ordinary finite-acquisition inputs shared by every slate."""
|
|
134
|
+
|
|
135
|
+
return FiniteAcquisitionRequest(
|
|
136
|
+
campaign_scope_sha256=self.campaign_scope_sha256,
|
|
137
|
+
cutoff_index=self.cutoff_index,
|
|
138
|
+
batch_size=self.batch_size,
|
|
139
|
+
seed=self.seed,
|
|
140
|
+
objectives=self.objectives,
|
|
141
|
+
observations=self.observations,
|
|
142
|
+
candidates=self.candidates,
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
def _unsigned_record(self) -> dict[str, object]:
|
|
146
|
+
return {
|
|
147
|
+
"schema_version": 1,
|
|
148
|
+
"base_request": self.base_request.to_record(),
|
|
149
|
+
"slates": [value.to_record() for value in self.slates],
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
def to_record(self) -> dict[str, object]:
|
|
153
|
+
self.__post_init__()
|
|
154
|
+
return {**self._unsigned_record(), "request_sha256": self.request_sha256}
|
|
155
|
+
|
|
156
|
+
def __eq__(self, other: object) -> bool:
|
|
157
|
+
return (
|
|
158
|
+
type(other) is FiniteAcquisitionBatchScoreRequest
|
|
159
|
+
and self.request_sha256 == other.request_sha256
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
__hash__ = None
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
@dataclass(frozen=True, slots=True)
|
|
166
|
+
class FiniteAcquisitionSlateScore:
|
|
167
|
+
slate: FiniteAcquisitionSlate
|
|
168
|
+
log_acquisition_value: float
|
|
169
|
+
|
|
170
|
+
def __post_init__(self) -> None:
|
|
171
|
+
if type(self.slate) is not FiniteAcquisitionSlate:
|
|
172
|
+
raise TypeError("slate must be an exact FiniteAcquisitionSlate")
|
|
173
|
+
self.slate.__post_init__()
|
|
174
|
+
_finite(self.log_acquisition_value, name="log_acquisition_value")
|
|
175
|
+
|
|
176
|
+
def to_record(self) -> dict[str, object]:
|
|
177
|
+
self.__post_init__()
|
|
178
|
+
return {
|
|
179
|
+
"slate": self.slate.to_record(),
|
|
180
|
+
"log_acquisition_value_hex": self.log_acquisition_value.hex(),
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
@dataclass(frozen=True, slots=True, eq=False)
|
|
185
|
+
class FiniteAcquisitionBatchScoreDecision:
|
|
186
|
+
request_sha256: str
|
|
187
|
+
policy_id: str
|
|
188
|
+
policy_version: int
|
|
189
|
+
policy_definition_sha256: str
|
|
190
|
+
scores: tuple[FiniteAcquisitionSlateScore, ...]
|
|
191
|
+
diagnostics: tuple[tuple[str, str], ...] = ()
|
|
192
|
+
decision_sha256: str = field(init=False, default="")
|
|
193
|
+
|
|
194
|
+
def __post_init__(self) -> None:
|
|
195
|
+
require_sha256(self.request_sha256, "request_sha256")
|
|
196
|
+
_require_token(self.policy_id, name="policy_id")
|
|
197
|
+
if type(self.policy_version) is not int or self.policy_version < 1:
|
|
198
|
+
raise ValueError("policy_version must be positive")
|
|
199
|
+
require_sha256(
|
|
200
|
+
self.policy_definition_sha256,
|
|
201
|
+
"policy_definition_sha256",
|
|
202
|
+
)
|
|
203
|
+
if type(self.scores) is not tuple or not self.scores:
|
|
204
|
+
raise ValueError("scores must be a non-empty exact tuple")
|
|
205
|
+
for value in self.scores:
|
|
206
|
+
if type(value) is not FiniteAcquisitionSlateScore:
|
|
207
|
+
raise TypeError("scores must contain exact slate scores")
|
|
208
|
+
value.__post_init__()
|
|
209
|
+
slates = tuple(value.slate for value in self.scores)
|
|
210
|
+
if slates != tuple(sorted(set(slates), key=lambda value: value.candidate_ids)):
|
|
211
|
+
raise ValueError("score slates must be unique and canonical")
|
|
212
|
+
if type(self.diagnostics) is not tuple:
|
|
213
|
+
raise TypeError("diagnostics must be an exact tuple")
|
|
214
|
+
keys: list[str] = []
|
|
215
|
+
for key, value in self.diagnostics:
|
|
216
|
+
_require_token(key, name="diagnostic key")
|
|
217
|
+
if type(value) is not str or not value.isascii():
|
|
218
|
+
raise ValueError("diagnostic values must be ASCII strings")
|
|
219
|
+
keys.append(key)
|
|
220
|
+
if tuple(keys) != tuple(sorted(set(keys))):
|
|
221
|
+
raise ValueError("diagnostics must be unique and key-sorted")
|
|
222
|
+
computed = hashlib.sha256(
|
|
223
|
+
_DECISION_DOMAIN + _canonical_json(self._unsigned_record())
|
|
224
|
+
).hexdigest()
|
|
225
|
+
if self.decision_sha256 not in ("", computed):
|
|
226
|
+
raise ValueError("decision_sha256 does not authenticate the decision")
|
|
227
|
+
object.__setattr__(self, "decision_sha256", computed)
|
|
228
|
+
|
|
229
|
+
def _unsigned_record(self) -> dict[str, object]:
|
|
230
|
+
return {
|
|
231
|
+
"schema_version": 1,
|
|
232
|
+
"request_sha256": self.request_sha256,
|
|
233
|
+
"policy": {
|
|
234
|
+
"policy_id": self.policy_id,
|
|
235
|
+
"policy_version": self.policy_version,
|
|
236
|
+
"definition_sha256": self.policy_definition_sha256,
|
|
237
|
+
},
|
|
238
|
+
"scores": [value.to_record() for value in self.scores],
|
|
239
|
+
"diagnostics": [
|
|
240
|
+
{"key": key, "value": value} for key, value in self.diagnostics
|
|
241
|
+
],
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
def to_record(self) -> dict[str, object]:
|
|
245
|
+
self.__post_init__()
|
|
246
|
+
return {**self._unsigned_record(), "decision_sha256": self.decision_sha256}
|
|
247
|
+
|
|
248
|
+
def __eq__(self, other: object) -> bool:
|
|
249
|
+
return (
|
|
250
|
+
type(other) is FiniteAcquisitionBatchScoreDecision
|
|
251
|
+
and self.decision_sha256 == other.decision_sha256
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
__hash__ = None
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def validate_finite_acquisition_batch_score_decision(
|
|
258
|
+
request: FiniteAcquisitionBatchScoreRequest,
|
|
259
|
+
decision: FiniteAcquisitionBatchScoreDecision,
|
|
260
|
+
) -> None:
|
|
261
|
+
"""Require exact coverage of every requested slate and policy binding."""
|
|
262
|
+
|
|
263
|
+
if type(request) is not FiniteAcquisitionBatchScoreRequest:
|
|
264
|
+
raise TypeError("request must be exact")
|
|
265
|
+
request.__post_init__()
|
|
266
|
+
if type(decision) is not FiniteAcquisitionBatchScoreDecision:
|
|
267
|
+
raise TypeError("decision must be exact")
|
|
268
|
+
decision.__post_init__()
|
|
269
|
+
if decision.request_sha256 != request.request_sha256:
|
|
270
|
+
raise ValueError("batch-score decision targets another request")
|
|
271
|
+
if tuple(value.slate for value in decision.scores) != request.slates:
|
|
272
|
+
raise ValueError("batch-score decision must cover every requested slate")
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
@runtime_checkable
|
|
276
|
+
class FiniteAcquisitionBatchScorePolicy(Protocol):
|
|
277
|
+
"""Score fixed slates under one past-only acquisition realization."""
|
|
278
|
+
|
|
279
|
+
policy_id: str
|
|
280
|
+
policy_version: int
|
|
281
|
+
definition_sha256: str
|
|
282
|
+
|
|
283
|
+
def score(
|
|
284
|
+
self,
|
|
285
|
+
request: FiniteAcquisitionBatchScoreRequest,
|
|
286
|
+
) -> FiniteAcquisitionBatchScoreDecision: ...
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
__all__ = [
|
|
290
|
+
"FiniteAcquisitionBatchScoreDecision",
|
|
291
|
+
"FiniteAcquisitionBatchScorePolicy",
|
|
292
|
+
"FiniteAcquisitionBatchScoreRequest",
|
|
293
|
+
"FiniteAcquisitionSlate",
|
|
294
|
+
"FiniteAcquisitionSlateScore",
|
|
295
|
+
"validate_finite_acquisition_batch_score_decision",
|
|
296
|
+
]
|