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,147 @@
|
|
|
1
|
+
"""What the model is told things MEAN. One renderer, shared by every prompt.
|
|
2
|
+
|
|
3
|
+
The program's own trace-first findings (I7) showed information-channel
|
|
4
|
+
defects masquerading as capability failures: an objective traded against but
|
|
5
|
+
never rendered, grids shown as bare number lists. The structural channel
|
|
6
|
+
(names, domains, directions) was always faithful; the SEMANTIC channel --
|
|
7
|
+
what a parameter is, what an objective measures, what the evaluator does --
|
|
8
|
+
had no carrier at all. This module is that carrier.
|
|
9
|
+
|
|
10
|
+
Sources, all harvested rather than invented, all optional, all already
|
|
11
|
+
writable by a problem author today:
|
|
12
|
+
|
|
13
|
+
- ``search_space_description()`` (existing optional method), else the
|
|
14
|
+
problem class docstring, else the candidate model's docstring -- the
|
|
15
|
+
domain in prose;
|
|
16
|
+
- ``evaluate``'s docstring -- what an evaluation actually runs;
|
|
17
|
+
- ``ObjectiveSpec.description`` -- what each objective measures;
|
|
18
|
+
- pydantic ``Field(description=...)`` -- what each parameter means, read
|
|
19
|
+
from the model's own JSON schema (these were previously harvested by
|
|
20
|
+
nothing and silently dropped).
|
|
21
|
+
|
|
22
|
+
Every helper degrades to the structural rendering when a source is absent:
|
|
23
|
+
a missing description never breaks a prompt, it just starves it.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
from typing import Any, Iterable, List, Optional, Sequence
|
|
29
|
+
|
|
30
|
+
from agent_evolve.policies.genetic import Locus, locus_domain
|
|
31
|
+
|
|
32
|
+
__all__ = ["objective_lines", "parameter_lines", "domain_card"]
|
|
33
|
+
|
|
34
|
+
_MAX_VALUES_SHOWN = 12
|
|
35
|
+
_MAX_PROSE = 900
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _first_paragraph(text: Optional[str]) -> str:
|
|
39
|
+
if not text:
|
|
40
|
+
return ""
|
|
41
|
+
paragraph = text.strip().split("\n\n")[0]
|
|
42
|
+
collapsed = " ".join(paragraph.split())
|
|
43
|
+
return collapsed[:_MAX_PROSE]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def objective_lines(specs: Sequence[Any]) -> List[str]:
|
|
47
|
+
"""One line per objective: name, direction, and its meaning when given."""
|
|
48
|
+
|
|
49
|
+
out = []
|
|
50
|
+
for spec in specs:
|
|
51
|
+
line = f"{spec.name} ({spec.goal})"
|
|
52
|
+
description = _first_paragraph(getattr(spec, "description", ""))
|
|
53
|
+
if description:
|
|
54
|
+
line += f" -- {description}"
|
|
55
|
+
out.append(line)
|
|
56
|
+
return out
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _rendered_domain(domain: tuple) -> str:
|
|
60
|
+
if len(domain) <= _MAX_VALUES_SHOWN:
|
|
61
|
+
return f"one of {list(domain)}"
|
|
62
|
+
head = list(domain[:_MAX_VALUES_SHOWN - 2])
|
|
63
|
+
return (f"one of {head + ['...'] + [domain[-1]]} "
|
|
64
|
+
f"({len(domain)} levels)")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def parameter_lines(
|
|
68
|
+
candidate_model: Any,
|
|
69
|
+
*,
|
|
70
|
+
fields: Optional[Iterable[str]] = None,
|
|
71
|
+
) -> List[str]:
|
|
72
|
+
"""One line per field: domain, shape, and the Field description when given."""
|
|
73
|
+
|
|
74
|
+
try:
|
|
75
|
+
schema = candidate_model.model_json_schema()
|
|
76
|
+
except Exception:
|
|
77
|
+
return []
|
|
78
|
+
properties = schema.get("properties", {}) or {}
|
|
79
|
+
wanted = list(fields) if fields is not None else list(properties)
|
|
80
|
+
out = []
|
|
81
|
+
for name in wanted:
|
|
82
|
+
node = properties.get(name, {})
|
|
83
|
+
if not isinstance(node, dict):
|
|
84
|
+
node = {}
|
|
85
|
+
domain = locus_domain(candidate_model, Locus(name))
|
|
86
|
+
is_sequence = node.get("type") == "array"
|
|
87
|
+
if domain:
|
|
88
|
+
shape = ("sequence field, each position "
|
|
89
|
+
if is_sequence else "") + _rendered_domain(domain)
|
|
90
|
+
elif is_sequence:
|
|
91
|
+
shape = "sequence field"
|
|
92
|
+
else:
|
|
93
|
+
shape = "unconstrained by the schema"
|
|
94
|
+
line = f"{name}: {shape}"
|
|
95
|
+
description = _first_paragraph(node.get("description"))
|
|
96
|
+
if description:
|
|
97
|
+
line += f" -- {description}"
|
|
98
|
+
out.append(line)
|
|
99
|
+
return out
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def domain_card(problem: Any) -> str:
|
|
103
|
+
"""Everything the model should be told about WHAT it is optimizing.
|
|
104
|
+
|
|
105
|
+
Renders only the sections that have content; a problem that documents
|
|
106
|
+
nothing yields the structural card (objectives + parameters), which is
|
|
107
|
+
exactly what prompts carried before this module existed.
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
blocks: List[str] = []
|
|
111
|
+
|
|
112
|
+
prose = ""
|
|
113
|
+
describe = getattr(problem, "search_space_description", None)
|
|
114
|
+
if callable(describe):
|
|
115
|
+
try:
|
|
116
|
+
prose = _first_paragraph(describe()) or ""
|
|
117
|
+
# search_space_description is often multi-paragraph and entirely
|
|
118
|
+
# load-bearing; keep it whole rather than first-paragraph only.
|
|
119
|
+
prose = str(describe()).strip()[:_MAX_PROSE]
|
|
120
|
+
except Exception:
|
|
121
|
+
prose = ""
|
|
122
|
+
if not prose:
|
|
123
|
+
prose = _first_paragraph(getattr(type(problem), "__doc__", ""))
|
|
124
|
+
if not prose:
|
|
125
|
+
candidate_model = getattr(problem, "candidate_model", None)
|
|
126
|
+
prose = _first_paragraph(getattr(candidate_model, "__doc__", ""))
|
|
127
|
+
if prose:
|
|
128
|
+
blocks.append(f"PROBLEM:\n{prose}")
|
|
129
|
+
|
|
130
|
+
evaluate = getattr(problem, "evaluate", None)
|
|
131
|
+
evaluation = _first_paragraph(getattr(evaluate, "__doc__", ""))
|
|
132
|
+
if evaluation:
|
|
133
|
+
blocks.append(f"EVALUATION:\n{evaluation}")
|
|
134
|
+
|
|
135
|
+
objectives = list(getattr(problem, "objectives", ()) or ())
|
|
136
|
+
if objectives:
|
|
137
|
+
blocks.append("OBJECTIVES:\n" + "\n".join(
|
|
138
|
+
f" {line}" for line in objective_lines(objectives)))
|
|
139
|
+
|
|
140
|
+
candidate_model = getattr(problem, "candidate_model", None)
|
|
141
|
+
if candidate_model is not None:
|
|
142
|
+
lines = parameter_lines(candidate_model)
|
|
143
|
+
if lines:
|
|
144
|
+
blocks.append("PARAMETERS:\n" + "\n".join(
|
|
145
|
+
f" {line}" for line in lines))
|
|
146
|
+
|
|
147
|
+
return "\n\n".join(blocks)
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
"""Learning the landscape's structure, and spending the knowledge.
|
|
2
|
+
|
|
3
|
+
The loop this package shipped with could only ever ask "which parents, which
|
|
4
|
+
cut points" -- decisions *inside* a fixed schema-uniform sampling distribution.
|
|
5
|
+
That caps what any guidance can buy: on an exhaustively-censused venue the best
|
|
6
|
+
achievable operator choice reached 7 of 34 frontier configurations, while
|
|
7
|
+
simply sampling from the right quarter of the space reaches 11. The ceiling was
|
|
8
|
+
the distribution, not the chooser.
|
|
9
|
+
|
|
10
|
+
This module adds the phase that was missing. A *screen* spends a few
|
|
11
|
+
evaluations on a design that can actually identify structure; *attribution*
|
|
12
|
+
turns those evaluations into per-level evidence; a *prior proposer* -- a plain
|
|
13
|
+
rule or a model -- turns the evidence into a :class:`DomainRestriction` that
|
|
14
|
+
narrows where every later operator samples.
|
|
15
|
+
|
|
16
|
+
Two things are load-bearing and neither is about language models.
|
|
17
|
+
|
|
18
|
+
A screen must be CROSSED, not merely balanced. Balancing each locus marginally
|
|
19
|
+
leaves its contrast confounded with every other locus, and a confounded table
|
|
20
|
+
says "nothing is excludable" no matter who reads it. Measured: on the same
|
|
21
|
+
venue, a marginally-balanced 8-run screen identified one of two deciding loci,
|
|
22
|
+
while a crossed 4-run screen identified both. Fewer evaluations, better design.
|
|
23
|
+
|
|
24
|
+
A prior governs SAMPLING, not the caller's input. Seeds are data the caller
|
|
25
|
+
supplied and survive a restriction untouched; only drawn candidates -- fresh
|
|
26
|
+
initialization and mutation -- are confined. A prior that could delete a seed
|
|
27
|
+
would be overruling the one thing the problem stated outright.
|
|
28
|
+
|
|
29
|
+
And the prior must be falsifiable. A restriction that removes the good region
|
|
30
|
+
is unrecoverable by construction, so callers get :func:`restriction_is_paying`
|
|
31
|
+
to check the bet against the screen's own best and unwind it.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
from __future__ import annotations
|
|
35
|
+
|
|
36
|
+
import itertools
|
|
37
|
+
import random
|
|
38
|
+
from dataclasses import dataclass, field
|
|
39
|
+
from typing import Any, Callable, Iterable, Mapping, Sequence
|
|
40
|
+
|
|
41
|
+
from agent_evolve.core.problem import ObjectiveSpec
|
|
42
|
+
from agent_evolve.policies.genetic import (
|
|
43
|
+
DomainRestriction,
|
|
44
|
+
Locus,
|
|
45
|
+
loci_of,
|
|
46
|
+
locus_domain,
|
|
47
|
+
read_locus,
|
|
48
|
+
write_locus,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
__all__ = [
|
|
52
|
+
"LevelSummary",
|
|
53
|
+
"Attribution",
|
|
54
|
+
"crossed_screen",
|
|
55
|
+
"attribute",
|
|
56
|
+
"render_attribution",
|
|
57
|
+
"statistical_prior",
|
|
58
|
+
"restriction_is_paying",
|
|
59
|
+
"PriorProposer",
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@dataclass(frozen=True)
|
|
64
|
+
class LevelSummary:
|
|
65
|
+
"""What the screen measured for one value of one locus."""
|
|
66
|
+
|
|
67
|
+
locus: str
|
|
68
|
+
value: Any
|
|
69
|
+
n: int
|
|
70
|
+
objective_means: Mapping[str, float]
|
|
71
|
+
nondominated: int
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@dataclass(frozen=True)
|
|
75
|
+
class Attribution:
|
|
76
|
+
"""Per-level evidence from the screened candidates."""
|
|
77
|
+
|
|
78
|
+
levels: tuple[LevelSummary, ...] = ()
|
|
79
|
+
n_evaluated: int = 0
|
|
80
|
+
blocking: tuple[str, ...] = ()
|
|
81
|
+
|
|
82
|
+
def for_locus(self, name: str) -> tuple[LevelSummary, ...]:
|
|
83
|
+
return tuple(s for s in self.levels if s.locus == name)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
#: Turns measured evidence into a prior over where to sample. A rule, a model,
|
|
87
|
+
#: anything: the loop only requires that it narrows declared domains.
|
|
88
|
+
PriorProposer = Callable[[Attribution, Any], DomainRestriction]
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def crossed_screen(
|
|
92
|
+
template: Mapping[str, Any],
|
|
93
|
+
candidate_model: Any,
|
|
94
|
+
*,
|
|
95
|
+
size: int,
|
|
96
|
+
blocking: Sequence[str] | None = None,
|
|
97
|
+
rng: random.Random | None = None,
|
|
98
|
+
pool_by_field: bool = False,
|
|
99
|
+
) -> list[dict[str, Any]]:
|
|
100
|
+
"""A screening design of *size* candidates that can identify structure.
|
|
101
|
+
|
|
102
|
+
The blocking loci are fully crossed -- every combination of their values
|
|
103
|
+
appears equally often -- so their contrasts are not confounded with each
|
|
104
|
+
other. Every remaining locus walks the same ladder of values inside each
|
|
105
|
+
block, so its levels are matched across blocks rather than correlated with
|
|
106
|
+
them.
|
|
107
|
+
|
|
108
|
+
Chosen automatically when *blocking* is omitted: the loci with the smallest
|
|
109
|
+
declared domains, taking as many as fit in *size*. Small domains are where
|
|
110
|
+
structural switches live, and they are the cheapest to cross.
|
|
111
|
+
|
|
112
|
+
``pool_by_field`` changes the design for SEQUENCE fields, whose positions
|
|
113
|
+
share one vocabulary: crossing them is out of reach (k^n cells) and
|
|
114
|
+
per-position ladders leave per-level n tiny, but if positions are roughly
|
|
115
|
+
exchangeable the value effect can be measured POOLED across positions.
|
|
116
|
+
The design is then per-value: first one PURE candidate per value (every
|
|
117
|
+
position set to it -- the cleanest pooled contrast), then SPIKED
|
|
118
|
+
candidates (the value at every other position, the rest cycling through
|
|
119
|
+
the vocabulary) until *size* is spent. Whether positions really are
|
|
120
|
+
exchangeable is the bet this design makes; the caller's prior gets
|
|
121
|
+
unwound by the standard test when they are not.
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
r = rng or random.Random()
|
|
125
|
+
if pool_by_field:
|
|
126
|
+
return _pooled_screen(template, candidate_model, size=size)
|
|
127
|
+
all_loci = [lc for lc in loci_of(template) if locus_domain(candidate_model, lc)]
|
|
128
|
+
if not all_loci or size <= 0:
|
|
129
|
+
return []
|
|
130
|
+
domains = {lc: locus_domain(candidate_model, lc) for lc in all_loci}
|
|
131
|
+
|
|
132
|
+
if blocking is None:
|
|
133
|
+
block: list[Locus] = []
|
|
134
|
+
cells = 1
|
|
135
|
+
for lc in sorted(all_loci, key=lambda l: len(domains[l])):
|
|
136
|
+
if cells * len(domains[lc]) > size:
|
|
137
|
+
break
|
|
138
|
+
block.append(lc)
|
|
139
|
+
cells *= len(domains[lc])
|
|
140
|
+
else:
|
|
141
|
+
wanted = tuple(blocking)
|
|
142
|
+
block = [lc for lc in all_loci if str(lc) in wanted or lc.field in wanted]
|
|
143
|
+
cells = 1
|
|
144
|
+
for lc in block:
|
|
145
|
+
cells *= len(domains[lc])
|
|
146
|
+
if not block: # nothing crossable: fall back to a walk
|
|
147
|
+
block, cells = [], 1
|
|
148
|
+
|
|
149
|
+
rest = [lc for lc in all_loci if lc not in block]
|
|
150
|
+
per_cell = max(1, size // max(1, cells))
|
|
151
|
+
# One shared ladder of settings for the non-blocking loci, reused verbatim
|
|
152
|
+
# in every block: that is what keeps their levels matched across blocks.
|
|
153
|
+
ladder = [
|
|
154
|
+
{lc: domains[lc][t % len(domains[lc])] for lc in rest}
|
|
155
|
+
for t in range(per_cell)
|
|
156
|
+
]
|
|
157
|
+
|
|
158
|
+
out: list[dict[str, Any]] = []
|
|
159
|
+
combos = list(itertools.product(*[domains[lc] for lc in block])) or [()]
|
|
160
|
+
for combo in combos:
|
|
161
|
+
for setting in ladder:
|
|
162
|
+
cfg = dict(template)
|
|
163
|
+
for lc, value in zip(block, combo):
|
|
164
|
+
cfg = write_locus(cfg, lc, value)
|
|
165
|
+
for lc, value in setting.items():
|
|
166
|
+
cfg = write_locus(cfg, lc, value)
|
|
167
|
+
out.append(cfg)
|
|
168
|
+
# Never exceed the budget the caller agreed to spend; if the crossing did
|
|
169
|
+
# not fill it, top up with schema-uniform draws rather than repeating.
|
|
170
|
+
while len(out) < size:
|
|
171
|
+
cfg = dict(template)
|
|
172
|
+
for lc in all_loci:
|
|
173
|
+
cfg = write_locus(cfg, lc, r.choice(domains[lc]))
|
|
174
|
+
out.append(cfg)
|
|
175
|
+
return out[:size]
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def _pooled_screen(
|
|
179
|
+
template: Mapping[str, Any],
|
|
180
|
+
candidate_model: Any,
|
|
181
|
+
*,
|
|
182
|
+
size: int,
|
|
183
|
+
) -> list[dict[str, Any]]:
|
|
184
|
+
"""Pure and spiked candidates over each sequence field's shared vocabulary."""
|
|
185
|
+
|
|
186
|
+
sequence_loci = [lc for lc in loci_of(template) if lc.index is not None
|
|
187
|
+
and locus_domain(candidate_model, lc)]
|
|
188
|
+
if not sequence_loci or size <= 0:
|
|
189
|
+
return []
|
|
190
|
+
fields: dict[str, list[Locus]] = {}
|
|
191
|
+
for lc in sequence_loci:
|
|
192
|
+
fields.setdefault(lc.field, []).append(lc)
|
|
193
|
+
|
|
194
|
+
out: list[dict[str, Any]] = []
|
|
195
|
+
spike_round = 0
|
|
196
|
+
while len(out) < size:
|
|
197
|
+
for name, loci in fields.items():
|
|
198
|
+
domain = locus_domain(candidate_model, loci[0])
|
|
199
|
+
for value_index, value in enumerate(domain):
|
|
200
|
+
if len(out) >= size:
|
|
201
|
+
break
|
|
202
|
+
cfg = dict(template)
|
|
203
|
+
for position, lc in enumerate(loci):
|
|
204
|
+
if spike_round == 0:
|
|
205
|
+
cfg = write_locus(cfg, lc, value) # pure
|
|
206
|
+
elif position % 2 == 0:
|
|
207
|
+
cfg = write_locus(cfg, lc, value) # spiked
|
|
208
|
+
else:
|
|
209
|
+
fill = domain[(value_index + position + spike_round)
|
|
210
|
+
% len(domain)]
|
|
211
|
+
cfg = write_locus(cfg, lc, fill)
|
|
212
|
+
out.append(cfg)
|
|
213
|
+
spike_round += 1
|
|
214
|
+
return out[:size]
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def _nondominated(points: Sequence[Sequence[float]]) -> list[bool]:
|
|
218
|
+
out = []
|
|
219
|
+
for a, pa in enumerate(points):
|
|
220
|
+
out.append(not any(
|
|
221
|
+
b != a
|
|
222
|
+
and all(x <= y for x, y in zip(pb, pa))
|
|
223
|
+
and any(x < y for x, y in zip(pb, pa))
|
|
224
|
+
for b, pb in enumerate(points)))
|
|
225
|
+
return out
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def attribute(
|
|
229
|
+
evaluated: Sequence[tuple[Mapping[str, Any], Mapping[str, float]]],
|
|
230
|
+
specs: Sequence[ObjectiveSpec],
|
|
231
|
+
candidate_model: Any,
|
|
232
|
+
*,
|
|
233
|
+
blocking: Sequence[str] = (),
|
|
234
|
+
pool_by_field: bool = False,
|
|
235
|
+
) -> Attribution:
|
|
236
|
+
"""Summarise screened candidates per locus value.
|
|
237
|
+
|
|
238
|
+
Non-domination is computed WITHIN the screen, in minimisation-normalised
|
|
239
|
+
coordinates, because that is the only comparison an optimizer can make from
|
|
240
|
+
its own evaluations -- no global frontier is available at run time.
|
|
241
|
+
|
|
242
|
+
``pool_by_field`` treats a sequence field's positions as exchangeable:
|
|
243
|
+
every (candidate, position) pair becomes one observation of the value it
|
|
244
|
+
holds, keyed by the bare field name. Per-position n on a short screen is
|
|
245
|
+
unusably small; pooled n is positions times larger. The exchangeability
|
|
246
|
+
bet itself is the caller's, and the standard unwind test is its check.
|
|
247
|
+
"""
|
|
248
|
+
|
|
249
|
+
if not evaluated:
|
|
250
|
+
return Attribution((), 0, tuple(blocking))
|
|
251
|
+
names = [s.name for s in specs]
|
|
252
|
+
sign = {s.name: (-1.0 if s.goal == "max" else 1.0) for s in specs}
|
|
253
|
+
pts = [[sign[n] * float(obj[n]) for n in names] for _, obj in evaluated]
|
|
254
|
+
nd = _nondominated(pts)
|
|
255
|
+
|
|
256
|
+
scalar_loci: list[Locus] = []
|
|
257
|
+
pooled_fields: dict[str, list[Locus]] = {}
|
|
258
|
+
for lc in loci_of(evaluated[0][0]):
|
|
259
|
+
if not locus_domain(candidate_model, lc):
|
|
260
|
+
continue
|
|
261
|
+
if pool_by_field and lc.index is not None:
|
|
262
|
+
pooled_fields.setdefault(lc.field, []).append(lc)
|
|
263
|
+
else:
|
|
264
|
+
scalar_loci.append(lc)
|
|
265
|
+
|
|
266
|
+
levels: list[LevelSummary] = []
|
|
267
|
+
for lc in scalar_loci:
|
|
268
|
+
seen: dict[Any, list[int]] = {}
|
|
269
|
+
for i, (cfg, _obj) in enumerate(evaluated):
|
|
270
|
+
seen.setdefault(read_locus(cfg, lc), []).append(i)
|
|
271
|
+
for value, idxs in seen.items():
|
|
272
|
+
levels.append(LevelSummary(
|
|
273
|
+
locus=str(lc), value=value, n=len(idxs),
|
|
274
|
+
objective_means={
|
|
275
|
+
n: sum(float(evaluated[i][1][n]) for i in idxs) / len(idxs)
|
|
276
|
+
for n in names},
|
|
277
|
+
nondominated=sum(1 for i in idxs if nd[i]),
|
|
278
|
+
))
|
|
279
|
+
for field_name, loci in pooled_fields.items():
|
|
280
|
+
seen = {}
|
|
281
|
+
for i, (cfg, _obj) in enumerate(evaluated):
|
|
282
|
+
for lc in loci:
|
|
283
|
+
seen.setdefault(read_locus(cfg, lc), []).append(i)
|
|
284
|
+
for value, idxs in seen.items():
|
|
285
|
+
levels.append(LevelSummary(
|
|
286
|
+
locus=field_name, value=value, n=len(idxs),
|
|
287
|
+
objective_means={
|
|
288
|
+
n: sum(float(evaluated[i][1][n]) for i in idxs) / len(idxs)
|
|
289
|
+
for n in names},
|
|
290
|
+
nondominated=sum(1 for i in idxs if nd[i]),
|
|
291
|
+
))
|
|
292
|
+
return Attribution(tuple(levels), len(evaluated), tuple(blocking))
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
def render_attribution(attr: Attribution) -> str:
|
|
296
|
+
"""The screen as text: what a reader (rule or model) gets to reason over."""
|
|
297
|
+
|
|
298
|
+
if not attr.levels:
|
|
299
|
+
return "(no screened evaluations)"
|
|
300
|
+
lines: list[str] = []
|
|
301
|
+
for name in dict.fromkeys(s.locus for s in attr.levels):
|
|
302
|
+
lines.append(f" {name}:")
|
|
303
|
+
for s in attr.for_locus(name):
|
|
304
|
+
means = " ".join(f"{k}={v:.6g}" for k, v in s.objective_means.items())
|
|
305
|
+
lines.append(f" {s.value}: n={s.n} {means} "
|
|
306
|
+
f"non-dominated {s.nondominated}/{s.n}")
|
|
307
|
+
return "\n".join(lines)
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def statistical_prior(
|
|
311
|
+
attr: Attribution,
|
|
312
|
+
candidate_model: Any = None,
|
|
313
|
+
*,
|
|
314
|
+
min_levels: int = 2,
|
|
315
|
+
) -> DomainRestriction:
|
|
316
|
+
"""The credential-free prior: keep the levels the screen did not refute.
|
|
317
|
+
|
|
318
|
+
For each locus, a level is kept when its within-screen non-domination rate
|
|
319
|
+
ties the best rate for that locus. A locus whose levels all tie is left
|
|
320
|
+
alone -- which is the honest reading of a screen that separated nothing,
|
|
321
|
+
and the reason this rule abstains far more often than it commits.
|
|
322
|
+
|
|
323
|
+
This ships as the default so the phase is useful with no model and no
|
|
324
|
+
credential, and so any model-proposed prior has a rule to beat.
|
|
325
|
+
"""
|
|
326
|
+
|
|
327
|
+
allowed: dict[str, list[Any]] = {}
|
|
328
|
+
for name in dict.fromkeys(s.locus for s in attr.levels):
|
|
329
|
+
summaries = attr.for_locus(name)
|
|
330
|
+
if len(summaries) < min_levels:
|
|
331
|
+
continue
|
|
332
|
+
rates = {s.value: (s.nondominated / s.n if s.n else 0.0) for s in summaries}
|
|
333
|
+
best = max(rates.values())
|
|
334
|
+
if best <= 0.0:
|
|
335
|
+
continue
|
|
336
|
+
keep = [v for v, rate in rates.items() if rate >= best]
|
|
337
|
+
if 0 < len(keep) < len(summaries):
|
|
338
|
+
allowed[name.split("[")[0]] = keep
|
|
339
|
+
return DomainRestriction(allowed)
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def restriction_is_paying(
|
|
343
|
+
restriction: DomainRestriction,
|
|
344
|
+
screen_best: float,
|
|
345
|
+
current_best: float,
|
|
346
|
+
*,
|
|
347
|
+
goal: str = "min",
|
|
348
|
+
) -> bool:
|
|
349
|
+
"""Is the bet still worth holding?
|
|
350
|
+
|
|
351
|
+
A restriction that removed the good region cannot recover on its own, so a
|
|
352
|
+
caller that installed one must be able to notice and unwind it. The test is
|
|
353
|
+
deliberately weak -- the restricted search only has to have matched what the
|
|
354
|
+
screen already found -- because unwinding a prior that is merely unlucky
|
|
355
|
+
costs less than holding one that is wrong.
|
|
356
|
+
"""
|
|
357
|
+
|
|
358
|
+
if not restriction.allowed:
|
|
359
|
+
return True
|
|
360
|
+
if goal == "max":
|
|
361
|
+
return current_best >= screen_best
|
|
362
|
+
return current_best <= screen_best
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Immutable structured-output budget policies."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import ClassVar
|
|
7
|
+
|
|
8
|
+
from agent_evolve.ports.structured_generator import MAX_OUTPUT_TOKENS
|
|
9
|
+
from agent_evolve.ports.structured_output_budget import (
|
|
10
|
+
StructuredOutputRequestKind,
|
|
11
|
+
validate_structured_output_operation,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _validate_budget(value: int, name: str) -> None:
|
|
16
|
+
if type(value) is not int or not 1 <= value <= MAX_OUTPUT_TOKENS:
|
|
17
|
+
raise ValueError(f"{name} must lie in [1, {MAX_OUTPUT_TOKENS}]")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass(frozen=True, slots=True)
|
|
21
|
+
class FixedStructuredOutputBudgetPolicy:
|
|
22
|
+
"""Assign immutable output limits by agentic request kind.
|
|
23
|
+
|
|
24
|
+
The operation argument is deliberately retained by the policy port. This
|
|
25
|
+
fixed implementation ignores its value after validation; experiments that
|
|
26
|
+
need per-operator allocation can inject another implementation without
|
|
27
|
+
changing the engine or a benchmark adapter.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
proposal_max_output_tokens: int = 2_048
|
|
31
|
+
reflection_max_output_tokens: int = 2_048
|
|
32
|
+
|
|
33
|
+
policy_id: ClassVar[str] = "fixed_by_agentic_request_kind"
|
|
34
|
+
policy_version: ClassVar[int] = 1
|
|
35
|
+
|
|
36
|
+
def __post_init__(self) -> None:
|
|
37
|
+
_validate_budget(
|
|
38
|
+
self.proposal_max_output_tokens,
|
|
39
|
+
"proposal_max_output_tokens",
|
|
40
|
+
)
|
|
41
|
+
_validate_budget(
|
|
42
|
+
self.reflection_max_output_tokens,
|
|
43
|
+
"reflection_max_output_tokens",
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
def max_output_tokens(
|
|
47
|
+
self,
|
|
48
|
+
*,
|
|
49
|
+
request_kind: StructuredOutputRequestKind,
|
|
50
|
+
operation: str,
|
|
51
|
+
) -> int:
|
|
52
|
+
if type(request_kind) is not StructuredOutputRequestKind:
|
|
53
|
+
raise TypeError(
|
|
54
|
+
"request_kind must be an exact StructuredOutputRequestKind"
|
|
55
|
+
)
|
|
56
|
+
validate_structured_output_operation(operation)
|
|
57
|
+
if request_kind is StructuredOutputRequestKind.PROPOSAL:
|
|
58
|
+
return self.proposal_max_output_tokens
|
|
59
|
+
return self.reflection_max_output_tokens
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
__all__ = ["FixedStructuredOutputBudgetPolicy"]
|