cmpnd 0.67.0__tar.gz → 0.69.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.67.0 → cmpnd-0.69.0}/PKG-INFO +1 -1
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/_authored_import.py +0 -1
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/authored.py +0 -5
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/cli/commands/programs.py +45 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/cli/verbs.py +1 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/deployment.py +1 -4
- {cmpnd-0.67.0 → cmpnd-0.69.0}/docs/cli.md +18 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/docs/sdk-instrumentation.md +3 -1
- {cmpnd-0.67.0 → cmpnd-0.69.0}/pyproject.toml +1 -1
- {cmpnd-0.67.0 → cmpnd-0.69.0}/scripts/seed_review_run.py +146 -66
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_assessments_cli.py +4 -9
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_deploy_programs.py +0 -1
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_optimize_loop.py +7 -11
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_valsets_cli.py +6 -10
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_authored.py +2 -1
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cli/test_programs.py +77 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_deploy.py +3 -4
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_deploy_program_id.py +1 -1
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_seed_review_run.py +106 -2
- {cmpnd-0.67.0 → cmpnd-0.69.0}/uv.lock +1 -1
- {cmpnd-0.67.0 → cmpnd-0.69.0}/.gitignore +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/AGENTS.md +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/CLAUDE.md +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/README.md +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/__init__.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/_assessments.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/_deployments.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/_exporter_pool.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/_gepa_patch.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/_http.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/_program_patch.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/_rlm_patch.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/_runtime_tools.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/_timespec.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/_traces.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/_valsets.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/callback.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/cli/__init__.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/cli/api_client.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/cli/commands/__init__.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/cli/commands/admin.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/cli/commands/assessments.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/cli/commands/auth.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/cli/commands/datasets.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/cli/commands/deployments.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/cli/commands/evals.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/cli/commands/login.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/cli/commands/optimizations.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/cli/commands/org.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/cli/commands/provider_credentials.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/cli/commands/tool_servers.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/cli/commands/top.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/cli/commands/traces.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/cli/commands/valsets.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/cli/credentials.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/cli/deprecation.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/cli/pagination.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/cli/shell.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/cli/trace_render.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/cli/tree_help.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/cli/views.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/client.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/configuration.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/context.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/credentials.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/dataset_sync.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/datasets.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/decorators.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/deployment_metadata.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/deployment_runs.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/eval_handler.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/execution.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/exporter.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/exporter_http.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/helpers.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/identity.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/imaging.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/ir/__init__.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/ir/decode.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/ir/encode.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/ir/hash.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/ir/program.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/ir/reflection.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/ir/types.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/ir/xxh64.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/lm_configuration.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/mcp_servers.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/models.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/named_programs.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/optimization.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/optimizers/__init__.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/optimizers/gepa.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/optimizers/gepa_callback.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/optimizers/resume.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/optimizers/tracker.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/packaging.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/programs.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/references.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/retry.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/cmpnd/traces.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/docs/2026-04-02-code-review.md +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/docs/client.md +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/docs/custom-proposer.md +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/docs/plans/2026-04-05-train-val-dataset-capture-design.md +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/docs/plans/2026-04-05-train-val-dataset-capture.md +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/docs/reading-traces.md +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/examples/generalizing_proposer.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/examples/local_ollama.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/ingest/LINEAGE.md +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/ingest/README.md +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/ingest/cmpnd_ingest/__init__.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/ingest/cmpnd_ingest/bodies.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/ingest/cmpnd_ingest/client_floor.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/ingest/cmpnd_ingest/exporter_http.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/ingest/cmpnd_ingest/program_names.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/ingest/cmpnd_ingest/protocols.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/ingest/cmpnd_ingest/py.typed +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/ingest/cmpnd_ingest/request_log.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/ingest/cmpnd_ingest/retry.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/ingest/cmpnd_ingest/trace_facts.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/ingest/pyproject.toml +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/scripts/audit-sdist.sh +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/scripts/capture_review_run.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/scripts/check-pip-install.sh +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/scripts/check_release_artifacts.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/scripts/fixtures/review_run.json.gz +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/scripts/gepa_resume_bug.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/scripts/install-test-env.sh +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/scripts/release-gate.sh +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/scripts/release-real-models.sh +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/scripts/require_version_bump.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/scripts/selfhost_compat.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/scripts/test-in-linux.sh +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/stubs/dspy/__init__.pyi +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/stubs/dspy/primitives/__init__.pyi +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/stubs/dspy/primitives/prediction.pyi +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/stubs/dspy/utils/__init__.pyi +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/stubs/dspy/utils/callback.pyi +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/stubs/dspy/utils/dummies.pyi +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/__init__.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/_credential_route.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/_deployment_signature_helpers.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/_exporter_helpers.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/_fake_clock.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/_identity_helpers.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/_resolve_refs.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/_traced_run.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/conftest.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/__init__.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/committee_task.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/conftest.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/continuation_task.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/data/committee_train.ndjson.gz +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/data/committee_val.ndjson.gz +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/fake_lm.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/helpers.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/target_capabilities.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_capture_prompts.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_composite_module.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_dataset_auto_creation.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_deploy_execute.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_deploy_pandas.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_edge_cases.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_example_hash.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_gepa_optimization.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_interpreter_spans.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_lm_accuracy.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_module_tracing.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_optimization_lineage.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_optimization_metric_identity.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_optimize_authored_metric.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_optimize_continuation.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_optimize_custom_proposer.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_optimize_failures.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_optimize_review_committee.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_optimize_server_owned_completion.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_parallel_export.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_project_attribution.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_react_tool_spans.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_save_load.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_trace_structure.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_traces_read.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/e2e/test_user_attribution.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/identity_vectors/01_predict_qa.json +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/identity_vectors/02_predict_renamed_field.json +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/identity_vectors/03_chain_of_thought_qa.json +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/identity_vectors/04_predict_richer_types.json +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/identity_vectors/05_composite_two_predicts.json +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/identity_vectors/06_multichaincomparison.json +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/identity_vectors/07_program_of_thought.json +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/identity_vectors/08_opaque_module.json +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/identity_vectors/09_predict_pydantic_field.json +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/identity_vectors/10_react.json +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/identity_vectors/11_refine.json +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/identity_vectors/12_retrieve.json +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/identity_vectors/13_knn.json +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/identity_vectors/14_parallel.json +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/identity_vectors/README.md +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/ingest_conformance.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/integration/__init__.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/integration/authored_optimize/judge.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/integration/authored_optimize/optimize_hosted.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/integration/conftest.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/integration/hosted_mcp_tool_optimize_probe.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/integration/hosted_optimize_probe.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/integration/optimization_run_probe.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/integration/test_cli_deploy_smoketest.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/integration/test_logs_renders_traces.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/integration/test_optimization_run.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/integration/test_optimizing_progress.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/integration/test_unhappy_path.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/load/__init__.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/load/__main__.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/load/drain.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/load/ingest.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/load/latency_transport.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/load/rlm_shape.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/load/rlm_size_report.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/load/sweep.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/load/test_rlm_shape.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/load/test_rlm_size_report.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/parity/__init__.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/parity/conftest.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/parity/seed_parity.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/parity/test_auth.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/parity/test_datasets.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/parity/test_deployments.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/parity/test_evals.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/parity/test_health.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/parity/test_modules.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/parity/test_optimizations.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/parity/test_programs.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/parity/test_signatures.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/parity/test_trace_streaming.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/parity/test_traces.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/real_models/__init__.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/real_models/_provider.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/real_models/_readiness.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/real_models/_reliability.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/real_models/_result.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/real_models/mint_bedrock_token.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/real_models/test_bedrock_converse.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/real_models/test_deploy_programs.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/real_models/test_multi_client_stress.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/real_models/test_optimize_client_committee.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/real_models/test_optimize_continuation.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/real_models/test_optimize_loop.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/real_models/test_optimize_loop_wasm.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/real_models/test_optimize_stress.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/real_models/test_provider_roles.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/real_models/test_readiness.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/real_models/test_real_provider_twins.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/real_models/test_reliability.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/real_models/test_reliability_classify.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/real_models/test_rlm_wasm.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/real_models/test_trace_search.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/span_reference_fixture.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_adapter_reentrancy.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_assessments_api.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_authored_binding_credentials.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_authored_bundle_collisions.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_authored_metric_contract.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_authored_named_models.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_authored_optimize.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_callback.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_candidate_lineage.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cli/__init__.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cli/conftest.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cli/test_admin.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cli/test_api_client.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cli/test_assessments.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cli/test_auth.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cli/test_credentials.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cli/test_datasets.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cli/test_deployment_runs.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cli/test_deployments.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cli/test_evals.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cli/test_login.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cli/test_main.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cli/test_optimizations.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cli/test_org.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cli/test_pagination.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cli/test_parity.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cli/test_provider_credentials.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cli/test_schema_sample.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cli/test_shell.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cli/test_tool_servers.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cli/test_top.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cli/test_traces.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cli/test_traces_program_and_module.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cli/test_traces_search_wire.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cli/test_tree_help.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cli/test_valsets.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_client.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_client_floor.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_client_program_names.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_clustering/__init__.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_clustering/conftest.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_clustering/test_edge_cases.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_clustering/test_hash_consistency.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_clustering/test_type_conversion.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_cmp551_grouping_identity.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_configuration.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_context.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_context_propagation.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_credential_kwargs.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_credential_selection.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_credential_values.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_dataset_polling.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_dataset_sync.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_datasets.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_decision_client_spans.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_decorators.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_deploy_mcp_tool_references.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_deployment_metadata.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_deployment_runs.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_deployments_read.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_eval.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_eval_example_attribution.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_eval_start.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_eval_trace_grouping.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_exception_paths.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_execute.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_execute_run_identity.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_exporter.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_exporter_program_names.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_exporter_queue.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_exporter_real.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_fake_lm.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_gepa_callback.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_gepa_integration.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_gepa_output_normalization.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_gepa_resume.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_identity.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_imaging.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_import_weight.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_ingest_conformance.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_ingest_second_producer.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_integration.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_interpreter_callback.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_ir_encoder_properties.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_ir_golden_vectors.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_ir_roundtrip.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_lm15_native_calls.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_lm_configuration.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_lm_usage_shapes.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_mcp_tools.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_models.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_multi_client_stress_readiness.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_optimization_progress.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_optimization_start.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_optimize.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_optimize_budget.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_optimize_lift.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_optimize_lms.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_optimize_proposer.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_optimize_reflection_lm.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_optimize_terminal_failure.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_packaging.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_packaging_callable_source.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_packaging_mcp_tools.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_packaging_program_source.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_poll_until.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_program_id_deprecation.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_program_identity.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_program_lineage_persist.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_program_names_in_deploy.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_programs_create.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_project_payload.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_real_provider_twins_readiness.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_reflector_properties.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_reflector_smoke.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_release_gate_script.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_release_real_models_script.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_replaced_names.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_repro_reactv2_bugs.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_require_version_bump.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_retry.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_reversible_failures.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_rlm_patch.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_run_attribution_paths.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_runtime_tools.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_schemas.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_seal_lm_credential.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_signature_inputs.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_span_references.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_span_sent_once.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_system_one.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_trace_context_concurrency.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_trace_fact_wire_contract.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_trace_facts.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_trace_render.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_traces_read.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_tracked_gepa.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_tracker_enrich.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_truncation.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_upload_auth_headers.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_valsets_api.py +0 -0
- {cmpnd-0.67.0 → cmpnd-0.69.0}/tests/test_xxh64.py +0 -0
|
@@ -263,7 +263,6 @@ def _program_facts(
|
|
|
263
263
|
lm = packaging._extract_lm_object(program)
|
|
264
264
|
lm_kwargs = getattr(lm, "kwargs", {}) if lm is not None else {}
|
|
265
265
|
facts = ProgramFacts(
|
|
266
|
-
program_signature_hash=identity.compute_program_hash(program),
|
|
267
266
|
entrypoint_kind=kind,
|
|
268
267
|
module_class=type(program).__name__,
|
|
269
268
|
litellm_model=getattr(lm, "model", None),
|
|
@@ -43,7 +43,6 @@ class SourceCheckError(ValueError):
|
|
|
43
43
|
class ProgramFacts:
|
|
44
44
|
"""Facts derived by importing the staged program without calling forward."""
|
|
45
45
|
|
|
46
|
-
program_signature_hash: int | None = None
|
|
47
46
|
entrypoint_kind: str = "instance"
|
|
48
47
|
module_class: str | None = None
|
|
49
48
|
signature_name: str | None = None
|
|
@@ -72,11 +71,7 @@ class ProgramFacts:
|
|
|
72
71
|
|
|
73
72
|
def deploy_body(self) -> dict[str, Any]:
|
|
74
73
|
"""Return fields the deployment create route accepts."""
|
|
75
|
-
from . import identity
|
|
76
|
-
|
|
77
74
|
body: dict[str, Any] = {}
|
|
78
|
-
if self.program_signature_hash is not None:
|
|
79
|
-
body["program_signature_hash"] = identity.format_signature_hash(self.program_signature_hash)
|
|
80
75
|
for name in (
|
|
81
76
|
"module_class",
|
|
82
77
|
"signature_name",
|
|
@@ -207,6 +207,19 @@ def register(subparsers: _SubParsersAction[ArgumentParser]) -> None:
|
|
|
207
207
|
purge.add_argument("--force", action="store_true", help="Skip the confirmation (required when not on a terminal)")
|
|
208
208
|
purge.set_defaults(func=handle_purge)
|
|
209
209
|
|
|
210
|
+
rename = sub.add_parser(
|
|
211
|
+
"rename",
|
|
212
|
+
help="Name or rename a program",
|
|
213
|
+
description=(
|
|
214
|
+
"Make NAME the current name of PROGRAM. The name it had keeps resolving to it, so code that still "
|
|
215
|
+
"declares the old name reaches the same program, with its id and history. A name another program "
|
|
216
|
+
"answers to is refused."
|
|
217
|
+
),
|
|
218
|
+
)
|
|
219
|
+
rename.add_argument("program", metavar="PROGRAM", help="Program name or p_ id")
|
|
220
|
+
rename.add_argument("new_name", metavar="NAME", help="The program's new name, unique in your organization")
|
|
221
|
+
rename.set_defaults(func=handle_rename)
|
|
222
|
+
|
|
210
223
|
select = sub.add_parser("select", help="Pin an optimization run as this program's chosen version")
|
|
211
224
|
select.add_argument("id", help=_COMPILED_HASH_HELP)
|
|
212
225
|
select.add_argument("--run", dest="run_id", required=True, help="Optimization run ID (op_...) to pin")
|
|
@@ -624,6 +637,38 @@ def handle_purge(client: api_client.ApiClient, args: Any) -> Any:
|
|
|
624
637
|
return _trash_write(client, f"/api/v1/programs/{program_id}/purge")
|
|
625
638
|
|
|
626
639
|
|
|
640
|
+
def handle_rename(client: api_client.ApiClient, args: Any) -> Any:
|
|
641
|
+
"""Make ``args.new_name`` the current name of the program ``args.program`` names, keeping its id."""
|
|
642
|
+
from ... import programs
|
|
643
|
+
from . import top
|
|
644
|
+
|
|
645
|
+
try:
|
|
646
|
+
programs.validate_program_name(args.new_name)
|
|
647
|
+
except ValueError as exc:
|
|
648
|
+
raise api_client.CliError(str(exc)) from exc
|
|
649
|
+
program_id, trashed = resolve(client, args.program, old_server_remedy=_rename_remedy())
|
|
650
|
+
if trashed:
|
|
651
|
+
raise api_client.CliError(
|
|
652
|
+
f"{args.program} is in the Trash. Restore it with `{top.hint_programs('restore', args.program)}` "
|
|
653
|
+
"before you rename it."
|
|
654
|
+
)
|
|
655
|
+
try:
|
|
656
|
+
return client.post(f"/api/v1/programs/{program_id}/rename", json={"name": args.new_name})
|
|
657
|
+
except api_client.CliError as exc:
|
|
658
|
+
# A server from before the rename route answers 405, because its GET dispatcher owns the path.
|
|
659
|
+
if exc.status_code == 405:
|
|
660
|
+
_refuse_if_old(client, exc, _rename_remedy(program_id))
|
|
661
|
+
raise api_client.CliError(
|
|
662
|
+
f"this cmpnd server predates renaming a program through the API. {_rename_remedy(program_id)}"
|
|
663
|
+
) from exc
|
|
664
|
+
raise
|
|
665
|
+
|
|
666
|
+
|
|
667
|
+
def _rename_remedy(program_id: str = "") -> str:
|
|
668
|
+
where = f"on its page in the web app, at /ui/programs/{program_id}" if program_id else "in the web app"
|
|
669
|
+
return f"Rename the program {where}, or upgrade the server."
|
|
670
|
+
|
|
671
|
+
|
|
627
672
|
def _trash_listing(client: api_client.ApiClient) -> Any:
|
|
628
673
|
"""GET the Trash. On a server from before the Trash API it answers 404, which is the old-server signal."""
|
|
629
674
|
try:
|
|
@@ -167,6 +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 keeps the old one resolving to it, which update would hide",
|
|
170
171
|
}
|
|
171
172
|
|
|
172
173
|
#: Leaves naming a related collection or sub-record rather than an action.
|
|
@@ -527,13 +527,10 @@ def deploy_module_under(
|
|
|
527
527
|
# Package the module
|
|
528
528
|
zip_bytes = packaging.generate_source_zip(module, metric, mcp_tools=pinned_mcp_tools)
|
|
529
529
|
|
|
530
|
-
#
|
|
531
|
-
# tag included); the signature is kept around only for display metadata.
|
|
530
|
+
# The deployment names its program by id alone; the signature only describes it.
|
|
532
531
|
sig = packaging._get_module_signature(module)
|
|
533
|
-
program_signature_hash = identity.compute_program_hash(module) or 0
|
|
534
532
|
|
|
535
533
|
deploy_body: dict[str, Any] = {
|
|
536
|
-
"program_signature_hash": identity.format_signature_hash(program_signature_hash),
|
|
537
534
|
# Declare the ZIP's exact length so the server can reject an oversized
|
|
538
535
|
# deploy before the upload.
|
|
539
536
|
"declared_content_length": len(zip_bytes),
|
|
@@ -99,6 +99,24 @@ also names the `cmpnd programs optimized` command for a compiled program hash.
|
|
|
99
99
|
program hash, the value in the `program_hash` column of
|
|
100
100
|
`cmpnd programs optimized list`, as `cmpnd programs select` does.
|
|
101
101
|
|
|
102
|
+
## Renaming a program
|
|
103
|
+
|
|
104
|
+
`cmpnd programs rename PROGRAM NAME` makes NAME the current name of PROGRAM,
|
|
105
|
+
which is a program name or a `p_` id. The program keeps its id and its
|
|
106
|
+
history. The CLI checks NAME's syntax before it sends anything, looks a
|
|
107
|
+
PROGRAM name up as the other `cmpnd programs` commands do, and sends
|
|
108
|
+
`POST /api/v1/programs/{id}/rename`. The command needs `traces:write` or
|
|
109
|
+
`optimizations:write`.
|
|
110
|
+
|
|
111
|
+
The old name keeps resolving to the program, so code that still declares it
|
|
112
|
+
reaches the same program. A program with no name takes its first name this
|
|
113
|
+
way, and code that declares the new name with `cmpnd.Program(name, ...)`
|
|
114
|
+
traces to it. Serve refuses a name another live
|
|
115
|
+
program answers to, as its current or a retired name. A program in the Trash
|
|
116
|
+
is refused until `cmpnd programs restore` returns it. A server from before the
|
|
117
|
+
rename route says so, and the error points at the program's page in the web
|
|
118
|
+
app, which renames it too.
|
|
119
|
+
|
|
102
120
|
## The Trash
|
|
103
121
|
|
|
104
122
|
A program in the Trash leaves every view, and its traces with it, until it is
|
|
@@ -803,7 +803,9 @@ name form. A program name wins over the config's id. `configure()`
|
|
|
803
803
|
checks the id's shape and raises `ValueError` on a bad one, and a `Config` built directly
|
|
804
804
|
is checked the same way.
|
|
805
805
|
|
|
806
|
-
The id rides every body that can declare a program
|
|
806
|
+
The id rides every body that can declare a program. A deployment create names its program
|
|
807
|
+
by the id alone and sends no `program_signature_hash`. The other bodies still carry the
|
|
808
|
+
hash beside the id:
|
|
807
809
|
|
|
808
810
|
| Body | Where | Built by |
|
|
809
811
|
|---|---|---|
|
|
@@ -5,7 +5,7 @@ name = "cmpnd"
|
|
|
5
5
|
# it's new) — no git tags. Bump with `uv version --bump {minor,patch}` or by
|
|
6
6
|
# hand. Runtime `cmpnd.__version__` reads installed metadata, so it tracks
|
|
7
7
|
# this automatically. See docs/plans/2026-07-02-sdk-pypi-tag-free-publish.md.
|
|
8
|
-
version = "0.
|
|
8
|
+
version = "0.69.0"
|
|
9
9
|
description = "DSPy observability and deployment SDK for cmpnd"
|
|
10
10
|
readme = "README.md"
|
|
11
11
|
requires-python = ">=3.11"
|
|
@@ -25,6 +25,11 @@ Each run is made fresh: every trace/span UUID is remapped to a new one, a fresh
|
|
|
25
25
|
reserve-then-PUT shape), the traces are linked to it, and all timestamps are
|
|
26
26
|
shifted so the run lands at "now".
|
|
27
27
|
|
|
28
|
+
Every seeded program is named. The seeder resolves each name to its `p_` id
|
|
29
|
+
through `PUT /api/v1/programs/by-name/{name}` and declares that id on the
|
|
30
|
+
program's traces, runs and deployments, and pins by it. The replayed payloads
|
|
31
|
+
keep the `program_signature_hash` the SDK captured, as the SDK still sends it.
|
|
32
|
+
|
|
28
33
|
Non-gating: any failure logs and exits 0 (the review pipeline must not break on it).
|
|
29
34
|
|
|
30
35
|
Env: CMPND_E2E_ENDPOINT, CMPND_E2E_API_KEY (the review app URL + key; no LM keys).
|
|
@@ -148,9 +153,9 @@ def _transform(obj, uuid_map: dict[str, str], delta: datetime.timedelta, opt_run
|
|
|
148
153
|
# A realistic GEPA `log_dir` (== gepa `run_dir`) the resume pair shares. The
|
|
149
154
|
# completed run and its interrupted twin are the SAME job (CMP-442): a laptop
|
|
150
155
|
# sleep / power cut split one optimization into a stuck `running` row plus a
|
|
151
|
-
# separate `completed` row, keyed on this directory.
|
|
152
|
-
#
|
|
153
|
-
#
|
|
156
|
+
# separate `completed` row, keyed on this directory. Both declare the committee
|
|
157
|
+
# program's `p_` id; the shared `log_dir` is what makes them read as one
|
|
158
|
+
# interrupted-then-resumed job.
|
|
154
159
|
_LOG_DIR = "/home/researcher/gepa_runs/committee-3b"
|
|
155
160
|
|
|
156
161
|
# Freeze the captured run right after iteration 2 — the point where GEPA has
|
|
@@ -625,6 +630,50 @@ def _replay_flat_fixture(
|
|
|
625
630
|
}
|
|
626
631
|
|
|
627
632
|
|
|
633
|
+
# The name of each program the seed plants. The seeder resolves each to its p_ id
|
|
634
|
+
# and declares that id; a review app makes each program on its first seed.
|
|
635
|
+
_PROGRAM_COMMITTEE = "committee-extractor"
|
|
636
|
+
_PROGRAM_DISTRICT_COUNTER = "district-counter"
|
|
637
|
+
_PROGRAM_SOURCE_CATEGORIZER = "source-categorizer"
|
|
638
|
+
_PROGRAM_TOOL_KIND_DEMO = "tool-kind-demo"
|
|
639
|
+
_PROGRAM_REACT_COMMITTEE = "react-committee"
|
|
640
|
+
|
|
641
|
+
|
|
642
|
+
def _declare_program(payload: dict, program_id: str | None) -> dict:
|
|
643
|
+
"""A copy of a trace or optimization run payload that declares ``program_id``.
|
|
644
|
+
With no id, the copy declares no program."""
|
|
645
|
+
out = dict(payload)
|
|
646
|
+
if program_id is not None:
|
|
647
|
+
out["program_id"] = program_id
|
|
648
|
+
return out
|
|
649
|
+
|
|
650
|
+
|
|
651
|
+
def _declare_program_traces(traces: list, module_class: str, program_id: str | None) -> list:
|
|
652
|
+
"""Declare ``program_id`` on the captured run's program traces: those whose root
|
|
653
|
+
module is the run's program class. The optimizer's own traces (GEPA) belong to
|
|
654
|
+
no program and stay undeclared."""
|
|
655
|
+
return [
|
|
656
|
+
_declare_program(t, program_id) if isinstance(t, dict) and t.get("module_class") == module_class else t
|
|
657
|
+
for t in traces
|
|
658
|
+
]
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
def _ensure_program(endpoint: str, api_key: str, name: str) -> str | None:
|
|
662
|
+
"""The p_ id of the program named ``name``, made on first use. Non-gating:
|
|
663
|
+
None on any failure, and the seed goes on without the program."""
|
|
664
|
+
try:
|
|
665
|
+
_status, resp = _post(
|
|
666
|
+
endpoint, "/api/v1/programs/by-name/" + urllib.parse.quote(name, safe=""), {}, api_key, method="PUT"
|
|
667
|
+
)
|
|
668
|
+
except Exception as exc: # noqa: BLE001 - non-gating, matches the seeder's philosophy
|
|
669
|
+
log.warning("resolve program %s failed (non-gating): %s", name, exc)
|
|
670
|
+
return None
|
|
671
|
+
program_id = resp.get("program_id") if isinstance(resp, dict) else None
|
|
672
|
+
if not program_id:
|
|
673
|
+
log.warning("resolve program %s returned no id", name)
|
|
674
|
+
return program_id
|
|
675
|
+
|
|
676
|
+
|
|
628
677
|
def _post(endpoint: str, path: str, payload, api_key: str, method: str = "POST"):
|
|
629
678
|
body = json.dumps(payload).encode("utf-8")
|
|
630
679
|
req = urllib.request.Request(
|
|
@@ -650,20 +699,21 @@ def _reserve_optimization(endpoint: str, api_key: str) -> str | None:
|
|
|
650
699
|
return run_id
|
|
651
700
|
|
|
652
701
|
|
|
653
|
-
def _create_deployment(endpoint: str, api_key: str,
|
|
702
|
+
def _create_deployment(endpoint: str, api_key: str, program_id: str) -> str | None:
|
|
654
703
|
"""Create a real deployment row (no ZIP upload) and return its `d_…` id.
|
|
655
704
|
|
|
656
705
|
The traces-index Deployment filter (CMP-277) reads distinct deployment_id
|
|
657
706
|
off traces, and the ingest sanitizer strips any deployment_id that isn't a
|
|
658
707
|
real deployment for the org — so seeded traces need real rows to point at.
|
|
659
708
|
A create-only POST suffices; the row exists (pending upload) and the
|
|
660
|
-
sanitizer accepts its id. The program
|
|
661
|
-
page resolve a human program-name label.
|
|
662
|
-
failure so the seed proceeds without the
|
|
709
|
+
sanitizer accepts its id. The program id, which the route requires, lets the
|
|
710
|
+
filter menu + Deployments page resolve a human program-name label.
|
|
711
|
+
Non-gating: returns None on any failure so the seed proceeds without the
|
|
712
|
+
deployment dimension.
|
|
663
713
|
"""
|
|
664
714
|
payload = {
|
|
715
|
+
"program_id": program_id,
|
|
665
716
|
"litellm_model": "openai/gpt-4o",
|
|
666
|
-
"program_signature_hash": program_signature_hash,
|
|
667
717
|
"metadata": {"seed": "true"},
|
|
668
718
|
}
|
|
669
719
|
try:
|
|
@@ -677,16 +727,16 @@ def _create_deployment(endpoint: str, api_key: str, program_signature_hash: int)
|
|
|
677
727
|
def _stamp_deployments(traces: list[dict], dep_for) -> None:
|
|
678
728
|
"""Stamp ~2/3 of the traces with the deployment for their own program (every
|
|
679
729
|
third trace left unstamped for a visible deployed/undeployed mix), keying on
|
|
680
|
-
each trace's
|
|
681
|
-
its program. `dep_for(
|
|
682
|
-
deployment per program
|
|
730
|
+
each trace's declared program_id so a deployment's traces coherently share
|
|
731
|
+
its program. `dep_for(program_id) -> id | None` lazily creates + caches one
|
|
732
|
+
deployment per program. No-op for traces that declare no program."""
|
|
683
733
|
for i, trace in enumerate(traces):
|
|
684
734
|
if i % 3 == 0 or not isinstance(trace, dict):
|
|
685
735
|
continue
|
|
686
|
-
|
|
687
|
-
if
|
|
736
|
+
program_id = trace.get("program_id")
|
|
737
|
+
if not program_id:
|
|
688
738
|
continue
|
|
689
|
-
dep = dep_for(
|
|
739
|
+
dep = dep_for(program_id)
|
|
690
740
|
if dep:
|
|
691
741
|
trace["deployment_id"] = dep
|
|
692
742
|
|
|
@@ -703,13 +753,6 @@ _CSRF_INPUT_RE = re.compile(r'name="csrf_token"\s+value="([^"]+)"')
|
|
|
703
753
|
_CSRF_META_RE = re.compile(r'name="csrf-token"\s+content="([^"]+)"')
|
|
704
754
|
|
|
705
755
|
|
|
706
|
-
def _display_program_hash(signed_hash: int) -> str:
|
|
707
|
-
"""The 16-hex display form of a signed-int64 program_signature_hash — the
|
|
708
|
-
shape the /ui/programs/{hash}/pin route parses (ids.FormatProgramHashInt64
|
|
709
|
-
in serve: fmt.Sprintf("%016x", uint64(n)))."""
|
|
710
|
-
return format(signed_hash & 0xFFFFFFFFFFFFFFFF, "016x")
|
|
711
|
-
|
|
712
|
-
|
|
713
756
|
def _scrape_csrf(html: str) -> str | None:
|
|
714
757
|
"""Pull a CSRF token from a serve HTML page — the hidden `csrf_token` form
|
|
715
758
|
input, or the `<meta name="csrf-token">` fallback (both carry the per-session
|
|
@@ -718,12 +761,12 @@ def _scrape_csrf(html: str) -> str | None:
|
|
|
718
761
|
return m.group(1) if m else None
|
|
719
762
|
|
|
720
763
|
|
|
721
|
-
def _pin_committee_program(endpoint: str,
|
|
764
|
+
def _pin_committee_program(endpoint: str, program_id: str) -> None:
|
|
722
765
|
"""Pin the completed committee program for the demo admin (CMP-634).
|
|
723
766
|
|
|
724
|
-
Pins are per-user web state
|
|
725
|
-
|
|
726
|
-
|
|
767
|
+
Pins are per-user web state, and serve's Pin() is reachable ONLY through the
|
|
768
|
+
session+CSRF web route POST /ui/programs/{id}/pin, which takes the program's
|
|
769
|
+
p_ id — the API key (bearer, no cookies) can't hit it.
|
|
727
770
|
So we drive the browser flow with a cookie jar: log in as the bootstrap admin,
|
|
728
771
|
harvest a fresh CSRF token from the program page, then POST the pin. Wholly
|
|
729
772
|
non-gating — any failure logs and returns, like the rest of the seed.
|
|
@@ -761,13 +804,13 @@ def _pin_committee_program(endpoint: str, display_hash: str) -> None:
|
|
|
761
804
|
# single-use for this POST only.
|
|
762
805
|
post("/auth/login", {"email": _ADMIN_EMAIL, "password": password, "csrf_token": login_csrf})
|
|
763
806
|
# 3) Harvest a FRESH CSRF token from the (now authenticated) program page.
|
|
764
|
-
pin_csrf = _scrape_csrf(get(f"/ui/programs/{
|
|
807
|
+
pin_csrf = _scrape_csrf(get(f"/ui/programs/{program_id}"))
|
|
765
808
|
if not pin_csrf:
|
|
766
809
|
log.warning("pin: no CSRF token on program page (login may have failed); skipping pin")
|
|
767
810
|
return
|
|
768
811
|
# 4) POST the pin.
|
|
769
|
-
status = post(f"/ui/programs/{
|
|
770
|
-
log.info("pinned committee program %s (status %s)",
|
|
812
|
+
status = post(f"/ui/programs/{program_id}/pin", {"csrf_token": pin_csrf})
|
|
813
|
+
log.info("pinned committee program %s (status %s)", program_id, status)
|
|
771
814
|
|
|
772
815
|
|
|
773
816
|
def main() -> int:
|
|
@@ -778,19 +821,19 @@ def main() -> int:
|
|
|
778
821
|
return 0
|
|
779
822
|
|
|
780
823
|
try:
|
|
781
|
-
# Lazily create one real deployment row per program
|
|
824
|
+
# Lazily create one real deployment row per program the first time a
|
|
782
825
|
# trace of that program is stamped, tied to the program so the filter
|
|
783
826
|
# menu + Deployments page resolve a human program-name label. The ingest
|
|
784
827
|
# sanitizer strips any id without a backing row, so real rows are
|
|
785
828
|
# required for the traces-index Deployment filter (CMP-277). Review apps
|
|
786
829
|
# run CMPND_DEPLOY_BACKEND=lambda, so the create forwards through the
|
|
787
830
|
# per-PR deploy stack; non-gating (cached None) if that's down.
|
|
788
|
-
dep_cache: dict[
|
|
831
|
+
dep_cache: dict[str, str | None] = {}
|
|
789
832
|
|
|
790
|
-
def dep_for(
|
|
791
|
-
if
|
|
792
|
-
dep_cache[
|
|
793
|
-
return dep_cache[
|
|
833
|
+
def dep_for(program_id: str) -> str | None:
|
|
834
|
+
if program_id not in dep_cache:
|
|
835
|
+
dep_cache[program_id] = _create_deployment(endpoint, api_key, program_id)
|
|
836
|
+
return dep_cache[program_id]
|
|
794
837
|
|
|
795
838
|
parts = json.loads(gzip.decompress(_FIXTURE.read_bytes()))
|
|
796
839
|
|
|
@@ -807,11 +850,21 @@ def main() -> int:
|
|
|
807
850
|
# record to it. It carries the shared `log_dir` so its interrupted twin
|
|
808
851
|
# (step 3) reads as the same job.
|
|
809
852
|
opt = next(p for p in parts if p["kind"] == "optimization")
|
|
853
|
+
# The captured run optimizes one program, whose root module class the run
|
|
854
|
+
# records as its program_name. Its runs and program traces declare it.
|
|
855
|
+
committee_class = opt["payload"].get("program_name") or "Predict"
|
|
856
|
+
committee_id = _ensure_program(endpoint, api_key, _PROGRAM_COMMITTEE)
|
|
810
857
|
new_op = _reserve_optimization(endpoint, api_key)
|
|
811
858
|
if not new_op:
|
|
812
859
|
log.warning("could not reserve an optimization run id; aborting seed")
|
|
813
860
|
return 0
|
|
814
|
-
opt_payload = _transform(
|
|
861
|
+
opt_payload = _transform(
|
|
862
|
+
_declare_program(_with_log_dir(opt["payload"]), committee_id),
|
|
863
|
+
uuid_map,
|
|
864
|
+
delta,
|
|
865
|
+
opt_run=new_op,
|
|
866
|
+
tags=_TAGS_COMPLETE,
|
|
867
|
+
)
|
|
815
868
|
_post(endpoint, f"/api/v1/optimizations/{new_op}", opt_payload, api_key, method="PUT")
|
|
816
869
|
log.info("seeded optimization run %s", new_op)
|
|
817
870
|
|
|
@@ -819,7 +872,10 @@ def main() -> int:
|
|
|
819
872
|
n_traces = n_spans = 0
|
|
820
873
|
for p in parts:
|
|
821
874
|
if p["kind"] == "traces_batch":
|
|
822
|
-
payload = [
|
|
875
|
+
payload = [
|
|
876
|
+
_transform(item, uuid_map, delta, new_op, _TAGS_COMPLETE)
|
|
877
|
+
for item in _declare_program_traces(p["payload"], committee_class, committee_id)
|
|
878
|
+
]
|
|
823
879
|
_stamp_deployments(payload, dep_for)
|
|
824
880
|
_post(endpoint, "/api/v1/traces/batch", payload, api_key)
|
|
825
881
|
n_traces += len(payload)
|
|
@@ -837,11 +893,10 @@ def main() -> int:
|
|
|
837
893
|
# login+web-route flow (the only path to a per-user pin) can never break
|
|
838
894
|
# the seed.
|
|
839
895
|
try:
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
_pin_committee_program(endpoint, _display_program_hash(int(committee_hash)))
|
|
896
|
+
if committee_id is not None:
|
|
897
|
+
_pin_committee_program(endpoint, committee_id)
|
|
843
898
|
else:
|
|
844
|
-
log.warning("pin:
|
|
899
|
+
log.warning("pin: the committee program has no id; skipping pin")
|
|
845
900
|
except Exception as exc: # noqa: BLE001 - non-gating, like the rest of the seed
|
|
846
901
|
log.warning("pin committee program failed (non-gating): %s", exc)
|
|
847
902
|
|
|
@@ -855,7 +910,11 @@ def main() -> int:
|
|
|
855
910
|
running_op = _reserve_optimization(endpoint, api_key)
|
|
856
911
|
if running_op:
|
|
857
912
|
interrupted = _transform(
|
|
858
|
-
_interrupted_variant(opt["payload"]),
|
|
913
|
+
_declare_program(_interrupted_variant(opt["payload"]), committee_id),
|
|
914
|
+
umap,
|
|
915
|
+
delta,
|
|
916
|
+
opt_run=running_op,
|
|
917
|
+
tags=_TAGS_RUNNING,
|
|
859
918
|
)
|
|
860
919
|
code, _ = _post(endpoint, f"/api/v1/optimizations/{running_op}", interrupted, api_key, method="PUT")
|
|
861
920
|
log.info("seeded running (interrupted) optimization run %s", running_op)
|
|
@@ -863,7 +922,11 @@ def main() -> int:
|
|
|
863
922
|
n_it = 0
|
|
864
923
|
for p in parts:
|
|
865
924
|
if p["kind"] == "traces_batch":
|
|
866
|
-
kept = [
|
|
925
|
+
kept = [
|
|
926
|
+
t
|
|
927
|
+
for t in _declare_program_traces(p["payload"], committee_class, committee_id)
|
|
928
|
+
if t.get("trace_id") in keep
|
|
929
|
+
]
|
|
867
930
|
if kept:
|
|
868
931
|
payload = [_transform(item, umap, delta, running_op, _TAGS_RUNNING) for item in kept]
|
|
869
932
|
_post(endpoint, "/api/v1/traces/batch", payload, api_key)
|
|
@@ -900,7 +963,9 @@ def main() -> int:
|
|
|
900
963
|
umap = {u: str(uuid.uuid4()) for u in acc}
|
|
901
964
|
rid = _reserve_optimization(endpoint, api_key)
|
|
902
965
|
if rid:
|
|
903
|
-
failed = _lifecycle_variant(
|
|
966
|
+
failed = _lifecycle_variant(
|
|
967
|
+
_transform(_declare_program(opt["payload"], committee_id), umap, delta, rid, _TAGS_FAILED), "failed"
|
|
968
|
+
)
|
|
904
969
|
code, _ = _post(endpoint, f"/api/v1/optimizations/{rid}", failed, api_key, method="PUT")
|
|
905
970
|
log.info("seeded failed optimization run %s (status %s)", rid, code)
|
|
906
971
|
else:
|
|
@@ -909,7 +974,8 @@ def main() -> int:
|
|
|
909
974
|
# 4) Plant a synthetic RLM (predict-with-REPL) trace so the notebook
|
|
910
975
|
# view (CMP-372) has trajectory data to render — the captured
|
|
911
976
|
# optimization run has none. Unlinked to any optimization run.
|
|
912
|
-
|
|
977
|
+
district_counter_id = _ensure_program(endpoint, api_key, _PROGRAM_DISTRICT_COUNTER)
|
|
978
|
+
notebook_batch = [_declare_program(_notebook_trace(now), district_counter_id)]
|
|
913
979
|
_stamp_deployments(notebook_batch, dep_for)
|
|
914
980
|
code, _ = _post(endpoint, "/api/v1/traces/batch", notebook_batch, api_key)
|
|
915
981
|
log.info("seeded RLM notebook trace (status %s)", code)
|
|
@@ -919,7 +985,12 @@ def main() -> int:
|
|
|
919
985
|
# autofill next to the completed run above. No end_time, partial trajectory,
|
|
920
986
|
# status in_progress → serve renders the "running" notebook. Left unstamped
|
|
921
987
|
# (a live run predates any deployment link).
|
|
922
|
-
code, _ = _post(
|
|
988
|
+
code, _ = _post(
|
|
989
|
+
endpoint,
|
|
990
|
+
"/api/v1/traces/batch",
|
|
991
|
+
[_declare_program(_notebook_trace_in_progress(now), district_counter_id)],
|
|
992
|
+
api_key,
|
|
993
|
+
)
|
|
923
994
|
log.info("seeded in-progress RLM notebook trace (status %s)", code)
|
|
924
995
|
|
|
925
996
|
# 4b) Plant the two CMP-187 tool-span demo traces so every review app
|
|
@@ -930,26 +1001,32 @@ def main() -> int:
|
|
|
930
1001
|
tool_demos: list[dict] = []
|
|
931
1002
|
if _SOURCE_CATEGORIZER_FIXTURE.exists():
|
|
932
1003
|
tool_demos.append(
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
1004
|
+
_declare_program(
|
|
1005
|
+
_replay_flat_fixture(
|
|
1006
|
+
_SOURCE_CATEGORIZER_FIXTURE,
|
|
1007
|
+
now,
|
|
1008
|
+
"RLM",
|
|
1009
|
+
_SEED_TAGS + ["tool-demo"],
|
|
1010
|
+
"vector_pdf source_table/glenn-pdf-p15.pdf (page 1)",
|
|
1011
|
+
"candidate_columns, precinct",
|
|
1012
|
+
),
|
|
1013
|
+
_ensure_program(endpoint, api_key, _PROGRAM_SOURCE_CATEGORIZER),
|
|
940
1014
|
)
|
|
941
1015
|
)
|
|
942
1016
|
else:
|
|
943
1017
|
log.warning("skipping SourceCategorizer seed: fixture missing at %s", _SOURCE_CATEGORIZER_FIXTURE)
|
|
944
1018
|
if _TOOL_KIND_DEMO_FIXTURE.exists():
|
|
945
1019
|
tool_demos.append(
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
1020
|
+
_declare_program(
|
|
1021
|
+
_replay_flat_fixture(
|
|
1022
|
+
_TOOL_KIND_DEMO_FIXTURE,
|
|
1023
|
+
now,
|
|
1024
|
+
"ToolKindDemo",
|
|
1025
|
+
_SEED_TAGS + ["tool-demo"],
|
|
1026
|
+
"espresso place review (function-tool + module-tool)",
|
|
1027
|
+
"The speaker loved the new downtown espresso place and its incredible pastries.",
|
|
1028
|
+
),
|
|
1029
|
+
_ensure_program(endpoint, api_key, _PROGRAM_TOOL_KIND_DEMO),
|
|
953
1030
|
)
|
|
954
1031
|
)
|
|
955
1032
|
else:
|
|
@@ -959,13 +1036,16 @@ def main() -> int:
|
|
|
959
1036
|
# the committee — the tool-span ReAct exemplar the golden-path demo lacked.
|
|
960
1037
|
if _REACT_COMMITTEE_FIXTURE.exists():
|
|
961
1038
|
tool_demos.append(
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
1039
|
+
_declare_program(
|
|
1040
|
+
_replay_flat_fixture(
|
|
1041
|
+
_REACT_COMMITTEE_FIXTURE,
|
|
1042
|
+
now,
|
|
1043
|
+
"ReAct",
|
|
1044
|
+
_SEED_TAGS + [_GOLDEN_PATH, "react-demo"],
|
|
1045
|
+
"committee fundraising email (ReAct + lookup_disclaimer tool)",
|
|
1046
|
+
"NATIONAL REPUBLICAN SENATORIAL COMMITTEE",
|
|
1047
|
+
),
|
|
1048
|
+
_ensure_program(endpoint, api_key, _PROGRAM_REACT_COMMITTEE),
|
|
969
1049
|
)
|
|
970
1050
|
)
|
|
971
1051
|
else:
|
|
@@ -29,18 +29,13 @@ def _ns(**kw: object) -> argparse.Namespace:
|
|
|
29
29
|
|
|
30
30
|
class TestAssessmentsCliE2E:
|
|
31
31
|
def test_create_list_show_against_live_api(self, server_client, trace_capture):
|
|
32
|
-
# Produce a real trace to assess under a minted program, then read back
|
|
33
|
-
# program hash + a span.
|
|
32
|
+
# Produce a real trace to assess under a minted program, then read back a span.
|
|
34
33
|
with declaring_program("test_assessments_cli") as program_id:
|
|
35
34
|
dspy.Predict("question -> answer")(question="Who represents District 4?")
|
|
36
35
|
flush_and_wait()
|
|
37
36
|
trace_id = trace_capture.last_trace_id
|
|
38
37
|
assert trace_id is not None, "no trace captured"
|
|
39
38
|
data = server_client.get_trace(trace_id)
|
|
40
|
-
# The trace API returns the hash as a signed int64 (decimal); the
|
|
41
|
-
# assessments and modules APIs speak the 16-hex display form. Normalize
|
|
42
|
-
# so the create/list calls and the assertion compare like for like.
|
|
43
|
-
program_hash = format(int(data["trace"]["program_signature_hash"]) & 0xFFFFFFFFFFFFFFFF, "016x")
|
|
44
39
|
assert data["spans"], "trace has no spans to annotate"
|
|
45
40
|
span_id = data["spans"][0]["span_id"]
|
|
46
41
|
|
|
@@ -62,9 +57,9 @@ class TestAssessmentsCliE2E:
|
|
|
62
57
|
)
|
|
63
58
|
assert created["id"].startswith("as_")
|
|
64
59
|
assert created["conclusion"] == "down"
|
|
65
|
-
# The
|
|
66
|
-
|
|
67
|
-
assert
|
|
60
|
+
# The assessment names the trace's program by its id, never by a signature hash.
|
|
61
|
+
assert created["program_id"] == program_id
|
|
62
|
+
assert "program_signature_hash" not in created
|
|
68
63
|
anns = {(a["kind"], a["ref"]): a for a in created["annotations"]}
|
|
69
64
|
assert ("span", span_id) in anns
|
|
70
65
|
assert ("output", "/answer") in anns
|
|
@@ -219,7 +219,6 @@ class TestDeployBadImportRejected:
|
|
|
219
219
|
create_resp = client.post(
|
|
220
220
|
f"{config.endpoint}/api/v1/deployments",
|
|
221
221
|
json={
|
|
222
|
-
"program_signature_hash": 0,
|
|
223
222
|
"declared_content_length": len(zip_bytes),
|
|
224
223
|
"program_id": program_id_for(f"test_deploy_programs-{uuid.uuid4().hex[:8]}"),
|
|
225
224
|
# A worker that spends egress tokens needs the model a token names, so
|