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,286 @@
|
|
|
1
|
+
"""Pure formatting/parsing helpers shared by the loop and the LLM prompts.
|
|
2
|
+
|
|
3
|
+
Everything here is a pure function of its arguments (no I/O, no globals).
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import re
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple
|
|
12
|
+
|
|
13
|
+
from pydantic import BaseModel
|
|
14
|
+
|
|
15
|
+
from agent_evolve.core.problem import ObjectiveSpec
|
|
16
|
+
from agent_evolve.core.results import Candidate, objective_value
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class CandidateResult:
|
|
21
|
+
"""Intermediate evaluation record (richer than the public :class:`Candidate`)."""
|
|
22
|
+
|
|
23
|
+
configuration: Dict[str, Any]
|
|
24
|
+
objectives: Dict[str, float]
|
|
25
|
+
is_valid: bool
|
|
26
|
+
error_message: Optional[str] = None
|
|
27
|
+
failure_phase: Optional[str] = None
|
|
28
|
+
#: True iff ``Problem.evaluate`` was actually invoked for this candidate.
|
|
29
|
+
evaluation_attempted: bool = False
|
|
30
|
+
insight: str = ""
|
|
31
|
+
#: Original element from the LLM ``candidates`` list (before/while parsing).
|
|
32
|
+
raw_llm_element: Optional[Any] = None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# ------------------------------------------------------------------
|
|
36
|
+
# Prettifiers (consumed by LLM prompts)
|
|
37
|
+
# ------------------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
def prettify_configuration(config: Dict[str, Any], indent: int = 2) -> str:
|
|
40
|
+
return json.dumps(config, indent=indent, sort_keys=True, default=str)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def dump_raw_llm_element(obj: Any, *, max_len: int = 12_000) -> str:
|
|
44
|
+
"""Serialize a raw LLM list element for logs and failure prompts."""
|
|
45
|
+
if obj is None:
|
|
46
|
+
return "(none)"
|
|
47
|
+
try:
|
|
48
|
+
s = json.dumps(obj, indent=2, default=str, ensure_ascii=False)
|
|
49
|
+
except (TypeError, ValueError):
|
|
50
|
+
s = repr(obj)
|
|
51
|
+
if len(s) > max_len:
|
|
52
|
+
return s[:max_len] + f"\n... [truncated, {len(s)} chars total]"
|
|
53
|
+
return s
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def prettify_objectives(objectives: Sequence[ObjectiveSpec]) -> str:
|
|
57
|
+
lines = ["OBJECTIVES:", "=" * 60]
|
|
58
|
+
for spec in objectives:
|
|
59
|
+
desc = "higher is better" if spec.goal == "max" else "lower is better"
|
|
60
|
+
lines.append(f" - {spec.name}: {desc}")
|
|
61
|
+
return "\n".join(lines)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def prettify_results(
|
|
65
|
+
results: Sequence[CandidateResult],
|
|
66
|
+
objectives: Sequence[ObjectiveSpec],
|
|
67
|
+
render: Optional[Callable[[Dict[str, Any]], str]] = None,
|
|
68
|
+
) -> str:
|
|
69
|
+
"""Format candidate results for LLM prompts.
|
|
70
|
+
|
|
71
|
+
``render`` optionally produces a compact one-line view of each configuration
|
|
72
|
+
(e.g. a problem-specific summary); when absent, pretty JSON is used.
|
|
73
|
+
"""
|
|
74
|
+
lines: List[str] = []
|
|
75
|
+
for i, r in enumerate(results, 1):
|
|
76
|
+
lines.append(f"--- Candidate {i} ---")
|
|
77
|
+
config_str = render(r.configuration) if render is not None else prettify_configuration(r.configuration)
|
|
78
|
+
lines.append(f"Configuration: {config_str}")
|
|
79
|
+
if getattr(r, "raw_llm_element", None) is not None:
|
|
80
|
+
lines.append(
|
|
81
|
+
"Raw LLM element (exact item from the model's candidates list): "
|
|
82
|
+
+ dump_raw_llm_element(r.raw_llm_element)
|
|
83
|
+
)
|
|
84
|
+
if r.is_valid:
|
|
85
|
+
parts = []
|
|
86
|
+
for spec in objectives:
|
|
87
|
+
val = objective_value(r.objectives, spec.name)
|
|
88
|
+
arrow = "\u2191" if spec.goal == "max" else "\u2193"
|
|
89
|
+
parts.append(f"{spec.name}={val:.4f}{arrow}")
|
|
90
|
+
lines.append(f"Objectives: {', '.join(parts)}")
|
|
91
|
+
else:
|
|
92
|
+
lines.append("Status: INVALID")
|
|
93
|
+
if r.failure_phase:
|
|
94
|
+
lines.append(f"Failure Phase: {r.failure_phase}")
|
|
95
|
+
if r.error_message:
|
|
96
|
+
lines.append(f"Error: {r.error_message}")
|
|
97
|
+
if r.insight:
|
|
98
|
+
lines.append(f"Insight: {r.insight}")
|
|
99
|
+
lines.append("")
|
|
100
|
+
return "\n".join(lines)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# ------------------------------------------------------------------
|
|
104
|
+
# Search-space description for LLM context
|
|
105
|
+
# ------------------------------------------------------------------
|
|
106
|
+
|
|
107
|
+
def format_search_space_description(
|
|
108
|
+
objectives: Sequence[ObjectiveSpec],
|
|
109
|
+
*,
|
|
110
|
+
config_schema: Optional[Dict[str, Any]] = None,
|
|
111
|
+
example_config: Optional[Dict[str, Any]] = None,
|
|
112
|
+
constraints: Optional[str] = None,
|
|
113
|
+
problem_description: Optional[str] = None,
|
|
114
|
+
) -> str:
|
|
115
|
+
lines: List[str] = []
|
|
116
|
+
lines.append("=" * 70)
|
|
117
|
+
lines.append("MULTI-OBJECTIVE OPTIMIZATION PROBLEM")
|
|
118
|
+
lines.append("=" * 70)
|
|
119
|
+
lines.append("")
|
|
120
|
+
lines.append("OBJECTIVES:")
|
|
121
|
+
for spec in objectives:
|
|
122
|
+
desc = "MAXIMIZE (higher is better)" if spec.goal == "max" else "MINIMIZE (lower is better)"
|
|
123
|
+
lines.append(f" \u2022 {spec.name}: {desc}")
|
|
124
|
+
lines.append("")
|
|
125
|
+
|
|
126
|
+
if problem_description:
|
|
127
|
+
lines.append("PROBLEM DESCRIPTION:")
|
|
128
|
+
lines.append(problem_description)
|
|
129
|
+
lines.append("")
|
|
130
|
+
|
|
131
|
+
if config_schema:
|
|
132
|
+
lines.append("CONFIGURATION SCHEMA:")
|
|
133
|
+
lines.append(prettify_configuration(config_schema))
|
|
134
|
+
lines.append("")
|
|
135
|
+
|
|
136
|
+
if example_config:
|
|
137
|
+
lines.append("EXAMPLE CONFIGURATION:")
|
|
138
|
+
lines.append(prettify_configuration(example_config))
|
|
139
|
+
lines.append("")
|
|
140
|
+
|
|
141
|
+
if constraints:
|
|
142
|
+
lines.append("CONSTRAINTS:")
|
|
143
|
+
lines.append(constraints)
|
|
144
|
+
lines.append("")
|
|
145
|
+
|
|
146
|
+
return "\n".join(lines)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
# ------------------------------------------------------------------
|
|
150
|
+
# Conversions between CandidateResult and the public Candidate
|
|
151
|
+
# ------------------------------------------------------------------
|
|
152
|
+
|
|
153
|
+
def result_to_candidate(
|
|
154
|
+
result: CandidateResult,
|
|
155
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
156
|
+
) -> Candidate[Dict[str, Any]]:
|
|
157
|
+
return Candidate(
|
|
158
|
+
configuration=result.configuration,
|
|
159
|
+
objectives=result.objectives,
|
|
160
|
+
metadata=metadata or {"is_pareto": False},
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def candidate_to_result(candidate: Candidate[Dict[str, Any]]) -> CandidateResult:
|
|
165
|
+
return CandidateResult(
|
|
166
|
+
configuration=candidate.configuration,
|
|
167
|
+
objectives=candidate.objectives,
|
|
168
|
+
is_valid=True,
|
|
169
|
+
evaluation_attempted=True,
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
# ------------------------------------------------------------------
|
|
174
|
+
# Parse LLM candidate output
|
|
175
|
+
# ------------------------------------------------------------------
|
|
176
|
+
|
|
177
|
+
def parse_llm_json_array(s: str) -> List[Any]:
|
|
178
|
+
"""Parse a JSON array (or single object) from an LLM ``str`` field.
|
|
179
|
+
|
|
180
|
+
The single-JSON-string output contract avoids the ``[{}, {}, ...]`` degradation
|
|
181
|
+
that ``list[dict]`` structured outputs are prone to. Strips optional markdown fences.
|
|
182
|
+
"""
|
|
183
|
+
s = (s or "").strip()
|
|
184
|
+
if not s:
|
|
185
|
+
raise ValueError("Empty candidates JSON string")
|
|
186
|
+
if s.startswith("```"):
|
|
187
|
+
s = re.sub(r"^```(?:json)?\s*", "", s, flags=re.IGNORECASE)
|
|
188
|
+
s = re.sub(r"\s*```\s*$", "", s)
|
|
189
|
+
data = json.loads(s)
|
|
190
|
+
if isinstance(data, dict):
|
|
191
|
+
inner = data.get("candidates")
|
|
192
|
+
if isinstance(inner, list):
|
|
193
|
+
return inner
|
|
194
|
+
return [data]
|
|
195
|
+
if isinstance(data, list):
|
|
196
|
+
return data
|
|
197
|
+
raise ValueError(f"Candidates JSON must be an array or object, got {type(data).__name__}")
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def parse_candidates(
|
|
201
|
+
candidates: Any,
|
|
202
|
+
expected_count: int,
|
|
203
|
+
log_fn: Callable[[str], None] = lambda m: None,
|
|
204
|
+
) -> Tuple[List[Dict[str, Any]], List[Any]]:
|
|
205
|
+
"""Normalise LLM output into configuration dicts.
|
|
206
|
+
|
|
207
|
+
Returns ``(parsed_configs, raw_elements)`` with one raw element per input list
|
|
208
|
+
item (same order), so failures can show what the model actually returned even
|
|
209
|
+
when the parsed dict is ``{}`` or wrong.
|
|
210
|
+
"""
|
|
211
|
+
if isinstance(candidates, str):
|
|
212
|
+
try:
|
|
213
|
+
candidates = parse_llm_json_array(candidates)
|
|
214
|
+
except Exception as exc:
|
|
215
|
+
log_fn(f"Warning: could not parse candidates as JSON array string: {exc}")
|
|
216
|
+
return [], []
|
|
217
|
+
|
|
218
|
+
if isinstance(candidates, dict):
|
|
219
|
+
inner = candidates.get("candidates")
|
|
220
|
+
if isinstance(inner, list):
|
|
221
|
+
candidates = inner
|
|
222
|
+
else:
|
|
223
|
+
log_fn(
|
|
224
|
+
f"Warning: LLM returned a dict without a 'candidates' list "
|
|
225
|
+
f"(keys: {list(candidates.keys())})."
|
|
226
|
+
)
|
|
227
|
+
return [], []
|
|
228
|
+
|
|
229
|
+
if not isinstance(candidates, list):
|
|
230
|
+
log_fn(f"Warning: LLM returned non-list candidates: {type(candidates)}")
|
|
231
|
+
return [], []
|
|
232
|
+
|
|
233
|
+
parsed: List[Dict[str, Any]] = []
|
|
234
|
+
raw_elements: List[Any] = []
|
|
235
|
+
for c in candidates:
|
|
236
|
+
raw_elements.append(c)
|
|
237
|
+
if isinstance(c, BaseModel):
|
|
238
|
+
parsed.append(c.model_dump())
|
|
239
|
+
elif isinstance(c, dict):
|
|
240
|
+
parsed.append(c)
|
|
241
|
+
elif isinstance(c, str):
|
|
242
|
+
try:
|
|
243
|
+
parsed.append(json.loads(c))
|
|
244
|
+
except Exception:
|
|
245
|
+
log_fn(f"Warning: Could not parse candidate string: {c[:100]}")
|
|
246
|
+
parsed.append({})
|
|
247
|
+
else:
|
|
248
|
+
log_fn(
|
|
249
|
+
f"Warning: candidate element has unexpected type {type(c).__name__}"
|
|
250
|
+
)
|
|
251
|
+
parsed.append({})
|
|
252
|
+
|
|
253
|
+
if len(parsed) != expected_count:
|
|
254
|
+
log_fn(f"Warning: Expected {expected_count} candidates, got {len(parsed)}")
|
|
255
|
+
return parsed, raw_elements
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def result_to_json(result: Any) -> str:
|
|
259
|
+
"""One machine-readable document for a ``SearchResult``.
|
|
260
|
+
|
|
261
|
+
Blocks that were never populated serialize as ``null`` rather than being
|
|
262
|
+
omitted, so a reader can tell "measured zero" (a present block with zero
|
|
263
|
+
counts) from "nobody looked" (null). Values outside JSON's vocabulary fall
|
|
264
|
+
back to ``str`` -- a printable document beats a crash on an exotic locus
|
|
265
|
+
type, and the exact values live in the caller's hands anyway.
|
|
266
|
+
"""
|
|
267
|
+
import dataclasses
|
|
268
|
+
|
|
269
|
+
def _candidate(c: Any) -> Dict[str, Any]:
|
|
270
|
+
return {"configuration": c.configuration, "objectives": c.objectives}
|
|
271
|
+
|
|
272
|
+
payload = {
|
|
273
|
+
"best": _candidate(result.best),
|
|
274
|
+
"pareto_front": [_candidate(c) for c in result.pareto_front],
|
|
275
|
+
"evaluations": result.evaluations,
|
|
276
|
+
"history": result.history,
|
|
277
|
+
"provider_usage": (
|
|
278
|
+
dataclasses.asdict(result.provider_usage)
|
|
279
|
+
if result.provider_usage is not None else None
|
|
280
|
+
),
|
|
281
|
+
"telemetry": (
|
|
282
|
+
dataclasses.asdict(result.telemetry)
|
|
283
|
+
if result.telemetry is not None else None
|
|
284
|
+
),
|
|
285
|
+
}
|
|
286
|
+
return json.dumps(payload, sort_keys=True, default=str)
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
"""Immutable, prompt-safe semantics for optimization metrics and ordering.
|
|
2
|
+
|
|
3
|
+
The application core must not guess what a benchmark metric means. This
|
|
4
|
+
module gives benchmark adapters a small inverted API for publishing that
|
|
5
|
+
meaning once, binding it to the objective and outcome-relation identities,
|
|
6
|
+
and rendering the same canonical record into every agentic prompt.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import hashlib
|
|
12
|
+
import json
|
|
13
|
+
import math
|
|
14
|
+
import re
|
|
15
|
+
from dataclasses import dataclass, field
|
|
16
|
+
from enum import Enum
|
|
17
|
+
from typing import Sequence
|
|
18
|
+
|
|
19
|
+
from agent_evolve.core.problem import ObjectiveSpec, validate_objective_specs
|
|
20
|
+
from agent_evolve.domain.patch import require_sha256
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
_TOKEN = re.compile(r"^[a-z][a-z0-9_.-]{0,95}$")
|
|
24
|
+
_SEMANTICS_HASH_DOMAIN = b"agent-evolve:optimization-semantics:v1\x00"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class MetricRole(str, Enum):
|
|
28
|
+
"""Closed role vocabulary for values exposed to an optimizer."""
|
|
29
|
+
|
|
30
|
+
OBJECTIVE = "objective"
|
|
31
|
+
VIOLATION = "violation"
|
|
32
|
+
CONSTRAINT = "constraint"
|
|
33
|
+
DIAGNOSTIC = "diagnostic"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class MetricSense(str, Enum):
|
|
37
|
+
"""How better values of a metric are interpreted."""
|
|
38
|
+
|
|
39
|
+
MINIMIZE = "minimize"
|
|
40
|
+
MAXIMIZE = "maximize"
|
|
41
|
+
TARGET = "target"
|
|
42
|
+
SATISFY_BOUNDS = "satisfy_bounds"
|
|
43
|
+
INFORMATIONAL = "informational"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class OutcomeOrderingKind(str, Enum):
|
|
47
|
+
"""High-level structure of the benchmark's outcome comparison."""
|
|
48
|
+
|
|
49
|
+
LEXICOGRAPHIC = "lexicographic"
|
|
50
|
+
PARETO = "pareto"
|
|
51
|
+
SCALAR = "scalar"
|
|
52
|
+
CUSTOM = "custom"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _nonempty(value: object, name: str) -> str:
|
|
56
|
+
if type(value) is not str or not value.strip():
|
|
57
|
+
raise ValueError(f"{name} must be a non-empty exact string")
|
|
58
|
+
return value
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _token(value: object, name: str) -> str:
|
|
62
|
+
text = _nonempty(value, name)
|
|
63
|
+
if _TOKEN.fullmatch(text) is None:
|
|
64
|
+
raise ValueError(f"{name} must use the closed token grammar")
|
|
65
|
+
return text
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _finite_optional(value: object, name: str) -> float | None:
|
|
69
|
+
if value is None:
|
|
70
|
+
return None
|
|
71
|
+
if isinstance(value, bool) or not isinstance(value, (int, float)):
|
|
72
|
+
raise TypeError(f"{name} must be a finite number or None")
|
|
73
|
+
number = float(value)
|
|
74
|
+
if not math.isfinite(number):
|
|
75
|
+
raise ValueError(f"{name} must be finite")
|
|
76
|
+
return number
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@dataclass(frozen=True, slots=True)
|
|
80
|
+
class MetricSemantics:
|
|
81
|
+
"""Exact human-facing meaning of one objective/evidence metric."""
|
|
82
|
+
|
|
83
|
+
metric_id: str
|
|
84
|
+
name: str
|
|
85
|
+
role: MetricRole
|
|
86
|
+
sense: MetricSense
|
|
87
|
+
definition: str
|
|
88
|
+
aggregation: str
|
|
89
|
+
witness_interpretation: str
|
|
90
|
+
reference_target: float | None = None
|
|
91
|
+
bounds: tuple[float | None, float | None] | None = None
|
|
92
|
+
tolerance: float | None = None
|
|
93
|
+
|
|
94
|
+
def __post_init__(self) -> None:
|
|
95
|
+
_token(self.name, "metric name")
|
|
96
|
+
if type(self.role) is not MetricRole:
|
|
97
|
+
raise TypeError("role must be an exact MetricRole")
|
|
98
|
+
if type(self.sense) is not MetricSense:
|
|
99
|
+
raise TypeError("sense must be an exact MetricSense")
|
|
100
|
+
expected_prefix = f"{self.role.value}:"
|
|
101
|
+
if (
|
|
102
|
+
type(self.metric_id) is not str
|
|
103
|
+
or not self.metric_id.startswith(expected_prefix)
|
|
104
|
+
or _TOKEN.fullmatch(self.metric_id[len(expected_prefix) :]) is None
|
|
105
|
+
):
|
|
106
|
+
raise ValueError(
|
|
107
|
+
"metric_id must be '<role>:<closed-token-name>' and match role"
|
|
108
|
+
)
|
|
109
|
+
_nonempty(self.definition, "metric definition")
|
|
110
|
+
_nonempty(self.aggregation, "metric aggregation")
|
|
111
|
+
_nonempty(self.witness_interpretation, "witness_interpretation")
|
|
112
|
+
target = _finite_optional(self.reference_target, "reference_target")
|
|
113
|
+
tolerance = _finite_optional(self.tolerance, "tolerance")
|
|
114
|
+
if tolerance is not None and tolerance < 0:
|
|
115
|
+
raise ValueError("tolerance must be non-negative")
|
|
116
|
+
if self.sense is MetricSense.TARGET and target is None:
|
|
117
|
+
raise ValueError("target-sense metrics require reference_target")
|
|
118
|
+
if self.bounds is not None:
|
|
119
|
+
if type(self.bounds) is not tuple or len(self.bounds) != 2:
|
|
120
|
+
raise TypeError("bounds must be an exact (lower, upper) tuple")
|
|
121
|
+
lower = _finite_optional(self.bounds[0], "bounds lower")
|
|
122
|
+
upper = _finite_optional(self.bounds[1], "bounds upper")
|
|
123
|
+
if lower is None and upper is None:
|
|
124
|
+
raise ValueError("bounds must publish at least one endpoint")
|
|
125
|
+
if lower is not None and upper is not None and lower > upper:
|
|
126
|
+
raise ValueError("bounds lower endpoint exceeds upper endpoint")
|
|
127
|
+
elif self.sense is MetricSense.SATISFY_BOUNDS:
|
|
128
|
+
raise ValueError("satisfy-bounds metrics require bounds")
|
|
129
|
+
|
|
130
|
+
def to_record(self) -> dict[str, object]:
|
|
131
|
+
return {
|
|
132
|
+
"metric_id": self.metric_id,
|
|
133
|
+
"name": self.name,
|
|
134
|
+
"role": self.role.value,
|
|
135
|
+
"sense": self.sense.value,
|
|
136
|
+
"definition": self.definition,
|
|
137
|
+
"aggregation": self.aggregation,
|
|
138
|
+
"reference_target": self.reference_target,
|
|
139
|
+
"bounds": None if self.bounds is None else list(self.bounds),
|
|
140
|
+
"tolerance": self.tolerance,
|
|
141
|
+
"witness_interpretation": self.witness_interpretation,
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@dataclass(frozen=True, slots=True)
|
|
146
|
+
class OutcomeOrderingSemantics:
|
|
147
|
+
"""Human-readable ordering bound to the executable relation policy."""
|
|
148
|
+
|
|
149
|
+
kind: OutcomeOrderingKind
|
|
150
|
+
metric_priority: tuple[str, ...]
|
|
151
|
+
description: str
|
|
152
|
+
equivalence: str
|
|
153
|
+
policy_id: str
|
|
154
|
+
policy_version: int
|
|
155
|
+
definition_sha256: str
|
|
156
|
+
|
|
157
|
+
def __post_init__(self) -> None:
|
|
158
|
+
if type(self.kind) is not OutcomeOrderingKind:
|
|
159
|
+
raise TypeError("kind must be an exact OutcomeOrderingKind")
|
|
160
|
+
if type(self.metric_priority) is not tuple or not self.metric_priority:
|
|
161
|
+
raise ValueError("metric_priority must be a non-empty exact tuple")
|
|
162
|
+
if any(type(value) is not str or not value for value in self.metric_priority):
|
|
163
|
+
raise TypeError("metric_priority entries must be non-empty strings")
|
|
164
|
+
if len(set(self.metric_priority)) != len(self.metric_priority):
|
|
165
|
+
raise ValueError("metric_priority must not contain duplicates")
|
|
166
|
+
_nonempty(self.description, "outcome ordering description")
|
|
167
|
+
_nonempty(self.equivalence, "outcome equivalence description")
|
|
168
|
+
_token(self.policy_id, "outcome policy_id")
|
|
169
|
+
if type(self.policy_version) is not int or self.policy_version <= 0:
|
|
170
|
+
raise ValueError("outcome policy_version must be a positive exact integer")
|
|
171
|
+
require_sha256(self.definition_sha256, "outcome definition_sha256")
|
|
172
|
+
|
|
173
|
+
@property
|
|
174
|
+
def relation_identity(self) -> tuple[str, int, str]:
|
|
175
|
+
return self.policy_id, self.policy_version, self.definition_sha256
|
|
176
|
+
|
|
177
|
+
def to_record(self) -> dict[str, object]:
|
|
178
|
+
return {
|
|
179
|
+
"kind": self.kind.value,
|
|
180
|
+
"metric_priority": list(self.metric_priority),
|
|
181
|
+
"description": self.description,
|
|
182
|
+
"equivalence": self.equivalence,
|
|
183
|
+
"relation_policy": {
|
|
184
|
+
"policy_id": self.policy_id,
|
|
185
|
+
"policy_version": self.policy_version,
|
|
186
|
+
"definition_sha256": self.definition_sha256,
|
|
187
|
+
},
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
@dataclass(frozen=True, slots=True)
|
|
192
|
+
class OptimizationSemantics:
|
|
193
|
+
"""Versioned semantic contract supplied by a benchmark adapter."""
|
|
194
|
+
|
|
195
|
+
semantics_id: str
|
|
196
|
+
semantics_version: int
|
|
197
|
+
metrics: tuple[MetricSemantics, ...]
|
|
198
|
+
outcome_ordering: OutcomeOrderingSemantics
|
|
199
|
+
definition_sha256: str = field(init=False)
|
|
200
|
+
|
|
201
|
+
def __post_init__(self) -> None:
|
|
202
|
+
_token(self.semantics_id, "semantics_id")
|
|
203
|
+
if type(self.semantics_version) is not int or self.semantics_version <= 0:
|
|
204
|
+
raise ValueError("semantics_version must be a positive exact integer")
|
|
205
|
+
if type(self.metrics) is not tuple or not self.metrics:
|
|
206
|
+
raise ValueError("metrics must be a non-empty exact tuple")
|
|
207
|
+
for metric in self.metrics:
|
|
208
|
+
if type(metric) is not MetricSemantics:
|
|
209
|
+
raise TypeError("metrics must contain exact MetricSemantics values")
|
|
210
|
+
MetricSemantics.__post_init__(metric)
|
|
211
|
+
metric_ids = tuple(metric.metric_id for metric in self.metrics)
|
|
212
|
+
if len(set(metric_ids)) != len(metric_ids):
|
|
213
|
+
raise ValueError("metric IDs must be unique")
|
|
214
|
+
if type(self.outcome_ordering) is not OutcomeOrderingSemantics:
|
|
215
|
+
raise TypeError(
|
|
216
|
+
"outcome_ordering must be an exact OutcomeOrderingSemantics"
|
|
217
|
+
)
|
|
218
|
+
OutcomeOrderingSemantics.__post_init__(self.outcome_ordering)
|
|
219
|
+
missing = set(self.outcome_ordering.metric_priority) - set(metric_ids)
|
|
220
|
+
if missing:
|
|
221
|
+
raise ValueError(
|
|
222
|
+
"outcome metric_priority references unknown metrics: "
|
|
223
|
+
+ ", ".join(sorted(missing))
|
|
224
|
+
)
|
|
225
|
+
encoded = json.dumps(
|
|
226
|
+
self._definition_record(),
|
|
227
|
+
allow_nan=False,
|
|
228
|
+
ensure_ascii=True,
|
|
229
|
+
separators=(",", ":"),
|
|
230
|
+
sort_keys=True,
|
|
231
|
+
).encode("ascii")
|
|
232
|
+
object.__setattr__(
|
|
233
|
+
self,
|
|
234
|
+
"definition_sha256",
|
|
235
|
+
hashlib.sha256(_SEMANTICS_HASH_DOMAIN + encoded).hexdigest(),
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
def _definition_record(self) -> dict[str, object]:
|
|
239
|
+
return {
|
|
240
|
+
"schema_version": 1,
|
|
241
|
+
"semantics_id": self.semantics_id,
|
|
242
|
+
"semantics_version": self.semantics_version,
|
|
243
|
+
"metrics": [metric.to_record() for metric in self.metrics],
|
|
244
|
+
"outcome_ordering": self.outcome_ordering.to_record(),
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
@property
|
|
248
|
+
def identity(self) -> tuple[str, int, str]:
|
|
249
|
+
return self.semantics_id, self.semantics_version, self.definition_sha256
|
|
250
|
+
|
|
251
|
+
def to_record(self) -> dict[str, object]:
|
|
252
|
+
return {
|
|
253
|
+
**self._definition_record(),
|
|
254
|
+
"definition_sha256": self.definition_sha256,
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
def validate_binding(
|
|
258
|
+
self,
|
|
259
|
+
objectives: Sequence[ObjectiveSpec],
|
|
260
|
+
outcome_relation_identity: tuple[str, int, str],
|
|
261
|
+
) -> None:
|
|
262
|
+
"""Bind published prose to executable objective and relation semantics."""
|
|
263
|
+
|
|
264
|
+
validate_objective_specs(objectives)
|
|
265
|
+
if self.outcome_ordering.relation_identity != outcome_relation_identity:
|
|
266
|
+
raise ValueError(
|
|
267
|
+
"optimization semantics outcome ordering differs from the "
|
|
268
|
+
"executable outcome relation"
|
|
269
|
+
)
|
|
270
|
+
objective_metrics = {
|
|
271
|
+
metric.name: metric
|
|
272
|
+
for metric in self.metrics
|
|
273
|
+
if metric.role is MetricRole.OBJECTIVE
|
|
274
|
+
}
|
|
275
|
+
expected_names = {objective.name for objective in objectives}
|
|
276
|
+
if set(objective_metrics) != expected_names:
|
|
277
|
+
raise ValueError(
|
|
278
|
+
"optimization semantics objective metrics differ from declared "
|
|
279
|
+
"problem objectives"
|
|
280
|
+
)
|
|
281
|
+
for objective in objectives:
|
|
282
|
+
expected_sense = (
|
|
283
|
+
MetricSense.MINIMIZE
|
|
284
|
+
if objective.goal == "min"
|
|
285
|
+
else MetricSense.MAXIMIZE
|
|
286
|
+
)
|
|
287
|
+
if objective_metrics[objective.name].sense is not expected_sense:
|
|
288
|
+
raise ValueError(
|
|
289
|
+
f"optimization semantics sense differs for {objective.name!r}"
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def render_optimization_semantics(semantics: OptimizationSemantics) -> str:
|
|
294
|
+
"""Return the canonical prompt block shared by proposal and reflection."""
|
|
295
|
+
|
|
296
|
+
if type(semantics) is not OptimizationSemantics:
|
|
297
|
+
raise TypeError("semantics must be an exact OptimizationSemantics")
|
|
298
|
+
OptimizationSemantics.__post_init__(semantics)
|
|
299
|
+
payload = json.dumps(
|
|
300
|
+
semantics.to_record(),
|
|
301
|
+
allow_nan=False,
|
|
302
|
+
ensure_ascii=True,
|
|
303
|
+
separators=(",", ":"),
|
|
304
|
+
sort_keys=True,
|
|
305
|
+
)
|
|
306
|
+
return "\n".join(
|
|
307
|
+
(
|
|
308
|
+
"OPTIMIZATION SEMANTICS (VERSIONED, AUTHORITATIVE)",
|
|
309
|
+
"Use these exact metric definitions, witness signs, and outcome "
|
|
310
|
+
"ordering; do not infer semantics from metric names.",
|
|
311
|
+
payload,
|
|
312
|
+
)
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
__all__ = [
|
|
317
|
+
"MetricRole",
|
|
318
|
+
"MetricSemantics",
|
|
319
|
+
"MetricSense",
|
|
320
|
+
"OptimizationSemantics",
|
|
321
|
+
"OutcomeOrderingKind",
|
|
322
|
+
"OutcomeOrderingSemantics",
|
|
323
|
+
"render_optimization_semantics",
|
|
324
|
+
]
|