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