cmpnd 0.74.0__tar.gz → 0.76.0__tar.gz
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.
- {cmpnd-0.74.0 → cmpnd-0.76.0}/PKG-INFO +1 -1
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/_gepa_patch.py +1 -2
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/callback.py +2 -14
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/cli/commands/evals.py +1 -1
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/cli/commands/programs.py +3 -3
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/cli/commands/top.py +8 -2
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/cli/verbs.py +1 -1
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/eval_handler.py +5 -19
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/identity.py +0 -17
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/models.py +1 -15
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/optimizers/gepa.py +1 -8
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/optimizers/resume.py +12 -11
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/optimizers/tracker.py +3 -14
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/program_naming.py +4 -7
- {cmpnd-0.74.0 → cmpnd-0.76.0}/docs/cli.md +20 -7
- {cmpnd-0.74.0 → cmpnd-0.76.0}/docs/sdk-instrumentation.md +14 -11
- {cmpnd-0.74.0 → cmpnd-0.76.0}/ingest/cmpnd_ingest/program_names.py +3 -2
- {cmpnd-0.74.0 → cmpnd-0.76.0}/ingest/cmpnd_ingest/trace_facts.py +0 -6
- {cmpnd-0.74.0 → cmpnd-0.76.0}/pyproject.toml +1 -1
- {cmpnd-0.74.0 → cmpnd-0.76.0}/scripts/seed_review_run.py +2 -4
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/conftest.py +14 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_composite_module.py +4 -4
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_module_tracing.py +2 -3
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_optimization_lineage.py +0 -2
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_optimize_review_committee.py +0 -1
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_save_load.py +28 -33
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_trace_structure.py +21 -20
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/load/rlm_shape.py +0 -8
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/parity/test_trace_streaming.py +0 -1
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/real_models/test_multi_client_stress.py +0 -4
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_callback.py +20 -9
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_client_program_names.py +12 -7
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_eval.py +4 -6
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_eval_program_id.py +2 -9
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_exporter.py +1 -2
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_exporter_program_names.py +0 -1
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_exporter_queue.py +0 -1
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_exporter_real.py +2 -3
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_gepa_callback.py +16 -12
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_gepa_resume.py +15 -12
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_identity.py +0 -21
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_ingest_conformance.py +8 -18
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_models.py +17 -7
- cmpnd-0.76.0/tests/test_no_signature_hash_on_the_wire.py +188 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_program_identity.py +3 -4
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_program_naming.py +8 -8
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_repro_reactv2_bugs.py +0 -1
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_reversible_failures.py +1 -2
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_schemas.py +0 -2
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_trace_fact_wire_contract.py +0 -1
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_trace_facts.py +0 -1
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_tracker_enrich.py +3 -2
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_xxh64.py +0 -2
- {cmpnd-0.74.0 → cmpnd-0.76.0}/uv.lock +1 -1
- {cmpnd-0.74.0 → cmpnd-0.76.0}/.gitignore +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/AGENTS.md +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/CLAUDE.md +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/README.md +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/__init__.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/_assessments.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/_authored_import.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/_deployments.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/_exporter_pool.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/_http.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/_program_patch.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/_rlm_patch.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/_runtime_tools.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/_timespec.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/_traces.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/_valsets.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/authored.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/cli/__init__.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/cli/api_client.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/cli/commands/__init__.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/cli/commands/admin.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/cli/commands/assessments.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/cli/commands/auth.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/cli/commands/datasets.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/cli/commands/deployments.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/cli/commands/login.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/cli/commands/optimizations.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/cli/commands/org.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/cli/commands/provider_credentials.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/cli/commands/tool_servers.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/cli/commands/traces.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/cli/commands/valsets.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/cli/credentials.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/cli/deprecation.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/cli/pagination.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/cli/shell.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/cli/trace_render.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/cli/tree_help.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/cli/views.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/client.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/configuration.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/context.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/credentials.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/dataset_sync.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/datasets.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/decorators.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/deployment.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/deployment_metadata.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/deployment_runs.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/execution.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/exporter.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/exporter_http.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/helpers.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/imaging.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/ir/__init__.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/ir/decode.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/ir/encode.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/ir/hash.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/ir/program.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/ir/reflection.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/ir/types.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/ir/xxh64.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/lm_configuration.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/mcp_servers.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/named_programs.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/optimization.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/optimizers/__init__.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/optimizers/gepa_callback.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/packaging.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/programs.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/references.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/retry.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/cmpnd/traces.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/docs/2026-04-02-code-review.md +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/docs/client.md +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/docs/custom-proposer.md +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/docs/plans/2026-04-05-train-val-dataset-capture-design.md +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/docs/plans/2026-04-05-train-val-dataset-capture.md +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/docs/reading-traces.md +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/examples/generalizing_proposer.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/examples/local_ollama.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/ingest/LINEAGE.md +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/ingest/README.md +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/ingest/cmpnd_ingest/__init__.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/ingest/cmpnd_ingest/bodies.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/ingest/cmpnd_ingest/client_floor.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/ingest/cmpnd_ingest/exporter_http.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/ingest/cmpnd_ingest/protocols.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/ingest/cmpnd_ingest/py.typed +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/ingest/cmpnd_ingest/request_log.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/ingest/cmpnd_ingest/retry.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/ingest/pyproject.toml +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/scripts/audit-sdist.sh +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/scripts/capture_review_run.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/scripts/check-pip-install.sh +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/scripts/check_release_artifacts.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/scripts/fixtures/review_run.json.gz +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/scripts/gepa_resume_bug.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/scripts/install-test-env.sh +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/scripts/release-gate.sh +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/scripts/release-real-models.sh +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/scripts/require_version_bump.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/scripts/selfhost_compat.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/scripts/test-in-linux.sh +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/stubs/dspy/__init__.pyi +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/stubs/dspy/primitives/__init__.pyi +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/stubs/dspy/primitives/prediction.pyi +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/stubs/dspy/utils/__init__.pyi +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/stubs/dspy/utils/callback.pyi +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/stubs/dspy/utils/dummies.pyi +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/__init__.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/_credential_route.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/_deployment_signature_helpers.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/_exporter_helpers.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/_fake_clock.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/_identity_helpers.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/_resolve_refs.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/_traced_run.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/conftest.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/__init__.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/committee_task.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/continuation_task.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/data/committee_train.ndjson.gz +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/data/committee_val.ndjson.gz +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/fake_lm.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/helpers.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/target_capabilities.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_assessments_cli.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_capture_prompts.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_dataset_auto_creation.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_deploy_execute.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_deploy_pandas.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_deploy_programs.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_edge_cases.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_example_hash.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_gepa_optimization.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_interpreter_spans.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_lm_accuracy.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_optimization_metric_identity.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_optimize_authored_metric.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_optimize_continuation.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_optimize_custom_proposer.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_optimize_failures.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_optimize_loop.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_optimize_server_owned_completion.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_parallel_export.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_project_attribution.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_react_tool_spans.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_traces_read.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_user_attribution.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/e2e/test_valsets_cli.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/identity_vectors/01_predict_qa.json +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/identity_vectors/02_predict_renamed_field.json +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/identity_vectors/03_chain_of_thought_qa.json +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/identity_vectors/04_predict_richer_types.json +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/identity_vectors/05_composite_two_predicts.json +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/identity_vectors/06_multichaincomparison.json +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/identity_vectors/07_program_of_thought.json +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/identity_vectors/08_opaque_module.json +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/identity_vectors/09_predict_pydantic_field.json +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/identity_vectors/10_react.json +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/identity_vectors/11_refine.json +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/identity_vectors/12_retrieve.json +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/identity_vectors/13_knn.json +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/identity_vectors/14_parallel.json +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/identity_vectors/README.md +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/ingest_conformance.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/integration/__init__.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/integration/authored_optimize/judge.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/integration/authored_optimize/optimize_hosted.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/integration/conftest.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/integration/hosted_mcp_tool_optimize_probe.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/integration/hosted_optimize_probe.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/integration/optimization_run_probe.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/integration/test_cli_deploy_smoketest.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/integration/test_logs_renders_traces.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/integration/test_optimization_run.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/integration/test_optimizing_progress.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/integration/test_unhappy_path.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/load/__init__.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/load/__main__.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/load/drain.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/load/ingest.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/load/latency_transport.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/load/rlm_size_report.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/load/sweep.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/load/test_rlm_shape.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/load/test_rlm_size_report.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/parity/__init__.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/parity/conftest.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/parity/seed_parity.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/parity/test_auth.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/parity/test_datasets.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/parity/test_deployments.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/parity/test_evals.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/parity/test_health.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/parity/test_modules.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/parity/test_optimizations.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/parity/test_programs.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/parity/test_signatures.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/parity/test_traces.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/real_models/__init__.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/real_models/_provider.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/real_models/_readiness.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/real_models/_reliability.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/real_models/_result.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/real_models/mint_bedrock_token.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/real_models/test_bedrock_converse.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/real_models/test_deploy_programs.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/real_models/test_optimize_client_committee.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/real_models/test_optimize_continuation.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/real_models/test_optimize_loop.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/real_models/test_optimize_loop_wasm.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/real_models/test_optimize_stress.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/real_models/test_provider_roles.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/real_models/test_readiness.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/real_models/test_real_provider_twins.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/real_models/test_reliability.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/real_models/test_reliability_classify.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/real_models/test_rlm_wasm.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/real_models/test_trace_search.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/span_reference_fixture.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_adapter_reentrancy.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_assessments_api.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_authored.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_authored_binding_credentials.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_authored_bundle_collisions.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_authored_metric_contract.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_authored_named_models.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_authored_optimize.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_candidate_lineage.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cli/__init__.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cli/conftest.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cli/test_admin.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cli/test_api_client.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cli/test_assessments.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cli/test_auth.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cli/test_credentials.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cli/test_datasets.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cli/test_deployment_runs.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cli/test_deployments.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cli/test_evals.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cli/test_login.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cli/test_main.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cli/test_optimizations.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cli/test_org.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cli/test_pagination.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cli/test_parity.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cli/test_programs.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cli/test_provider_credentials.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cli/test_schema_sample.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cli/test_shell.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cli/test_tool_servers.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cli/test_top.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cli/test_traces.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cli/test_traces_program_and_module.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cli/test_traces_search_wire.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cli/test_tree_help.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cli/test_valsets.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_client.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_client_floor.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_clustering/__init__.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_clustering/conftest.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_clustering/test_edge_cases.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_clustering/test_hash_consistency.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_clustering/test_type_conversion.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_cmp551_grouping_identity.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_configuration.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_context.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_context_propagation.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_credential_kwargs.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_credential_selection.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_credential_values.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_dataset_polling.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_dataset_sync.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_datasets.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_decision_client_spans.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_decorators.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_deploy.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_deploy_mcp_tool_references.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_deploy_program_id.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_deployment_metadata.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_deployment_runs.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_deployments_read.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_eval_example_attribution.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_eval_start.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_eval_trace_grouping.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_exception_paths.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_execute.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_execute_run_identity.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_fake_lm.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_gepa_integration.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_gepa_output_normalization.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_imaging.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_import_weight.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_ingest_second_producer.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_integration.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_interpreter_callback.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_ir_encoder_properties.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_ir_golden_vectors.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_ir_roundtrip.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_lm15_native_calls.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_lm_configuration.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_lm_usage_shapes.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_mcp_tools.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_multi_client_stress_readiness.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_optimization_program_names.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_optimization_progress.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_optimization_start.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_optimize.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_optimize_budget.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_optimize_lift.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_optimize_lms.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_optimize_proposer.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_optimize_reflection_lm.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_optimize_terminal_failure.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_packaging.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_packaging_callable_source.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_packaging_mcp_tools.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_packaging_program_source.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_poll_until.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_program_id_deprecation.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_program_lineage_persist.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_program_names_in_deploy.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_programs_create.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_project_payload.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_real_provider_twins_readiness.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_reflector_properties.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_reflector_smoke.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_release_gate_script.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_release_real_models_script.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_replaced_names.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_require_version_bump.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_retry.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_rlm_patch.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_run_attribution_paths.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_runtime_tools.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_seal_lm_credential.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_seed_review_run.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_signature_inputs.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_span_references.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_span_sent_once.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_system_one.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_trace_context_concurrency.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_trace_render.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_traces_read.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_tracked_gepa.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_truncation.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_upload_auth_headers.py +0 -0
- {cmpnd-0.74.0 → cmpnd-0.76.0}/tests/test_valsets_api.py +0 -0
|
@@ -133,9 +133,8 @@ def _run_tracked_compile(
|
|
|
133
133
|
max_metric_calls=max_metric_calls,
|
|
134
134
|
)
|
|
135
135
|
|
|
136
|
-
# `enrich_from_program` hashed the student, so its generated name reuses that hash.
|
|
137
136
|
if client_config is None and trk.program_id is None and dspy_callback._declared_program_name() is None:
|
|
138
|
-
trk.generated_program_name = program_naming.generated_program_name(student
|
|
137
|
+
trk.generated_program_name = program_naming.generated_program_name(student)
|
|
139
138
|
|
|
140
139
|
restore_attribution = callback.start_trace_attribution()
|
|
141
140
|
|
|
@@ -1188,16 +1188,11 @@ class _ModuleMixin(_CallbackBase):
|
|
|
1188
1188
|
identity.get_field_schema(field_info.annotation) for field_info in output_fields.values()
|
|
1189
1189
|
]
|
|
1190
1190
|
|
|
1191
|
-
span.program_signature_hash = identity.compute_program_hash(instance) or 0
|
|
1192
|
-
|
|
1193
1191
|
# For ChainOfThought, also capture extended signature
|
|
1194
1192
|
if hasattr(instance, "extended_signature"):
|
|
1195
1193
|
ext_sig = instance.extended_signature
|
|
1196
1194
|
span.attributes["extended_signature"] = getattr(ext_sig, "signature", str(ext_sig))
|
|
1197
1195
|
|
|
1198
|
-
else:
|
|
1199
|
-
span.program_signature_hash = identity.compute_program_hash(instance) or 0
|
|
1200
|
-
|
|
1201
1196
|
# Capture demo count and contents if available
|
|
1202
1197
|
demos = getattr(instance, "demos", None)
|
|
1203
1198
|
if demos:
|
|
@@ -1257,9 +1252,6 @@ class _ModuleMixin(_CallbackBase):
|
|
|
1257
1252
|
elif hasattr(instance, "predict") and hasattr(instance.predict, "signature"):
|
|
1258
1253
|
signature = instance.predict.signature
|
|
1259
1254
|
|
|
1260
|
-
# The root module's signature hash, once a branch below computes it. An unnamed
|
|
1261
|
-
# program's generated name reuses it rather than reflecting the module again.
|
|
1262
|
-
program_hash: int | None = None
|
|
1263
1255
|
if signature:
|
|
1264
1256
|
# Single-signature module (Predict, ChainOfThought, etc.)
|
|
1265
1257
|
sig_name = getattr(signature, "__name__", None)
|
|
@@ -1287,12 +1279,10 @@ class _ModuleMixin(_CallbackBase):
|
|
|
1287
1279
|
identity.get_field_schema(field_info.annotation) for field_info in output_fields.values()
|
|
1288
1280
|
]
|
|
1289
1281
|
|
|
1290
|
-
program_hash = identity.compute_program_hash(instance)
|
|
1291
|
-
trace.program_signature_hash = program_hash or 0
|
|
1292
1282
|
trace.signature_summary = identity.build_signature_summary(signature)
|
|
1293
1283
|
else:
|
|
1294
1284
|
# Multi-child module: collect Predict children via DSPy's own walker
|
|
1295
|
-
# for metadata
|
|
1285
|
+
# for metadata.
|
|
1296
1286
|
dspy_mod, _ = _get_dspy()
|
|
1297
1287
|
children: list[tuple[str, Any]] = []
|
|
1298
1288
|
if dspy_mod and hasattr(instance, "named_predictors"):
|
|
@@ -1303,8 +1293,6 @@ class _ModuleMixin(_CallbackBase):
|
|
|
1303
1293
|
|
|
1304
1294
|
if children:
|
|
1305
1295
|
trace.signature_name = instance.__class__.__name__
|
|
1306
|
-
program_hash = identity.compute_program_hash(instance)
|
|
1307
|
-
trace.program_signature_hash = program_hash or 0
|
|
1308
1296
|
|
|
1309
1297
|
# Build component_signatures for grouped field display
|
|
1310
1298
|
components = []
|
|
@@ -1340,7 +1328,7 @@ class _ModuleMixin(_CallbackBase):
|
|
|
1340
1328
|
if trace.program_id is None and trace.declared_name is None:
|
|
1341
1329
|
trace.program_id = context.optimization_program_id(trace.optimization_run_id)
|
|
1342
1330
|
if trace.program_id is None and trace.declared_name is None:
|
|
1343
|
-
trace.generated_name = program_naming.generated_program_name(instance
|
|
1331
|
+
trace.generated_name = program_naming.generated_program_name(instance)
|
|
1344
1332
|
_warn_once_about_generated_name(trace)
|
|
1345
1333
|
|
|
1346
1334
|
# Detect if this is a compiled program (from optimization)
|
|
@@ -13,7 +13,7 @@ def _add_list_args(p: ArgumentParser) -> None:
|
|
|
13
13
|
"--program",
|
|
14
14
|
dest="program_name",
|
|
15
15
|
metavar="NAME",
|
|
16
|
-
help="Only the runs of the program
|
|
16
|
+
help="Only the runs of the program whose current name is NAME",
|
|
17
17
|
)
|
|
18
18
|
p.add_argument(
|
|
19
19
|
"--module",
|
|
@@ -211,9 +211,9 @@ def register(subparsers: _SubParsersAction[ArgumentParser]) -> None:
|
|
|
211
211
|
"rename",
|
|
212
212
|
help="Name or rename a program",
|
|
213
213
|
description=(
|
|
214
|
-
"Make NAME the current name of PROGRAM
|
|
215
|
-
"
|
|
216
|
-
"
|
|
214
|
+
"Make NAME the current name of PROGRAM, which keeps its id and history. The name it had is free at "
|
|
215
|
+
"once: it no longer resolves, and any program can take it, so code that still declares the old name "
|
|
216
|
+
"reaches a new program. Another program's current name is refused."
|
|
217
217
|
),
|
|
218
218
|
)
|
|
219
219
|
rename.add_argument("program", metavar="PROGRAM", help="Program name or p_ id")
|
|
@@ -1440,7 +1440,10 @@ def register(subparsers: _SubParsersAction[ArgumentParser]) -> None:
|
|
|
1440
1440
|
help="Deploy authored Python source (file or stdin)",
|
|
1441
1441
|
description=(
|
|
1442
1442
|
"Stage authored Python without executing it in this process, check its "
|
|
1443
|
-
"entrypoint in a fresh child, and upload the exact staged bundle
|
|
1443
|
+
"entrypoint in a fresh child, and upload the exact staged bundle.\n\n"
|
|
1444
|
+
"The platform deploys only a program a user named. PROGRAM_NAME is such a name. "
|
|
1445
|
+
"A program with no name, or with a name a client generated, is refused until "
|
|
1446
|
+
"`cmpnd programs rename <p_id> <name>` names it."
|
|
1444
1447
|
),
|
|
1445
1448
|
epilog=(
|
|
1446
1449
|
"Examples:\n"
|
|
@@ -1501,7 +1504,10 @@ def register(subparsers: _SubParsersAction[ArgumentParser]) -> None:
|
|
|
1501
1504
|
"dspy.Prediction(score=, feedback=): gepa writes each new instruction by "
|
|
1502
1505
|
"reading that feedback, so a score-only metric is refused before the run "
|
|
1503
1506
|
"starts. `--reflection-model` is required for the same reason — it names "
|
|
1504
|
-
"the model that does the writing
|
|
1507
|
+
"the model that does the writing.\n\n"
|
|
1508
|
+
"The platform optimizes only a program a user named. A --deployment-id whose "
|
|
1509
|
+
"program has no name, or a name a client generated, such as an optimization's "
|
|
1510
|
+
"result, is refused until `cmpnd programs rename <p_id> <name>` names it."
|
|
1505
1511
|
),
|
|
1506
1512
|
epilog=(
|
|
1507
1513
|
"Examples:\n"
|
|
@@ -167,7 +167,7 @@ DOMAIN_VERBS: dict[str, str] = {
|
|
|
167
167
|
"trash": "moves a program to the Trash, where it stays restorable, and delete would read as the permanent purge",
|
|
168
168
|
"restore": "returns a program from the Trash with its history, which create would not",
|
|
169
169
|
"purge": "deletes a program in the Trash for good, the irreversible step after trash",
|
|
170
|
-
"rename": "gives a program a new current name and
|
|
170
|
+
"rename": "gives a program a new current name and frees the old one for any program, which update would hide",
|
|
171
171
|
}
|
|
172
172
|
|
|
173
173
|
#: Leaves naming a related collection or sub-record rather than an action.
|
|
@@ -87,16 +87,10 @@ class EvalHandler:
|
|
|
87
87
|
if program:
|
|
88
88
|
eval_run.module_class = program.__class__.__name__
|
|
89
89
|
|
|
90
|
-
#
|
|
91
|
-
# discriminates correctly; signature_summary is still derived from
|
|
92
|
-
# the root signature for human display.
|
|
93
|
-
program_hash = identity.compute_program_hash(program)
|
|
94
|
-
if program_hash is not None:
|
|
95
|
-
eval_run.program_signature_hash = program_hash
|
|
90
|
+
# The summary comes from the root signature, for human display.
|
|
96
91
|
signature = identity.get_program_signature(program)
|
|
97
92
|
if signature:
|
|
98
93
|
eval_run.signature_summary = identity.build_signature_summary(signature)
|
|
99
|
-
logger.debug(f"Eval run program_signature_hash: {eval_run.program_signature_hash}")
|
|
100
94
|
|
|
101
95
|
# Extract input field names for filtering example inputs in on_evaluate_end
|
|
102
96
|
if hasattr(signature, "input_fields"):
|
|
@@ -177,9 +171,7 @@ class EvalHandler:
|
|
|
177
171
|
eval_run._dataset_exists = None # Will include examples as fallback
|
|
178
172
|
|
|
179
173
|
exp = self._callback._current_exporter()
|
|
180
|
-
eval_run.program_id = self._program_id(
|
|
181
|
-
exp, program, eval_run.program_signature_hash, eval_run.optimization_run_id
|
|
182
|
-
)
|
|
174
|
+
eval_run.program_id = self._program_id(exp, program, eval_run.optimization_run_id)
|
|
183
175
|
|
|
184
176
|
logger.info(
|
|
185
177
|
f"EvalRun created: program_id={eval_run.program_id}, "
|
|
@@ -216,9 +208,7 @@ class EvalHandler:
|
|
|
216
208
|
self._callback._call_id_to_span[call_id] = span
|
|
217
209
|
context.push_span(span)
|
|
218
210
|
|
|
219
|
-
def _program_id(
|
|
220
|
-
self, exp: Any, program: Any, program_hash: int | None, optimization_run_id: str | None
|
|
221
|
-
) -> str | None:
|
|
211
|
+
def _program_id(self, exp: Any, program: Any, optimization_run_id: str | None) -> str | None:
|
|
222
212
|
"""The program id the eval run carries, resolved the way a trace's is.
|
|
223
213
|
|
|
224
214
|
A program name the call declares wins over the callback's program id. A run
|
|
@@ -227,9 +217,7 @@ class EvalHandler:
|
|
|
227
217
|
The exporter resolves either name now, on the caller's thread, because the run's
|
|
228
218
|
start is sent synchronously and must carry the id. The exporter keeps the answer
|
|
229
219
|
for the process, so a name its traces already resolved costs no request. A name
|
|
230
|
-
the exporter cannot resolve leaves the run without an id.
|
|
231
|
-
evaluated program's signature hash, already computed for the run, so naming the
|
|
232
|
-
program does not reflect it again.
|
|
220
|
+
the exporter cannot resolve leaves the run without an id.
|
|
233
221
|
"""
|
|
234
222
|
from . import callback
|
|
235
223
|
|
|
@@ -238,9 +226,7 @@ class EvalHandler:
|
|
|
238
226
|
program_id = self._callback._resolve_program_id() or context.optimization_program_id(optimization_run_id)
|
|
239
227
|
if program_id is not None or program is None:
|
|
240
228
|
return program_id
|
|
241
|
-
return program_naming.resolve_generated_name(
|
|
242
|
-
exp, program_naming.generated_program_name(program, program_hash)
|
|
243
|
-
)
|
|
229
|
+
return program_naming.resolve_generated_name(exp, program_naming.generated_program_name(program))
|
|
244
230
|
# Read with getattr because the member is optional: an in-memory collector
|
|
245
231
|
# that resolves no names has none.
|
|
246
232
|
resolve = getattr(exp, "resolve_program_name", None)
|
|
@@ -97,23 +97,6 @@ def _unsigned_to_signed_int64(value: int) -> int: # pyright: ignore[reportUnuse
|
|
|
97
97
|
return masked - 0x10000000000000000 if masked >= 0x8000000000000000 else masked
|
|
98
98
|
|
|
99
99
|
|
|
100
|
-
def format_signature_hash(value: int | None) -> str | None:
|
|
101
|
-
"""Render a ``program_signature_hash`` for the JSON wire as a quoted decimal
|
|
102
|
-
string (e.g. ``"-935109221252960526"``), or ``None`` when absent.
|
|
103
|
-
|
|
104
|
-
The hash is a signed int64 (xxhash64). Emitting it as a JSON *number* is
|
|
105
|
-
unsafe: any consumer that decodes through an untyped path floats it and
|
|
106
|
-
loses precision above 2^53 (Go ``any``/``map[string]any``, JavaScript
|
|
107
|
-
natively). Carrying it as a string makes the safe representation automatic
|
|
108
|
-
end to end. Storage stays signed int64; only the wire value is a
|
|
109
|
-
string. ``None`` stays ``None`` (nullable optimization hash); the trace/span
|
|
110
|
-
``0`` sentinel renders as ``"0"``.
|
|
111
|
-
"""
|
|
112
|
-
if value is None:
|
|
113
|
-
return None
|
|
114
|
-
return str(value)
|
|
115
|
-
|
|
116
|
-
|
|
117
100
|
# A program id is server-issued: ``p_`` and twelve base62 characters, the shape
|
|
118
101
|
# every platform id shares. The SDK never mints one; it carries the id serve gives
|
|
119
102
|
# a program name, or the id a deployment's worker passes to the kernel.
|
|
@@ -13,7 +13,7 @@ from uuid import UUID, uuid4
|
|
|
13
13
|
|
|
14
14
|
from cmpnd_ingest.trace_facts import CompletionFact, MetadataFact, StartedFact, StringMapChange
|
|
15
15
|
|
|
16
|
-
from . import
|
|
16
|
+
from . import imaging
|
|
17
17
|
|
|
18
18
|
# U+0000 (NUL) and lone UTF-16 surrogates are valid JSON, and valid in a Python
|
|
19
19
|
# str, but the server cannot store either: a JSON column rejects both, and a NUL
|
|
@@ -758,8 +758,6 @@ class SpanBuilder:
|
|
|
758
758
|
# Each element is None for primitives, or a schema dict for complex types
|
|
759
759
|
signature_input_field_schemas: list[dict[str, Any] | None] = field(default_factory=list)
|
|
760
760
|
signature_output_field_schemas: list[dict[str, Any] | None] = field(default_factory=list)
|
|
761
|
-
# Hash of input/output fields+types for program identity (xxhash64, signed)
|
|
762
|
-
program_signature_hash: int = 0
|
|
763
761
|
|
|
764
762
|
# DSPy-specific: Module info
|
|
765
763
|
module_type: str | None = None
|
|
@@ -905,7 +903,6 @@ class SpanBuilder:
|
|
|
905
903
|
"signature_output_field_descs": self.signature_output_field_descs,
|
|
906
904
|
"signature_input_field_schemas": self.signature_input_field_schemas,
|
|
907
905
|
"signature_output_field_schemas": self.signature_output_field_schemas,
|
|
908
|
-
"program_signature_hash": identity.format_signature_hash(self.program_signature_hash),
|
|
909
906
|
"module_type": self.module_type,
|
|
910
907
|
"module_name": self.module_name,
|
|
911
908
|
"model_name": self.model_name,
|
|
@@ -945,7 +942,6 @@ class TraceBuilder:
|
|
|
945
942
|
# The root DSPy module's class. The program's own name is `declared_name`,
|
|
946
943
|
# which the transport resolves to `program_id`.
|
|
947
944
|
module_class: str | None = None
|
|
948
|
-
program_version: str | None = None
|
|
949
945
|
|
|
950
946
|
# Signature info - identifies the program by its inputs/outputs
|
|
951
947
|
signature_name: str | None = None
|
|
@@ -956,7 +952,6 @@ class TraceBuilder:
|
|
|
956
952
|
# Schemas for complex types (Pydantic models, dataclasses)
|
|
957
953
|
signature_input_field_schemas: list[dict[str, Any] | None] = field(default_factory=list)
|
|
958
954
|
signature_output_field_schemas: list[dict[str, Any] | None] = field(default_factory=list)
|
|
959
|
-
program_signature_hash: int = 0 # Hash of input/output fields+types (legacy program key)
|
|
960
955
|
signature_summary: str | None = None # Human-readable: "input1, input2 -> output1, output2"
|
|
961
956
|
component_signatures: list[dict[str, Any]] = field(default_factory=list)
|
|
962
957
|
# The server-issued program id the trace declares (`p_…`), snapshotted from
|
|
@@ -1080,7 +1075,6 @@ class TraceBuilder:
|
|
|
1080
1075
|
"module_class": self.module_class,
|
|
1081
1076
|
# Also under the key a serve from before module_class reads (StartedFact.creation_dict).
|
|
1082
1077
|
"program_name": self.module_class,
|
|
1083
|
-
"program_version": self.program_version,
|
|
1084
1078
|
"signature_name": self.signature_name,
|
|
1085
1079
|
"signature_input_fields": self.signature_input_fields,
|
|
1086
1080
|
"signature_output_fields": self.signature_output_fields,
|
|
@@ -1088,7 +1082,6 @@ class TraceBuilder:
|
|
|
1088
1082
|
"signature_output_field_types": self.signature_output_field_types,
|
|
1089
1083
|
"signature_input_field_schemas": self.signature_input_field_schemas,
|
|
1090
1084
|
"signature_output_field_schemas": self.signature_output_field_schemas,
|
|
1091
|
-
"program_signature_hash": identity.format_signature_hash(self.program_signature_hash),
|
|
1092
1085
|
"signature_summary": self.signature_summary,
|
|
1093
1086
|
# The server forwards this blob verbatim into a jsonb column, and its
|
|
1094
1087
|
# program registration is best-effort (a rejection is only logged), so
|
|
@@ -1123,13 +1116,11 @@ class TraceBuilder:
|
|
|
1123
1116
|
"module_class": self.module_class,
|
|
1124
1117
|
# Also under the key a serve from before module_class reads (StartedFact.creation_dict).
|
|
1125
1118
|
"program_name": self.module_class,
|
|
1126
|
-
"program_version": self.program_version,
|
|
1127
1119
|
"signature_name": self.signature_name,
|
|
1128
1120
|
"signature_input_fields": self.signature_input_fields,
|
|
1129
1121
|
"signature_output_fields": self.signature_output_fields,
|
|
1130
1122
|
"signature_input_field_types": self.signature_input_field_types,
|
|
1131
1123
|
"signature_output_field_types": self.signature_output_field_types,
|
|
1132
|
-
"program_signature_hash": identity.format_signature_hash(self.program_signature_hash),
|
|
1133
1124
|
"signature_summary": self.signature_summary,
|
|
1134
1125
|
"component_signatures": _safe_serialize(self.component_signatures),
|
|
1135
1126
|
"root_span_type": self.root_span_type,
|
|
@@ -1287,9 +1278,6 @@ class EvalRunBuilder:
|
|
|
1287
1278
|
metric_name: str | None = None
|
|
1288
1279
|
dataset_hash: str | None = None
|
|
1289
1280
|
dataset_size: int = 0
|
|
1290
|
-
# The evaluated module's signature hash (legacy program key). None when the run has
|
|
1291
|
-
# no module, and then sent as null.
|
|
1292
|
-
program_signature_hash: int | None = None
|
|
1293
1281
|
signature_summary: str | None = None # Human-readable: "input1, input2 -> output1"
|
|
1294
1282
|
|
|
1295
1283
|
# Model Configuration
|
|
@@ -1411,7 +1399,6 @@ class EvalRunBuilder:
|
|
|
1411
1399
|
"metric_name": self.metric_name or "",
|
|
1412
1400
|
"dataset_hash": self.dataset_hash or "",
|
|
1413
1401
|
"dataset_size": self.dataset_size,
|
|
1414
|
-
"program_signature_hash": identity.format_signature_hash(self.program_signature_hash),
|
|
1415
1402
|
"signature_summary": self.signature_summary,
|
|
1416
1403
|
"model_name": self.model_name,
|
|
1417
1404
|
"model_provider": self.model_provider,
|
|
@@ -1432,7 +1419,6 @@ class EvalRunBuilder:
|
|
|
1432
1419
|
"metric_name": self.metric_name or "",
|
|
1433
1420
|
"dataset_hash": self.dataset_hash or "",
|
|
1434
1421
|
"dataset_size": self.dataset_size,
|
|
1435
|
-
"program_signature_hash": identity.format_signature_hash(self.program_signature_hash),
|
|
1436
1422
|
"signature_summary": self.signature_summary,
|
|
1437
1423
|
"model_name": self.model_name,
|
|
1438
1424
|
"model_provider": self.model_provider,
|
|
@@ -146,10 +146,6 @@ class TrackedGEPA:
|
|
|
146
146
|
|
|
147
147
|
component_signature_hash = identity.compute_signature_hash(config.get("components", []))
|
|
148
148
|
|
|
149
|
-
# Compute program_signature_hash via the IR reflector — same encoder
|
|
150
|
-
# the trace path uses, so optimization_runs and traces join on identity.
|
|
151
|
-
program_signature_hash = identity.compute_program_hash(student) or 0
|
|
152
|
-
|
|
153
149
|
# Initialize optimization tracking
|
|
154
150
|
self._tracker = tracker.OptimizationTracker(
|
|
155
151
|
optimizer_type="gepa",
|
|
@@ -159,7 +155,6 @@ class TrackedGEPA:
|
|
|
159
155
|
reflection_model_name=reflection_model_name,
|
|
160
156
|
valset_hash=valset_hash,
|
|
161
157
|
component_signature_hash=component_signature_hash,
|
|
162
|
-
program_signature_hash=program_signature_hash,
|
|
163
158
|
)
|
|
164
159
|
|
|
165
160
|
# This path builds its tracker without `enrich_from_program`, so it types the
|
|
@@ -170,9 +165,7 @@ class TrackedGEPA:
|
|
|
170
165
|
# SDK generates for the student, the name its rollouts' traces carry, and
|
|
171
166
|
# resolves it when the run starts.
|
|
172
167
|
if self._tracker.program_id is None and callback._declared_program_name() is None:
|
|
173
|
-
self._tracker.generated_program_name = program_naming.generated_program_name(
|
|
174
|
-
student, program_signature_hash
|
|
175
|
-
)
|
|
168
|
+
self._tracker.generated_program_name = program_naming.generated_program_name(student)
|
|
176
169
|
|
|
177
170
|
# Store both sets for dataset payload building
|
|
178
171
|
self._tracker._trainset = list(trainset)
|
|
@@ -30,7 +30,7 @@ def sidecar_path(log_dir: str) -> str:
|
|
|
30
30
|
return os.path.join(log_dir, _SIDECAR)
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
def write_run_id(log_dir: str, run_id: str,
|
|
33
|
+
def write_run_id(log_dir: str, run_id: str, program_id: str | None, start_time: datetime | None) -> None:
|
|
34
34
|
"""Persist the server-assigned ``run_id`` into ``log_dir`` so a later resume
|
|
35
35
|
can re-adopt it. Called at ``start()``, which runs before GEPA creates its
|
|
36
36
|
``run_dir`` — so create the directory if it isn't there yet. Best-effort: a
|
|
@@ -38,7 +38,7 @@ def write_run_id(log_dir: str, run_id: str, program_signature_hash: int | None,
|
|
|
38
38
|
"""
|
|
39
39
|
payload = {
|
|
40
40
|
"run_id": run_id,
|
|
41
|
-
"
|
|
41
|
+
"program_id": program_id,
|
|
42
42
|
"start_time": start_time.isoformat() if start_time is not None else None,
|
|
43
43
|
}
|
|
44
44
|
try:
|
|
@@ -49,15 +49,16 @@ def write_run_id(log_dir: str, run_id: str, program_signature_hash: int | None,
|
|
|
49
49
|
logger.warning("could not write resume sidecar in %s: %s", log_dir, e)
|
|
50
50
|
|
|
51
51
|
|
|
52
|
-
def read_resumable(log_dir: str,
|
|
52
|
+
def read_resumable(log_dir: str, program_id: str | None) -> tuple[str, datetime | None] | None:
|
|
53
53
|
"""Return ``(run_id, start_time)`` to re-adopt, or ``None`` if this is not a
|
|
54
54
|
resumable job.
|
|
55
55
|
|
|
56
56
|
Resumable requires: GEPA's ``gepa_state.bin`` checkpoint present (else GEPA
|
|
57
57
|
itself starts fresh) AND a readable sidecar carrying a ``run_id``. A definite
|
|
58
|
-
``
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
``program_id`` mismatch (a different program reusing the same ``log_dir``) is
|
|
59
|
+
rejected so it can't hijack the id. A missing program id on either side errs
|
|
60
|
+
toward stitching, since ``log_dir`` is the strong identity signal. A sidecar an
|
|
61
|
+
older SDK wrote names no program id, so it stitches.
|
|
61
62
|
"""
|
|
62
63
|
if not os.path.exists(os.path.join(log_dir, _CHECKPOINT)):
|
|
63
64
|
return None
|
|
@@ -71,13 +72,13 @@ def read_resumable(log_dir: str, program_signature_hash: int | None) -> tuple[st
|
|
|
71
72
|
if not run_id:
|
|
72
73
|
return None
|
|
73
74
|
|
|
74
|
-
|
|
75
|
-
if
|
|
75
|
+
prior_program = data.get("program_id")
|
|
76
|
+
if prior_program is not None and program_id is not None and prior_program != program_id:
|
|
76
77
|
logger.warning(
|
|
77
|
-
"resume sidecar in %s is for a different program (
|
|
78
|
+
"resume sidecar in %s is for a different program (%s != %s); not re-adopting",
|
|
78
79
|
log_dir,
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
prior_program,
|
|
81
|
+
program_id,
|
|
81
82
|
)
|
|
82
83
|
return None
|
|
83
84
|
|
|
@@ -274,7 +274,6 @@ class OptimizationTracker:
|
|
|
274
274
|
reflection_model_name: str = "",
|
|
275
275
|
valset_hash: str = "",
|
|
276
276
|
component_signature_hash: str = "",
|
|
277
|
-
program_signature_hash: int = 0,
|
|
278
277
|
):
|
|
279
278
|
# The SDK no longer mints this id. It stays None until start()
|
|
280
279
|
# runs the synchronous start POST and adopts the id assigned by the
|
|
@@ -303,8 +302,6 @@ class OptimizationTracker:
|
|
|
303
302
|
self.trainset_hash = "" # individual trainset hash
|
|
304
303
|
self.valset_individual_hash = "" # individual valset hash
|
|
305
304
|
self.component_signature_hash = component_signature_hash # SHA256[:16] for model sweep grouping
|
|
306
|
-
# Program signature hash - matches trace format (64-bit int from input/output fields+types)
|
|
307
|
-
self.program_signature_hash = program_signature_hash
|
|
308
305
|
self.start_time = datetime.now(timezone.utc)
|
|
309
306
|
|
|
310
307
|
# Collected data
|
|
@@ -751,7 +748,7 @@ class OptimizationTracker:
|
|
|
751
748
|
log_dir = self.config.get("log_dir") if self.config else None
|
|
752
749
|
if not log_dir or not self.optimization_run_id:
|
|
753
750
|
return False
|
|
754
|
-
readopted = resume.read_resumable(log_dir, self.
|
|
751
|
+
readopted = resume.read_resumable(log_dir, self.program_id)
|
|
755
752
|
return readopted is not None and readopted[0] == self.optimization_run_id
|
|
756
753
|
|
|
757
754
|
def finalize_error(self, exception: BaseException) -> None:
|
|
@@ -853,7 +850,7 @@ class OptimizationTracker:
|
|
|
853
850
|
# that id (and its original start_time, so duration stays cumulative)
|
|
854
851
|
# instead of minting a fresh row. Jobs without a log_dir stay per-run.
|
|
855
852
|
log_dir = self.config.get("log_dir") if self.config else None
|
|
856
|
-
readopted = resume.read_resumable(log_dir, self.
|
|
853
|
+
readopted = resume.read_resumable(log_dir, self.program_id) if log_dir else None
|
|
857
854
|
if readopted is not None:
|
|
858
855
|
self.optimization_run_id, prior_start = readopted
|
|
859
856
|
if prior_start is not None:
|
|
@@ -870,7 +867,7 @@ class OptimizationTracker:
|
|
|
870
867
|
self._publish_program()
|
|
871
868
|
# Persist the id so a later resume of the same log_dir re-adopts it.
|
|
872
869
|
if log_dir and self.optimization_run_id:
|
|
873
|
-
resume.write_run_id(log_dir, self.optimization_run_id, self.
|
|
870
|
+
resume.write_run_id(log_dir, self.optimization_run_id, self.program_id, self.start_time)
|
|
874
871
|
logger.info(
|
|
875
872
|
f"Started optimization tracking: run_id={self.optimization_run_id}, "
|
|
876
873
|
f"max_metric_calls={self.max_metric_calls}"
|
|
@@ -1169,7 +1166,6 @@ class OptimizationTracker:
|
|
|
1169
1166
|
"reflection_model_name": self.reflection_model_name,
|
|
1170
1167
|
"valset_hash": self.valset_hash,
|
|
1171
1168
|
"component_signature_hash": self.component_signature_hash,
|
|
1172
|
-
"program_signature_hash": identity.format_signature_hash(self.program_signature_hash),
|
|
1173
1169
|
"start_time": self.start_time.isoformat() if self.start_time else None,
|
|
1174
1170
|
"end_time": self.end_time.isoformat() if self.end_time else None,
|
|
1175
1171
|
"duration_ms": duration_ms,
|
|
@@ -1435,13 +1431,6 @@ def enrich_from_program(
|
|
|
1435
1431
|
trk.component_signature_hash = identity.compute_signature_hash(components)
|
|
1436
1432
|
trk.component_types = code_component_types(student)
|
|
1437
1433
|
|
|
1438
|
-
# Program signature hash from the live module (routes through the IR
|
|
1439
|
-
# reflector so Predict vs ChainOfThought discriminates — don't pass a bare
|
|
1440
|
-
# signature).
|
|
1441
|
-
program_hash = identity.compute_program_hash(student)
|
|
1442
|
-
if program_hash is not None:
|
|
1443
|
-
trk.program_signature_hash = program_hash
|
|
1444
|
-
|
|
1445
1434
|
# Model names.
|
|
1446
1435
|
if lm is not None and getattr(lm, "model", None):
|
|
1447
1436
|
trk.model_name = lm.model or ""
|
|
@@ -34,7 +34,7 @@ _NAME_PUNCTUATION = "._-"
|
|
|
34
34
|
_RESERVED_PREFIX = "p_"
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
def generated_program_name(module: Any
|
|
37
|
+
def generated_program_name(module: Any) -> str:
|
|
38
38
|
"""The name the SDK gives the program ``module`` runs as, when its user named none.
|
|
39
39
|
|
|
40
40
|
The name is the module's class and twelve hex digits of its signature hash, such as
|
|
@@ -43,13 +43,10 @@ def generated_program_name(module: Any, signature_hash: int | None = None) -> st
|
|
|
43
43
|
names. An optimizer's new instructions and demos keep the shape, so they keep the
|
|
44
44
|
name. The name always fits the program-name syntax, whatever the class is called.
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
computes the hash.
|
|
46
|
+
The SDK sends the signature hash nowhere else, so naming the program is the only
|
|
47
|
+
place that reflects the module for it.
|
|
49
48
|
"""
|
|
50
|
-
|
|
51
|
-
signature_hash = identity.compute_program_hash(module)
|
|
52
|
-
signature_hash = signature_hash or 0
|
|
49
|
+
signature_hash = identity.compute_program_hash(module) or 0
|
|
53
50
|
suffix = f"{signature_hash & 0xFFFF_FFFF_FFFF_FFFF:016x}"[:_SUFFIX_DIGITS]
|
|
54
51
|
return f"{_class_part(module.__class__.__name__)}-{suffix}"
|
|
55
52
|
|
|
@@ -28,6 +28,18 @@ already has its program, and a program name with it is refused when the file
|
|
|
28
28
|
binds no program. In the shell, `deploy()` and `optimize()` take the
|
|
29
29
|
program name as `program=`.
|
|
30
30
|
|
|
31
|
+
The platform deploys and optimizes only a program a user named. A program name
|
|
32
|
+
given here, to `cmpnd.Program(name, ...)` or to `cmpnd programs rename` is one.
|
|
33
|
+
A program with no name, or with a name a client generated, such as an
|
|
34
|
+
optimization's result, is refused with `409` and error code `program_unnamed`,
|
|
35
|
+
and the error names the command that fixes it:
|
|
36
|
+
`cmpnd programs rename <p_id> <name>`. It also tells you to declare that name in
|
|
37
|
+
your code with `@cmpnd.program("<name>")` or `cmpnd.Program("<name>", ...)`. The
|
|
38
|
+
rename frees the generated name, so code that declares no name sends its later
|
|
39
|
+
traces to a new program under the generated name. Deployments of such a program that
|
|
40
|
+
already exist keep serving. A rename never clears the name of a program with
|
|
41
|
+
a deployment that can serve.
|
|
42
|
+
|
|
31
43
|
`cmpnd programs create PROGRAM_NAME` makes the program ahead of time and prints
|
|
32
44
|
its id on stdout. It refuses a program name that already has a program. The
|
|
33
45
|
command reports what it created on stderr, and `--json` prints serve's whole
|
|
@@ -108,11 +120,12 @@ PROGRAM name up as the other `cmpnd programs` commands do, and sends
|
|
|
108
120
|
`POST /api/v1/programs/{id}/rename`. The command needs `traces:write` or
|
|
109
121
|
`optimizations:write`.
|
|
110
122
|
|
|
111
|
-
The old name
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
123
|
+
The old name is free at once. It no longer resolves to the program, and any
|
|
124
|
+
program of the organization can take it, so code that still declares the old
|
|
125
|
+
name with `cmpnd.Program(name, ...)` reaches a new program, not this one.
|
|
126
|
+
Update that code to the new name. A program with no name takes its first name
|
|
127
|
+
this way, and code that declares the new name traces to it. Serve refuses
|
|
128
|
+
another live program's current name. A program in the Trash
|
|
116
129
|
is refused until `cmpnd programs restore` returns it. A server from before the
|
|
117
130
|
rename route says so, and the error points at the program's page in the web
|
|
118
131
|
app, which renames it too.
|
|
@@ -460,8 +473,8 @@ optimization result, not a program. Each group's `--help` names the column its
|
|
|
460
473
|
IDs come from.
|
|
461
474
|
|
|
462
475
|
`cmpnd evals list [--program NAME] [--module CLASS] [--metric] [--status]`
|
|
463
|
-
lists eval runs, newest first. `--program` takes the program's
|
|
464
|
-
|
|
476
|
+
lists eval runs, newest first. `--program` takes the program's current
|
|
477
|
+
name, and a name no program holds is an error that names it.
|
|
465
478
|
`--module` takes the evaluated module's class, such as `ReAct`, and matches it
|
|
466
479
|
exactly. The CLI sends them as `program_name` and `module_class`. Each eval
|
|
467
480
|
run in `evals list`, `evals show` and `programs evals` names what it evaluated
|
|
@@ -139,14 +139,16 @@ and every other name still raises. `TestDspyHookCoverage` in
|
|
|
139
139
|
`tests/test_callback.py` asserts the coverage against whatever DSPy is installed,
|
|
140
140
|
so the next release that adds a hook is caught by CI rather than by a user's logs.
|
|
141
141
|
|
|
142
|
-
### Signature extraction and
|
|
142
|
+
### Signature extraction and the program signature hash
|
|
143
143
|
|
|
144
|
-
|
|
144
|
+
No record the SDK sends carries the program signature hash. A trace, an eval run and an
|
|
145
|
+
optimization run name their program by `program_id`.
|
|
146
|
+
[`CLUSTERING.md`](../../docs/CLUSTERING.md) explains how the hash is computed.
|
|
145
147
|
|
|
146
|
-
- **On a span** — `_capture_module_attributes` in `callback.py
|
|
147
|
-
- **On a trace** — `_create_trace` in `callback.py
|
|
148
|
+
- **On a span** — `_capture_module_attributes` in `callback.py` walks `instance.signature.input_fields` / `output_fields` and records names, types, descriptions and schemas. It reflects nothing, because a span never names a program.
|
|
149
|
+
- **On a trace** — `_create_trace` in `callback.py` records the root signature, or for a composite module the `dspy.Predict` children's signatures as `component_signatures`. A root module call that names no program reflects the module once, for the name the SDK generates (`program_naming.generated_program_name`). The hash goes into that name and nowhere else.
|
|
148
150
|
|
|
149
|
-
|
|
151
|
+
`python-sdk/cmpnd/identity.py` is the home of every hash the SDK computes.
|
|
150
152
|
|
|
151
153
|
---
|
|
152
154
|
|
|
@@ -690,7 +692,10 @@ the top level and in `started_fact`, and again under `program_name`, the key a
|
|
|
690
692
|
serve from before `module_class` reads and digests a start from. A standalone
|
|
691
693
|
optimizer LM trace sends `GEPA` there. No trace body carries the program's own name: a declared name
|
|
692
694
|
travels as the program id it resolves to, as "A declared program name resolves
|
|
693
|
-
to an id in the exporter" describes.
|
|
695
|
+
to an id in the exporter" describes. No trace body carries a version either. A
|
|
696
|
+
trace serve executed names its version by the `deployment_id` serve stamps on
|
|
697
|
+
it, and `TraceBuilder` has no `program_version` field. A program that wants to
|
|
698
|
+
record a version of its own, such as a git SHA, adds it as a project tag.
|
|
694
699
|
|
|
695
700
|
The callback seals `started_fact` after it sets the root type, before the
|
|
696
701
|
module executes. It keeps that snapshot even when start emission is disabled.
|
|
@@ -735,7 +740,7 @@ What it captures beyond the normal span flow:
|
|
|
735
740
|
- An `EvalRunBuilder` (constructed at `eval_handler.py:79`) that groups all per-example traces under one eval ID.
|
|
736
741
|
- The metric name (via `get_metric_name` from `python-sdk/cmpnd/helpers.py`) and inferred provider.
|
|
737
742
|
- Links to the enclosing optimization run when one exists (`eval_handler.py:85`), so eval runs triggered inside `GEPA.compile` roll up under the optimization in the UI.
|
|
738
|
-
- The program the run evaluates, as `program_id`. A program name the call declares wins: the exporter resolves it with `resolve_program_name`, the same once-per-process answer its traces use, on the caller's thread because the eval start is sent synchronously. Without a declared name, the run takes the callback's program id, else the program of the optimization run it belongs to. A run with none of these resolves the name the SDK generates for the evaluated module, the name that module's traces carry, with `resolve_program_name(name, generated=True)`. A name serve refuses leaves the run without an id. The evaluated module's class goes as `module_class`, and again under `program_name`, the key a serve from before `module_class` reads.
|
|
743
|
+
- The program the run evaluates, as `program_id`. A program name the call declares wins: the exporter resolves it with `resolve_program_name`, the same once-per-process answer its traces use, on the caller's thread because the eval start is sent synchronously. Without a declared name, the run takes the callback's program id, else the program of the optimization run it belongs to. A run with none of these resolves the name the SDK generates for the evaluated module, the name that module's traces carry, with `resolve_program_name(name, generated=True)`. A name serve refuses leaves the run without an id. The evaluated module's class goes as `module_class`, and again under `program_name`, the key a serve from before `module_class` reads. The run sends no `program_signature_hash`.
|
|
739
744
|
- The exporter it publishes through: the callback's own (`_current_exporter`), so a client's eval runs go to the client's account.
|
|
740
745
|
- The dataset — on `on_evaluate_start` it triggers the `dataset_sync` pre-flight described above.
|
|
741
746
|
|
|
@@ -761,7 +766,6 @@ The trace payload is built in `python-sdk/cmpnd/models.py` by `TraceBuilder.to_a
|
|
|
761
766
|
"trace_id": "...",
|
|
762
767
|
"parent_span_id": "...",
|
|
763
768
|
"span_type": "predict",
|
|
764
|
-
"signature_hash": -3847510293847, # signed Int64
|
|
765
769
|
"signature_input_fields": ["question"],
|
|
766
770
|
"signature_output_fields": ["answer"],
|
|
767
771
|
"model_name": "gpt-4o-mini",
|
|
@@ -813,9 +817,8 @@ name form. A program name wins over the config's id. `configure()`
|
|
|
813
817
|
checks the id's shape and raises `ValueError` on a bad one, and a `Config` built directly
|
|
814
818
|
is checked the same way.
|
|
815
819
|
|
|
816
|
-
The id rides every body that can declare a program.
|
|
817
|
-
|
|
818
|
-
hash beside the id:
|
|
820
|
+
The id rides every body that can declare a program. No body carries a
|
|
821
|
+
`program_signature_hash`:
|
|
819
822
|
|
|
820
823
|
| Body | Where | Built by |
|
|
821
824
|
|---|---|---|
|
|
@@ -11,8 +11,9 @@ This module keeps the answers. The transport makes the requests, because they ri
|
|
|
11
11
|
client and its retry budget.
|
|
12
12
|
|
|
13
13
|
An answer is kept for the life of the process. A name that serve later points at
|
|
14
|
-
another program reaches a process only when the process starts again
|
|
15
|
-
|
|
14
|
+
another program reaches a process only when the process starts again. A rename frees
|
|
15
|
+
the old name, so a process that resolved it before the rename keeps sending to the
|
|
16
|
+
renamed program, and a process started after it gets a new program under that name.
|
|
16
17
|
|
|
17
18
|
A name settles in one of two ways. Serve gives an id, or serve refuses the name, as a
|
|
18
19
|
server without program names does with ``405``. A refused name sends its traces without
|