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,559 @@
|
|
|
1
|
+
"""Sealed *model-authored* candidates: replay by content, not by menu index.
|
|
2
|
+
|
|
3
|
+
The finite variation catalogue (:mod:`agent_evolve.domain.finite_variation`)
|
|
4
|
+
seals a decision as an **opaque option identifier** and lets trusted benchmark
|
|
5
|
+
code own every child configuration. That makes replay trivial -- resolve the id
|
|
6
|
+
against the sealed contract -- at the cost of deleting the operator: the model
|
|
7
|
+
never authors a genotype, it filters a list.
|
|
8
|
+
|
|
9
|
+
This module is the other half of that trade. A generative proposal seals the
|
|
10
|
+
**emitted configuration itself**, together with the exact prompt that produced
|
|
11
|
+
it and the schema that bounded it, so a replay reconstructs the decision from
|
|
12
|
+
the emission rather than from a catalogue index. Nothing here needs a
|
|
13
|
+
provider, a network, or a pre-enumerated option set.
|
|
14
|
+
|
|
15
|
+
Three properties are preserved from the catalogue scheme, and one is
|
|
16
|
+
deliberately given up.
|
|
17
|
+
|
|
18
|
+
Preserved:
|
|
19
|
+
|
|
20
|
+
``provider-free replay`` the configuration is stored verbatim as canonical
|
|
21
|
+
typed JSON, so replay is a parse, not a call.
|
|
22
|
+
``content addressing`` every record self-authenticates under a separated
|
|
23
|
+
hash domain, and calls are chained, so a call that
|
|
24
|
+
did not happen cannot be inserted after the fact.
|
|
25
|
+
``support pinning`` ``candidate_schema_sha256`` records the exact schema
|
|
26
|
+
the emission was drawn from, which is what makes a
|
|
27
|
+
matched null checkable: the null must sample *that*
|
|
28
|
+
schema, not some other one.
|
|
29
|
+
|
|
30
|
+
Given up, on purpose:
|
|
31
|
+
|
|
32
|
+
``bounded model authority`` the model now authors configurations. That is the
|
|
33
|
+
mechanism the catalogue was suppressing, so the
|
|
34
|
+
replacement guarantee is feasibility rather than
|
|
35
|
+
enumeration -- every emission carries the verdict
|
|
36
|
+
the problem's own ``validate`` returned for it, and
|
|
37
|
+
replay re-runs ``validate`` and requires agreement.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
from __future__ import annotations
|
|
41
|
+
|
|
42
|
+
import hashlib
|
|
43
|
+
import re
|
|
44
|
+
from dataclasses import dataclass
|
|
45
|
+
|
|
46
|
+
from agent_evolve.domain.patch import require_sha256
|
|
47
|
+
from agent_evolve.domain.typed_json import (
|
|
48
|
+
FrozenJsonObject,
|
|
49
|
+
canonical_typed_json_bytes,
|
|
50
|
+
freeze_json,
|
|
51
|
+
typed_json_sha256,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
__all__ = [
|
|
55
|
+
"GENESIS_CALL_SHA256",
|
|
56
|
+
"GenerativeEmission",
|
|
57
|
+
"GenerativeProposalCall",
|
|
58
|
+
"MAX_EMISSIONS_PER_CALL",
|
|
59
|
+
"SealedGuidanceCall",
|
|
60
|
+
"SealedRunHeader",
|
|
61
|
+
"chain_sealed_calls",
|
|
62
|
+
"generative_prompt_sha256",
|
|
63
|
+
"validate_generative_emission",
|
|
64
|
+
"validate_generative_proposal_call",
|
|
65
|
+
"validate_sealed_guidance_call",
|
|
66
|
+
"validate_sealed_run_header",
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
_TOKEN = re.compile(r"^[a-z][a-z0-9_.-]{0,95}$")
|
|
71
|
+
_MODEL_ID = re.compile(r"^[A-Za-z0-9][A-Za-z0-9_.:/-]{0,255}$")
|
|
72
|
+
_MAX_REASON_BYTES = 4_096
|
|
73
|
+
|
|
74
|
+
#: An emitted batch is a proposal, not a corpus. The loop asks for at most a
|
|
75
|
+
#: generation's worth; anything larger is a runaway model, not a decision.
|
|
76
|
+
MAX_EMISSIONS_PER_CALL = 256
|
|
77
|
+
|
|
78
|
+
#: The predecessor digest of the first call in a campaign. A chain that starts
|
|
79
|
+
#: anywhere else is a chain with a missing head.
|
|
80
|
+
GENESIS_CALL_SHA256 = "0" * 64
|
|
81
|
+
|
|
82
|
+
#: Guidance text that survives into the next prompt. A model that writes a
|
|
83
|
+
#: paragraph of insight and then reads it back next generation is running a
|
|
84
|
+
#: feedback loop, and replaying the proposals without it would reconstruct a
|
|
85
|
+
#: different question. Bounded so a runaway generation cannot be sealed.
|
|
86
|
+
MAX_GUIDANCE_BYTES = 262_144
|
|
87
|
+
|
|
88
|
+
_PROMPT_HASH_DOMAIN = b"agent-evolve:generative-proposal-prompt:v1\x00"
|
|
89
|
+
_EMISSION_HASH_DOMAIN = b"agent-evolve:generative-proposal-emission:v1\x00"
|
|
90
|
+
_CALL_HASH_DOMAIN = b"agent-evolve:generative-proposal-call:v1\x00"
|
|
91
|
+
_GUIDANCE_CALL_HASH_DOMAIN = b"agent-evolve:generative-guidance-call:v1\x00"
|
|
92
|
+
_RUN_HEADER_HASH_DOMAIN = b"agent-evolve:generative-run-header:v1\x00"
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _frame(payload: bytes) -> bytes:
|
|
96
|
+
if type(payload) is not bytes:
|
|
97
|
+
raise TypeError("framed payloads must be exact bytes")
|
|
98
|
+
return len(payload).to_bytes(8, "big", signed=False) + payload
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _bounded_reason(value: str) -> bytes:
|
|
102
|
+
if type(value) is not str:
|
|
103
|
+
raise TypeError("rejection_reason must be an exact string")
|
|
104
|
+
encoded = value.encode("utf-8", errors="strict")
|
|
105
|
+
if len(encoded) > _MAX_REASON_BYTES:
|
|
106
|
+
raise ValueError("rejection_reason exceeds its byte limit")
|
|
107
|
+
return encoded
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def generative_prompt_sha256(instruction: str) -> str:
|
|
111
|
+
"""Digest the exact instruction text a generative call was issued with.
|
|
112
|
+
|
|
113
|
+
The prompt is hashed rather than stored: it is reconstructible from the
|
|
114
|
+
sealed campaign inputs, and a hash is what a replay needs in order to prove
|
|
115
|
+
it is answering the same question. Domain separation keeps this digest from
|
|
116
|
+
colliding with any other use of the same bytes.
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
if type(instruction) is not str:
|
|
120
|
+
raise TypeError("instruction must be an exact string")
|
|
121
|
+
if not instruction:
|
|
122
|
+
raise ValueError("instruction must be non-empty")
|
|
123
|
+
return hashlib.sha256(
|
|
124
|
+
_PROMPT_HASH_DOMAIN + _frame(instruction.encode("utf-8", errors="strict"))
|
|
125
|
+
).hexdigest()
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@dataclass(frozen=True, slots=True, eq=False)
|
|
129
|
+
class GenerativeEmission:
|
|
130
|
+
"""One configuration the model authored, with the verdict it earned.
|
|
131
|
+
|
|
132
|
+
``configuration`` is the complete candidate, frozen typed JSON, exactly as
|
|
133
|
+
it will be handed to ``materialize``. ``accepted`` is what the problem's
|
|
134
|
+
``validate`` said about it at emission time; a replay that re-validates and
|
|
135
|
+
disagrees is a broken replay, not a repaired one.
|
|
136
|
+
"""
|
|
137
|
+
|
|
138
|
+
configuration: FrozenJsonObject
|
|
139
|
+
accepted: bool
|
|
140
|
+
rejection_reason: str = ""
|
|
141
|
+
|
|
142
|
+
def __post_init__(self) -> None:
|
|
143
|
+
if type(self.configuration) is not FrozenJsonObject:
|
|
144
|
+
raise TypeError("configuration must be an exact FrozenJsonObject")
|
|
145
|
+
if freeze_json(self.configuration) is not self.configuration:
|
|
146
|
+
raise TypeError("configuration must already be frozen typed JSON")
|
|
147
|
+
if type(self.accepted) is not bool:
|
|
148
|
+
raise TypeError("accepted must be an exact bool")
|
|
149
|
+
_bounded_reason(self.rejection_reason)
|
|
150
|
+
if self.accepted and self.rejection_reason:
|
|
151
|
+
raise ValueError("an accepted emission carries no rejection reason")
|
|
152
|
+
if not self.accepted and not self.rejection_reason:
|
|
153
|
+
raise ValueError(
|
|
154
|
+
"a rejected emission must carry the reason validate() gave, "
|
|
155
|
+
"because that reason is what the proposer was shown"
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
@property
|
|
159
|
+
def configuration_sha256(self) -> str:
|
|
160
|
+
validate_generative_emission(self)
|
|
161
|
+
return typed_json_sha256(self.configuration)
|
|
162
|
+
|
|
163
|
+
@property
|
|
164
|
+
def identity_sha256(self) -> str:
|
|
165
|
+
"""Bind the full configuration and its feasibility verdict."""
|
|
166
|
+
|
|
167
|
+
validate_generative_emission(self)
|
|
168
|
+
digest = hashlib.sha256()
|
|
169
|
+
digest.update(_EMISSION_HASH_DOMAIN)
|
|
170
|
+
digest.update(_frame(canonical_typed_json_bytes(self.configuration)))
|
|
171
|
+
digest.update(b"\x01" if self.accepted else b"\x00")
|
|
172
|
+
digest.update(_frame(_bounded_reason(self.rejection_reason)))
|
|
173
|
+
return digest.hexdigest()
|
|
174
|
+
|
|
175
|
+
def to_record(self) -> dict[str, object]:
|
|
176
|
+
"""Return the durable projection. The configuration is *not* elided.
|
|
177
|
+
|
|
178
|
+
A catalogue seal can publish an option id and stay content-free because
|
|
179
|
+
the contract holds the child. Here the emission is the only copy, so
|
|
180
|
+
replay needs it in full.
|
|
181
|
+
"""
|
|
182
|
+
|
|
183
|
+
validate_generative_emission(self)
|
|
184
|
+
return {
|
|
185
|
+
"configuration": _thawed(self.configuration),
|
|
186
|
+
"configuration_sha256": self.configuration_sha256,
|
|
187
|
+
"accepted": self.accepted,
|
|
188
|
+
"rejection_reason": self.rejection_reason,
|
|
189
|
+
"emission_identity_sha256": self.identity_sha256,
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
def _validated_values(self) -> tuple[object, ...]:
|
|
193
|
+
validate_generative_emission(self)
|
|
194
|
+
return (
|
|
195
|
+
canonical_typed_json_bytes(self.configuration),
|
|
196
|
+
self.accepted,
|
|
197
|
+
self.rejection_reason,
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
def __eq__(self, other: object) -> bool:
|
|
201
|
+
if type(self) is not GenerativeEmission or type(other) is not GenerativeEmission:
|
|
202
|
+
return False
|
|
203
|
+
return self._validated_values() == other._validated_values()
|
|
204
|
+
|
|
205
|
+
def __hash__(self) -> int:
|
|
206
|
+
return hash((GenerativeEmission, self._validated_values()))
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def _thawed(value: FrozenJsonObject) -> dict[str, object]:
|
|
210
|
+
from agent_evolve.domain.typed_json import thaw_json
|
|
211
|
+
|
|
212
|
+
thawed = thaw_json(value)
|
|
213
|
+
if type(thawed) is not dict:
|
|
214
|
+
raise TypeError("a frozen JSON object must thaw to an exact dict")
|
|
215
|
+
return thawed
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def validate_generative_emission(emission: GenerativeEmission) -> None:
|
|
219
|
+
"""Revalidate an exact emission at a public trust boundary."""
|
|
220
|
+
|
|
221
|
+
if type(emission) is not GenerativeEmission:
|
|
222
|
+
raise TypeError("emission must be an exact GenerativeEmission")
|
|
223
|
+
GenerativeEmission.__post_init__(emission)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
@dataclass(frozen=True, slots=True, eq=False)
|
|
227
|
+
class GenerativeProposalCall:
|
|
228
|
+
"""One sealed model call: what was asked, what came back, and after what.
|
|
229
|
+
|
|
230
|
+
``previous_call_sha256`` chains the calls of a campaign in issue order. The
|
|
231
|
+
chain is the part that makes fabrication detectable: a record invented for a
|
|
232
|
+
call that never happened cannot be spliced in without recomputing every
|
|
233
|
+
digest after it, and the campaign's terminal digest is published.
|
|
234
|
+
"""
|
|
235
|
+
|
|
236
|
+
call_ordinal: int
|
|
237
|
+
op: str
|
|
238
|
+
requested_model: str
|
|
239
|
+
prompt_sha256: str
|
|
240
|
+
candidate_schema_sha256: str
|
|
241
|
+
emissions: tuple[GenerativeEmission, ...]
|
|
242
|
+
previous_call_sha256: str = GENESIS_CALL_SHA256
|
|
243
|
+
|
|
244
|
+
def __post_init__(self) -> None:
|
|
245
|
+
if type(self.call_ordinal) is not int or self.call_ordinal < 0:
|
|
246
|
+
raise ValueError("call_ordinal must be a non-negative exact integer")
|
|
247
|
+
if type(self.op) is not str or _TOKEN.fullmatch(self.op) is None:
|
|
248
|
+
raise ValueError("op must use the closed lowercase token grammar")
|
|
249
|
+
if (
|
|
250
|
+
type(self.requested_model) is not str
|
|
251
|
+
or _MODEL_ID.fullmatch(self.requested_model) is None
|
|
252
|
+
):
|
|
253
|
+
raise ValueError("requested_model must be a closed model identifier")
|
|
254
|
+
require_sha256(self.prompt_sha256, "prompt_sha256")
|
|
255
|
+
require_sha256(self.candidate_schema_sha256, "candidate_schema_sha256")
|
|
256
|
+
require_sha256(self.previous_call_sha256, "previous_call_sha256")
|
|
257
|
+
if type(self.emissions) is not tuple:
|
|
258
|
+
raise TypeError("emissions must be an exact tuple")
|
|
259
|
+
if not self.emissions:
|
|
260
|
+
raise ValueError(
|
|
261
|
+
"a sealed call must carry at least one emission; a call that "
|
|
262
|
+
"returned nothing is a failure to record as a failure, not an "
|
|
263
|
+
"empty success"
|
|
264
|
+
)
|
|
265
|
+
if len(self.emissions) > MAX_EMISSIONS_PER_CALL:
|
|
266
|
+
raise ValueError("emission batch exceeds its limit")
|
|
267
|
+
for emission in self.emissions:
|
|
268
|
+
validate_generative_emission(emission)
|
|
269
|
+
|
|
270
|
+
@property
|
|
271
|
+
def identity_sha256(self) -> str:
|
|
272
|
+
"""Bind the request identity, every emission, and the predecessor."""
|
|
273
|
+
|
|
274
|
+
validate_generative_proposal_call(self)
|
|
275
|
+
digest = hashlib.sha256()
|
|
276
|
+
digest.update(_CALL_HASH_DOMAIN)
|
|
277
|
+
digest.update(bytes.fromhex(self.previous_call_sha256))
|
|
278
|
+
digest.update(self.call_ordinal.to_bytes(8, "big", signed=False))
|
|
279
|
+
digest.update(_frame(self.op.encode("ascii")))
|
|
280
|
+
digest.update(_frame(self.requested_model.encode("ascii")))
|
|
281
|
+
digest.update(bytes.fromhex(self.prompt_sha256))
|
|
282
|
+
digest.update(bytes.fromhex(self.candidate_schema_sha256))
|
|
283
|
+
digest.update(len(self.emissions).to_bytes(8, "big", signed=False))
|
|
284
|
+
for emission in self.emissions:
|
|
285
|
+
digest.update(bytes.fromhex(emission.identity_sha256))
|
|
286
|
+
return digest.hexdigest()
|
|
287
|
+
|
|
288
|
+
@property
|
|
289
|
+
def accepted_configurations(self) -> tuple[FrozenJsonObject, ...]:
|
|
290
|
+
validate_generative_proposal_call(self)
|
|
291
|
+
return tuple(e.configuration for e in self.emissions if e.accepted)
|
|
292
|
+
|
|
293
|
+
def to_record(self) -> dict[str, object]:
|
|
294
|
+
validate_generative_proposal_call(self)
|
|
295
|
+
return {
|
|
296
|
+
"schema_version": 1,
|
|
297
|
+
"record_kind": "proposal",
|
|
298
|
+
"call_ordinal": self.call_ordinal,
|
|
299
|
+
"op": self.op,
|
|
300
|
+
"requested_model": self.requested_model,
|
|
301
|
+
"prompt_sha256": self.prompt_sha256,
|
|
302
|
+
"candidate_schema_sha256": self.candidate_schema_sha256,
|
|
303
|
+
"previous_call_sha256": self.previous_call_sha256,
|
|
304
|
+
"emissions": [e.to_record() for e in self.emissions],
|
|
305
|
+
"call_identity_sha256": self.identity_sha256,
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
def _validated_values(self) -> tuple[object, ...]:
|
|
309
|
+
validate_generative_proposal_call(self)
|
|
310
|
+
return (
|
|
311
|
+
self.call_ordinal,
|
|
312
|
+
self.op,
|
|
313
|
+
self.requested_model,
|
|
314
|
+
self.prompt_sha256,
|
|
315
|
+
self.candidate_schema_sha256,
|
|
316
|
+
self.previous_call_sha256,
|
|
317
|
+
tuple(e._validated_values() for e in self.emissions),
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
def __eq__(self, other: object) -> bool:
|
|
321
|
+
if (
|
|
322
|
+
type(self) is not GenerativeProposalCall
|
|
323
|
+
or type(other) is not GenerativeProposalCall
|
|
324
|
+
):
|
|
325
|
+
return False
|
|
326
|
+
return self._validated_values() == other._validated_values()
|
|
327
|
+
|
|
328
|
+
def __hash__(self) -> int:
|
|
329
|
+
return hash((GenerativeProposalCall, self._validated_values()))
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def validate_generative_proposal_call(call: GenerativeProposalCall) -> None:
|
|
333
|
+
"""Revalidate an exact call at a public trust boundary."""
|
|
334
|
+
|
|
335
|
+
if type(call) is not GenerativeProposalCall:
|
|
336
|
+
raise TypeError("call must be an exact GenerativeProposalCall")
|
|
337
|
+
GenerativeProposalCall.__post_init__(call)
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
@dataclass(frozen=True, slots=True, eq=False)
|
|
341
|
+
class SealedGuidanceCall:
|
|
342
|
+
"""One sealed model call that returned text rather than configurations.
|
|
343
|
+
|
|
344
|
+
Insight and constraint-guide calls author no candidate, so they are not the
|
|
345
|
+
operator under test -- but their output is *pasted into the next prompt*.
|
|
346
|
+
Leaving them out of the chain would make the next proposal call unreplayable
|
|
347
|
+
for a reason that looks like drift and is really an omission, so they are
|
|
348
|
+
sealed at the same altitude and in the same sequence.
|
|
349
|
+
"""
|
|
350
|
+
|
|
351
|
+
call_ordinal: int
|
|
352
|
+
op: str
|
|
353
|
+
requested_model: str
|
|
354
|
+
prompt_sha256: str
|
|
355
|
+
outputs: tuple[str, ...]
|
|
356
|
+
previous_call_sha256: str = GENESIS_CALL_SHA256
|
|
357
|
+
|
|
358
|
+
def __post_init__(self) -> None:
|
|
359
|
+
if type(self.call_ordinal) is not int or self.call_ordinal < 0:
|
|
360
|
+
raise ValueError("call_ordinal must be a non-negative exact integer")
|
|
361
|
+
if type(self.op) is not str or _TOKEN.fullmatch(self.op) is None:
|
|
362
|
+
raise ValueError("op must use the closed lowercase token grammar")
|
|
363
|
+
if (
|
|
364
|
+
type(self.requested_model) is not str
|
|
365
|
+
or _MODEL_ID.fullmatch(self.requested_model) is None
|
|
366
|
+
):
|
|
367
|
+
raise ValueError("requested_model must be a closed model identifier")
|
|
368
|
+
require_sha256(self.prompt_sha256, "prompt_sha256")
|
|
369
|
+
require_sha256(self.previous_call_sha256, "previous_call_sha256")
|
|
370
|
+
if type(self.outputs) is not tuple:
|
|
371
|
+
raise TypeError("outputs must be an exact tuple")
|
|
372
|
+
total = 0
|
|
373
|
+
for value in self.outputs:
|
|
374
|
+
if type(value) is not str:
|
|
375
|
+
raise TypeError("every guidance output must be an exact string")
|
|
376
|
+
total += len(value.encode("utf-8", errors="strict"))
|
|
377
|
+
if total > MAX_GUIDANCE_BYTES:
|
|
378
|
+
raise ValueError("guidance output exceeds its byte limit")
|
|
379
|
+
|
|
380
|
+
@property
|
|
381
|
+
def identity_sha256(self) -> str:
|
|
382
|
+
validate_sealed_guidance_call(self)
|
|
383
|
+
digest = hashlib.sha256()
|
|
384
|
+
digest.update(_GUIDANCE_CALL_HASH_DOMAIN)
|
|
385
|
+
digest.update(bytes.fromhex(self.previous_call_sha256))
|
|
386
|
+
digest.update(self.call_ordinal.to_bytes(8, "big", signed=False))
|
|
387
|
+
digest.update(_frame(self.op.encode("ascii")))
|
|
388
|
+
digest.update(_frame(self.requested_model.encode("ascii")))
|
|
389
|
+
digest.update(bytes.fromhex(self.prompt_sha256))
|
|
390
|
+
digest.update(len(self.outputs).to_bytes(8, "big", signed=False))
|
|
391
|
+
for value in self.outputs:
|
|
392
|
+
digest.update(_frame(value.encode("utf-8", errors="strict")))
|
|
393
|
+
return digest.hexdigest()
|
|
394
|
+
|
|
395
|
+
def to_record(self) -> dict[str, object]:
|
|
396
|
+
validate_sealed_guidance_call(self)
|
|
397
|
+
return {
|
|
398
|
+
"schema_version": 1,
|
|
399
|
+
"record_kind": "guidance",
|
|
400
|
+
"call_ordinal": self.call_ordinal,
|
|
401
|
+
"op": self.op,
|
|
402
|
+
"requested_model": self.requested_model,
|
|
403
|
+
"prompt_sha256": self.prompt_sha256,
|
|
404
|
+
"previous_call_sha256": self.previous_call_sha256,
|
|
405
|
+
"outputs": list(self.outputs),
|
|
406
|
+
"call_identity_sha256": self.identity_sha256,
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
def _validated_values(self) -> tuple[object, ...]:
|
|
410
|
+
validate_sealed_guidance_call(self)
|
|
411
|
+
return (
|
|
412
|
+
self.call_ordinal,
|
|
413
|
+
self.op,
|
|
414
|
+
self.requested_model,
|
|
415
|
+
self.prompt_sha256,
|
|
416
|
+
self.previous_call_sha256,
|
|
417
|
+
self.outputs,
|
|
418
|
+
)
|
|
419
|
+
|
|
420
|
+
def __eq__(self, other: object) -> bool:
|
|
421
|
+
if type(self) is not SealedGuidanceCall or type(other) is not SealedGuidanceCall:
|
|
422
|
+
return False
|
|
423
|
+
return self._validated_values() == other._validated_values()
|
|
424
|
+
|
|
425
|
+
def __hash__(self) -> int:
|
|
426
|
+
return hash((SealedGuidanceCall, self._validated_values()))
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
def validate_sealed_guidance_call(call: SealedGuidanceCall) -> None:
|
|
430
|
+
"""Revalidate an exact guidance call at a public trust boundary."""
|
|
431
|
+
|
|
432
|
+
if type(call) is not SealedGuidanceCall:
|
|
433
|
+
raise TypeError("call must be an exact SealedGuidanceCall")
|
|
434
|
+
SealedGuidanceCall.__post_init__(call)
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
@dataclass(frozen=True, slots=True, eq=False)
|
|
438
|
+
class SealedRunHeader:
|
|
439
|
+
"""The run-level declarations a replay cannot re-derive from the calls.
|
|
440
|
+
|
|
441
|
+
``provides_insights`` is the reason this record exists. The loop skips
|
|
442
|
+
guidance operations entirely for a proposer that declares it makes none --
|
|
443
|
+
an uninformed baseline is exactly that case -- and a replay has no delegate
|
|
444
|
+
to ask. Guessing produced a call the recording never made, and then a drift
|
|
445
|
+
error about a divergence the replay had itself invented. A declaration that
|
|
446
|
+
changes which calls happen has to be sealed, not inferred.
|
|
447
|
+
"""
|
|
448
|
+
|
|
449
|
+
proposer_id: str
|
|
450
|
+
requested_model: str
|
|
451
|
+
candidate_schema_sha256: str
|
|
452
|
+
provides_insights: bool
|
|
453
|
+
call_ordinal: int = 0
|
|
454
|
+
previous_call_sha256: str = GENESIS_CALL_SHA256
|
|
455
|
+
|
|
456
|
+
def __post_init__(self) -> None:
|
|
457
|
+
if type(self.proposer_id) is not str or _TOKEN.fullmatch(
|
|
458
|
+
self.proposer_id
|
|
459
|
+
) is None:
|
|
460
|
+
raise ValueError("proposer_id must use the closed lowercase token grammar")
|
|
461
|
+
if (
|
|
462
|
+
type(self.requested_model) is not str
|
|
463
|
+
or _MODEL_ID.fullmatch(self.requested_model) is None
|
|
464
|
+
):
|
|
465
|
+
raise ValueError("requested_model must be a closed model identifier")
|
|
466
|
+
require_sha256(self.candidate_schema_sha256, "candidate_schema_sha256")
|
|
467
|
+
if type(self.provides_insights) is not bool:
|
|
468
|
+
raise TypeError("provides_insights must be an exact bool")
|
|
469
|
+
if self.call_ordinal != 0:
|
|
470
|
+
raise ValueError("the run header is always the head of the chain")
|
|
471
|
+
if self.previous_call_sha256 != GENESIS_CALL_SHA256:
|
|
472
|
+
raise ValueError("the run header follows nothing")
|
|
473
|
+
|
|
474
|
+
@property
|
|
475
|
+
def identity_sha256(self) -> str:
|
|
476
|
+
validate_sealed_run_header(self)
|
|
477
|
+
digest = hashlib.sha256()
|
|
478
|
+
digest.update(_RUN_HEADER_HASH_DOMAIN)
|
|
479
|
+
digest.update(_frame(self.proposer_id.encode("ascii")))
|
|
480
|
+
digest.update(_frame(self.requested_model.encode("ascii")))
|
|
481
|
+
digest.update(bytes.fromhex(self.candidate_schema_sha256))
|
|
482
|
+
digest.update(b"\x01" if self.provides_insights else b"\x00")
|
|
483
|
+
return digest.hexdigest()
|
|
484
|
+
|
|
485
|
+
def to_record(self) -> dict[str, object]:
|
|
486
|
+
validate_sealed_run_header(self)
|
|
487
|
+
return {
|
|
488
|
+
"schema_version": 1,
|
|
489
|
+
"record_kind": "run_header",
|
|
490
|
+
"call_ordinal": 0,
|
|
491
|
+
"proposer_id": self.proposer_id,
|
|
492
|
+
"requested_model": self.requested_model,
|
|
493
|
+
"candidate_schema_sha256": self.candidate_schema_sha256,
|
|
494
|
+
"provides_insights": self.provides_insights,
|
|
495
|
+
"previous_call_sha256": self.previous_call_sha256,
|
|
496
|
+
"call_identity_sha256": self.identity_sha256,
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
def __eq__(self, other: object) -> bool:
|
|
500
|
+
if type(self) is not SealedRunHeader or type(other) is not SealedRunHeader:
|
|
501
|
+
return False
|
|
502
|
+
return self.to_record() == other.to_record()
|
|
503
|
+
|
|
504
|
+
def __hash__(self) -> int:
|
|
505
|
+
return hash((SealedRunHeader, self.identity_sha256))
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
def validate_sealed_run_header(header: SealedRunHeader) -> None:
|
|
509
|
+
"""Revalidate an exact run header at a public trust boundary."""
|
|
510
|
+
|
|
511
|
+
if type(header) is not SealedRunHeader:
|
|
512
|
+
raise TypeError("header must be an exact SealedRunHeader")
|
|
513
|
+
SealedRunHeader.__post_init__(header)
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
def chain_sealed_calls(
|
|
517
|
+
calls: tuple[object, ...],
|
|
518
|
+
) -> str:
|
|
519
|
+
"""Verify a campaign's call chain and return its terminal digest.
|
|
520
|
+
|
|
521
|
+
Raises on the three ways a chain can lie: a missing head, a gap or a
|
|
522
|
+
reordering in the ordinals, and a predecessor digest that does not match the
|
|
523
|
+
call it claims to follow. Proposal and guidance calls share one sequence
|
|
524
|
+
because they share one conversation, and their hash domains differ so one
|
|
525
|
+
can never be replayed as the other.
|
|
526
|
+
"""
|
|
527
|
+
|
|
528
|
+
if type(calls) is not tuple:
|
|
529
|
+
raise TypeError("calls must be an exact tuple")
|
|
530
|
+
if not calls:
|
|
531
|
+
raise ValueError("a campaign chain requires at least one call")
|
|
532
|
+
if type(calls[0]) is not SealedRunHeader:
|
|
533
|
+
raise ValueError(
|
|
534
|
+
"a sealed chain begins with its run header; without it a replay "
|
|
535
|
+
"cannot know which operations the recorded proposer declined"
|
|
536
|
+
)
|
|
537
|
+
previous = GENESIS_CALL_SHA256
|
|
538
|
+
for index, call in enumerate(calls):
|
|
539
|
+
if type(call) is SealedRunHeader:
|
|
540
|
+
validate_sealed_run_header(call)
|
|
541
|
+
if index != 0:
|
|
542
|
+
raise ValueError("a run header can only be the head of the chain")
|
|
543
|
+
elif type(call) is GenerativeProposalCall:
|
|
544
|
+
validate_generative_proposal_call(call)
|
|
545
|
+
elif type(call) is SealedGuidanceCall:
|
|
546
|
+
validate_sealed_guidance_call(call)
|
|
547
|
+
else:
|
|
548
|
+
raise TypeError("a sealed chain holds only exact sealed call records")
|
|
549
|
+
if call.call_ordinal != index:
|
|
550
|
+
raise ValueError(
|
|
551
|
+
f"call chain is not contiguous at position {index}: "
|
|
552
|
+
f"ordinal {call.call_ordinal}"
|
|
553
|
+
)
|
|
554
|
+
if call.previous_call_sha256 != previous:
|
|
555
|
+
raise ValueError(
|
|
556
|
+
f"call {index} does not follow the call it claims to follow"
|
|
557
|
+
)
|
|
558
|
+
previous = call.identity_sha256
|
|
559
|
+
return previous
|