cmpnd 0.70.0__tar.gz → 0.72.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.70.0 → cmpnd-0.72.0}/PKG-INFO +1 -1
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/cli/__init__.py +2 -9
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/cli/commands/admin.py +1 -2
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/cli/commands/deployments.py +3 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/client.py +23 -23
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/execution.py +22 -1
- {cmpnd-0.70.0 → cmpnd-0.72.0}/docs/cli.md +6 -7
- {cmpnd-0.70.0 → cmpnd-0.72.0}/docs/client.md +5 -8
- {cmpnd-0.70.0 → cmpnd-0.72.0}/docs/sdk-instrumentation.md +8 -1
- {cmpnd-0.70.0 → cmpnd-0.72.0}/pyproject.toml +1 -1
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cli/test_deployment_runs.py +34 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cli/test_main.py +22 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cli/test_parity.py +10 -5
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_client.py +27 -16
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_client_program_names.py +0 -2
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_deployment_runs.py +68 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_program_id_deprecation.py +0 -1
- {cmpnd-0.70.0 → cmpnd-0.72.0}/uv.lock +1 -1
- {cmpnd-0.70.0 → cmpnd-0.72.0}/.gitignore +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/AGENTS.md +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/CLAUDE.md +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/README.md +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/__init__.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/_assessments.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/_authored_import.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/_deployments.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/_exporter_pool.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/_gepa_patch.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/_http.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/_program_patch.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/_rlm_patch.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/_runtime_tools.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/_timespec.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/_traces.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/_valsets.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/authored.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/callback.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/cli/api_client.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/cli/commands/__init__.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/cli/commands/assessments.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/cli/commands/auth.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/cli/commands/datasets.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/cli/commands/evals.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/cli/commands/login.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/cli/commands/optimizations.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/cli/commands/org.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/cli/commands/programs.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/cli/commands/provider_credentials.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/cli/commands/tool_servers.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/cli/commands/top.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/cli/commands/traces.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/cli/commands/valsets.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/cli/credentials.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/cli/deprecation.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/cli/pagination.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/cli/shell.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/cli/trace_render.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/cli/tree_help.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/cli/verbs.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/cli/views.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/configuration.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/context.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/credentials.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/dataset_sync.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/datasets.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/decorators.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/deployment.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/deployment_metadata.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/deployment_runs.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/eval_handler.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/exporter.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/exporter_http.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/helpers.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/identity.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/imaging.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/ir/__init__.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/ir/decode.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/ir/encode.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/ir/hash.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/ir/program.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/ir/reflection.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/ir/types.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/ir/xxh64.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/lm_configuration.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/mcp_servers.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/models.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/named_programs.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/optimization.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/optimizers/__init__.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/optimizers/gepa.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/optimizers/gepa_callback.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/optimizers/resume.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/optimizers/tracker.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/packaging.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/programs.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/references.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/retry.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/cmpnd/traces.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/docs/2026-04-02-code-review.md +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/docs/custom-proposer.md +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/docs/plans/2026-04-05-train-val-dataset-capture-design.md +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/docs/plans/2026-04-05-train-val-dataset-capture.md +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/docs/reading-traces.md +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/examples/generalizing_proposer.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/examples/local_ollama.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/ingest/LINEAGE.md +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/ingest/README.md +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/ingest/cmpnd_ingest/__init__.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/ingest/cmpnd_ingest/bodies.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/ingest/cmpnd_ingest/client_floor.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/ingest/cmpnd_ingest/exporter_http.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/ingest/cmpnd_ingest/program_names.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/ingest/cmpnd_ingest/protocols.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/ingest/cmpnd_ingest/py.typed +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/ingest/cmpnd_ingest/request_log.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/ingest/cmpnd_ingest/retry.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/ingest/cmpnd_ingest/trace_facts.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/ingest/pyproject.toml +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/scripts/audit-sdist.sh +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/scripts/capture_review_run.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/scripts/check-pip-install.sh +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/scripts/check_release_artifacts.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/scripts/fixtures/review_run.json.gz +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/scripts/gepa_resume_bug.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/scripts/install-test-env.sh +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/scripts/release-gate.sh +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/scripts/release-real-models.sh +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/scripts/require_version_bump.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/scripts/seed_review_run.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/scripts/selfhost_compat.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/scripts/test-in-linux.sh +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/stubs/dspy/__init__.pyi +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/stubs/dspy/primitives/__init__.pyi +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/stubs/dspy/primitives/prediction.pyi +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/stubs/dspy/utils/__init__.pyi +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/stubs/dspy/utils/callback.pyi +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/stubs/dspy/utils/dummies.pyi +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/__init__.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/_credential_route.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/_deployment_signature_helpers.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/_exporter_helpers.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/_fake_clock.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/_identity_helpers.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/_resolve_refs.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/_traced_run.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/conftest.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/__init__.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/committee_task.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/conftest.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/continuation_task.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/data/committee_train.ndjson.gz +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/data/committee_val.ndjson.gz +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/fake_lm.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/helpers.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/target_capabilities.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_assessments_cli.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_capture_prompts.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_composite_module.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_dataset_auto_creation.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_deploy_execute.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_deploy_pandas.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_deploy_programs.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_edge_cases.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_example_hash.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_gepa_optimization.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_interpreter_spans.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_lm_accuracy.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_module_tracing.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_optimization_lineage.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_optimization_metric_identity.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_optimize_authored_metric.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_optimize_continuation.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_optimize_custom_proposer.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_optimize_failures.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_optimize_loop.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_optimize_review_committee.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_optimize_server_owned_completion.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_parallel_export.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_project_attribution.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_react_tool_spans.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_save_load.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_trace_structure.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_traces_read.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_user_attribution.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/e2e/test_valsets_cli.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/identity_vectors/01_predict_qa.json +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/identity_vectors/02_predict_renamed_field.json +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/identity_vectors/03_chain_of_thought_qa.json +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/identity_vectors/04_predict_richer_types.json +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/identity_vectors/05_composite_two_predicts.json +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/identity_vectors/06_multichaincomparison.json +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/identity_vectors/07_program_of_thought.json +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/identity_vectors/08_opaque_module.json +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/identity_vectors/09_predict_pydantic_field.json +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/identity_vectors/10_react.json +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/identity_vectors/11_refine.json +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/identity_vectors/12_retrieve.json +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/identity_vectors/13_knn.json +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/identity_vectors/14_parallel.json +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/identity_vectors/README.md +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/ingest_conformance.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/integration/__init__.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/integration/authored_optimize/judge.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/integration/authored_optimize/optimize_hosted.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/integration/conftest.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/integration/hosted_mcp_tool_optimize_probe.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/integration/hosted_optimize_probe.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/integration/optimization_run_probe.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/integration/test_cli_deploy_smoketest.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/integration/test_logs_renders_traces.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/integration/test_optimization_run.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/integration/test_optimizing_progress.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/integration/test_unhappy_path.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/load/__init__.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/load/__main__.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/load/drain.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/load/ingest.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/load/latency_transport.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/load/rlm_shape.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/load/rlm_size_report.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/load/sweep.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/load/test_rlm_shape.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/load/test_rlm_size_report.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/parity/__init__.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/parity/conftest.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/parity/seed_parity.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/parity/test_auth.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/parity/test_datasets.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/parity/test_deployments.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/parity/test_evals.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/parity/test_health.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/parity/test_modules.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/parity/test_optimizations.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/parity/test_programs.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/parity/test_signatures.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/parity/test_trace_streaming.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/parity/test_traces.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/real_models/__init__.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/real_models/_provider.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/real_models/_readiness.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/real_models/_reliability.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/real_models/_result.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/real_models/mint_bedrock_token.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/real_models/test_bedrock_converse.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/real_models/test_deploy_programs.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/real_models/test_multi_client_stress.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/real_models/test_optimize_client_committee.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/real_models/test_optimize_continuation.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/real_models/test_optimize_loop.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/real_models/test_optimize_loop_wasm.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/real_models/test_optimize_stress.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/real_models/test_provider_roles.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/real_models/test_readiness.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/real_models/test_real_provider_twins.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/real_models/test_reliability.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/real_models/test_reliability_classify.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/real_models/test_rlm_wasm.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/real_models/test_trace_search.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/span_reference_fixture.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_adapter_reentrancy.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_assessments_api.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_authored.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_authored_binding_credentials.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_authored_bundle_collisions.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_authored_metric_contract.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_authored_named_models.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_authored_optimize.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_callback.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_candidate_lineage.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cli/__init__.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cli/conftest.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cli/test_admin.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cli/test_api_client.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cli/test_assessments.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cli/test_auth.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cli/test_credentials.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cli/test_datasets.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cli/test_deployments.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cli/test_evals.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cli/test_login.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cli/test_optimizations.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cli/test_org.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cli/test_pagination.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cli/test_programs.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cli/test_provider_credentials.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cli/test_schema_sample.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cli/test_shell.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cli/test_tool_servers.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cli/test_top.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cli/test_traces.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cli/test_traces_program_and_module.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cli/test_traces_search_wire.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cli/test_tree_help.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cli/test_valsets.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_client_floor.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_clustering/__init__.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_clustering/conftest.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_clustering/test_edge_cases.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_clustering/test_hash_consistency.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_clustering/test_type_conversion.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_cmp551_grouping_identity.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_configuration.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_context.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_context_propagation.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_credential_kwargs.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_credential_selection.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_credential_values.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_dataset_polling.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_dataset_sync.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_datasets.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_decision_client_spans.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_decorators.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_deploy.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_deploy_mcp_tool_references.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_deploy_program_id.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_deployment_metadata.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_deployments_read.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_eval.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_eval_example_attribution.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_eval_program_id.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_eval_start.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_eval_trace_grouping.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_exception_paths.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_execute.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_execute_run_identity.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_exporter.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_exporter_program_names.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_exporter_queue.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_exporter_real.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_fake_lm.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_gepa_callback.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_gepa_integration.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_gepa_output_normalization.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_gepa_resume.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_identity.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_imaging.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_import_weight.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_ingest_conformance.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_ingest_second_producer.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_integration.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_interpreter_callback.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_ir_encoder_properties.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_ir_golden_vectors.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_ir_roundtrip.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_lm15_native_calls.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_lm_configuration.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_lm_usage_shapes.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_mcp_tools.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_models.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_multi_client_stress_readiness.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_optimization_progress.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_optimization_start.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_optimize.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_optimize_budget.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_optimize_lift.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_optimize_lms.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_optimize_proposer.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_optimize_reflection_lm.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_optimize_terminal_failure.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_packaging.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_packaging_callable_source.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_packaging_mcp_tools.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_packaging_program_source.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_poll_until.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_program_identity.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_program_lineage_persist.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_program_names_in_deploy.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_programs_create.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_project_payload.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_real_provider_twins_readiness.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_reflector_properties.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_reflector_smoke.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_release_gate_script.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_release_real_models_script.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_replaced_names.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_repro_reactv2_bugs.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_require_version_bump.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_retry.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_reversible_failures.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_rlm_patch.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_run_attribution_paths.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_runtime_tools.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_schemas.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_seal_lm_credential.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_seed_review_run.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_signature_inputs.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_span_references.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_span_sent_once.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_system_one.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_trace_context_concurrency.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_trace_fact_wire_contract.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_trace_facts.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_trace_render.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_traces_read.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_tracked_gepa.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_tracker_enrich.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_truncation.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_upload_auth_headers.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_valsets_api.py +0 -0
- {cmpnd-0.70.0 → cmpnd-0.72.0}/tests/test_xxh64.py +0 -0
|
@@ -171,15 +171,8 @@ def main() -> None:
|
|
|
171
171
|
evals.register(subparsers)
|
|
172
172
|
datasets.register(subparsers)
|
|
173
173
|
deployments.register(subparsers)
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
# CMPND_CLI_DEV=1 (mirroring the CMPND_CLI_ADMIN gate above). The env var
|
|
177
|
-
# only hides the commands from customers; the server still gates each action
|
|
178
|
-
# on the assessments:* / valsets:* scope, so this is discoverability, not
|
|
179
|
-
# enforcement.
|
|
180
|
-
if os.environ.get("CMPND_CLI_DEV") == "1":
|
|
181
|
-
assessments.register(subparsers)
|
|
182
|
-
valsets.register(subparsers)
|
|
174
|
+
assessments.register(subparsers)
|
|
175
|
+
valsets.register(subparsers)
|
|
183
176
|
|
|
184
177
|
# Top-level Docker-style shortcuts (human-readable by default; --json opts in)
|
|
185
178
|
top.register(subparsers)
|
|
@@ -14,8 +14,7 @@ default limits and feature flags, and `cmpnd admin signup …` sets who may sign
|
|
|
14
14
|
and the plan a new account's org lands on. `cmpnd admin feature-flags …` reads and
|
|
15
15
|
toggles the server's runtime flags. These hit
|
|
16
16
|
/api/v1/admin/* and require an API key carrying the admin:* scopes — the server
|
|
17
|
-
is the real authority. The CMPND_CLI_ADMIN env gate
|
|
18
|
-
only keeps these out of customers' --help; it grants nothing.
|
|
17
|
+
is the real authority. The CMPND_CLI_ADMIN env gate only keeps these out of customers' --help; it grants nothing.
|
|
19
18
|
"""
|
|
20
19
|
|
|
21
20
|
from __future__ import annotations
|
|
@@ -191,6 +191,9 @@ def submit_cli_run(
|
|
|
191
191
|
raise
|
|
192
192
|
except httpx.HTTPStatusError as exc:
|
|
193
193
|
raise _http_refusal(exc) from exc
|
|
194
|
+
trace_id = settled.get("trace_id")
|
|
195
|
+
if isinstance(trace_id, str) and trace_id:
|
|
196
|
+
print(f"Trace: {trace_id}", file=sys.stderr)
|
|
194
197
|
if settled["status"] == "failed":
|
|
195
198
|
return settled, None
|
|
196
199
|
result = settled.get("result")
|
|
@@ -17,10 +17,6 @@ and propagates to its own eval / parallel threads. It registers nothing global
|
|
|
17
17
|
and holds no OS resource: exporters are pooled by credentials at module scope
|
|
18
18
|
(:mod:`cmpnd._exporter_pool`), so a client may fall out of scope with nothing to
|
|
19
19
|
release. ``close()`` is an optional alias for end-of-scope flushing.
|
|
20
|
-
|
|
21
|
-
The assessment and valset calls are in development. Each raises unless
|
|
22
|
-
``CMPND_CLI_DEV=1`` is set, the switch that hides the in-development
|
|
23
|
-
``cmpnd assessments`` and ``cmpnd valsets`` CLI groups. Tracing needs no flag.
|
|
24
20
|
"""
|
|
25
21
|
|
|
26
22
|
from __future__ import annotations
|
|
@@ -111,15 +107,6 @@ class Client:
|
|
|
111
107
|
if not self._active:
|
|
112
108
|
raise RuntimeError("client is closed; create a new cmpnd.Client")
|
|
113
109
|
|
|
114
|
-
def _check_in_development(self, method: str) -> None:
|
|
115
|
-
"""Refuse an assessment or valset call unless ``CMPND_CLI_DEV=1`` is set."""
|
|
116
|
-
if os.getenv("CMPND_CLI_DEV") != "1":
|
|
117
|
-
raise RuntimeError(
|
|
118
|
-
f"cmpnd.Client.{method}() is in development and not yet generally available. "
|
|
119
|
-
"Set CMPND_CLI_DEV=1 to enable it."
|
|
120
|
-
)
|
|
121
|
-
self._check_active()
|
|
122
|
-
|
|
123
110
|
def _scoped_callbacks(self) -> list[Any]:
|
|
124
111
|
"""This client's callback, plus the caller's own non-cmpnd callbacks.
|
|
125
112
|
|
|
@@ -403,6 +390,19 @@ class Client:
|
|
|
403
390
|
|
|
404
391
|
return execution.deployment_run_id(result_or_error)
|
|
405
392
|
|
|
393
|
+
def get_trace_id(self, result_or_error: Any) -> str | None:
|
|
394
|
+
"""The root trace id of a ``run_deployment`` prediction or exception.
|
|
395
|
+
|
|
396
|
+
It reads the id serve returned with the settled run and sends no
|
|
397
|
+
request. ``get_trace`` opens the trace.
|
|
398
|
+
The id lives outside the prediction's output fields. A run that stored no
|
|
399
|
+
trace, a server that names none, and a failure before serve accepted a run
|
|
400
|
+
all return ``None``.
|
|
401
|
+
"""
|
|
402
|
+
from . import execution
|
|
403
|
+
|
|
404
|
+
return execution.get_trace_id(result_or_error)
|
|
405
|
+
|
|
406
406
|
def submit_deployment_run(
|
|
407
407
|
self,
|
|
408
408
|
deployment_or_id: Any,
|
|
@@ -918,7 +918,7 @@ class Client:
|
|
|
918
918
|
e.g. ``annotations=[("output", "/trends/2", "the third trend"),
|
|
919
919
|
("span", "a1b2c3", "wrong field")]``.
|
|
920
920
|
"""
|
|
921
|
-
self.
|
|
921
|
+
self._check_active()
|
|
922
922
|
_exporter_pool.flush(self._config) # the referenced trace must be durable first
|
|
923
923
|
return _assessments.create(
|
|
924
924
|
trace_id,
|
|
@@ -937,7 +937,7 @@ class Client:
|
|
|
937
937
|
Pass exactly one of ``program`` (all of that program's assessments, named by
|
|
938
938
|
its name or ``p_`` id) or ``trace_id`` (one trace's assessments).
|
|
939
939
|
"""
|
|
940
|
-
self.
|
|
940
|
+
self._check_active()
|
|
941
941
|
if program is not None and trace_id is not None:
|
|
942
942
|
raise ValueError("pass exactly one of program or trace_id")
|
|
943
943
|
page = _assessments.list(
|
|
@@ -952,24 +952,24 @@ class Client:
|
|
|
952
952
|
|
|
953
953
|
def get_assessment(self, assessment_id: str) -> dict[str, Any]:
|
|
954
954
|
"""Fetch one assessment with its annotations."""
|
|
955
|
-
self.
|
|
955
|
+
self._check_active()
|
|
956
956
|
return _assessments.get(assessment_id, api_key=self._config.api_key, endpoint=self._config.endpoint)
|
|
957
957
|
|
|
958
958
|
def delete_assessment(self, assessment_id: str) -> None:
|
|
959
959
|
"""Delete one assessment. Raises if it does not exist."""
|
|
960
|
-
self.
|
|
960
|
+
self._check_active()
|
|
961
961
|
_assessments.delete(assessment_id, api_key=self._config.api_key, endpoint=self._config.endpoint)
|
|
962
962
|
|
|
963
963
|
def create_valset(self, program: str, *, name: str | None = None) -> dict[str, Any]:
|
|
964
964
|
"""Create a valset owned by ``program``, a program name or ``p_`` id; name auto-assigned when omitted."""
|
|
965
|
-
self.
|
|
965
|
+
self._check_active()
|
|
966
966
|
return _valsets.create(
|
|
967
967
|
self._program_id(program), name=name, api_key=self._config.api_key, endpoint=self._config.endpoint
|
|
968
968
|
)
|
|
969
969
|
|
|
970
970
|
def list_valsets(self, program: str, *, limit: int = 50, offset: int = 0) -> list[dict[str, Any]]:
|
|
971
971
|
"""The valsets of ``program``, a program name or ``p_`` id, newest first (paged by limit/offset)."""
|
|
972
|
-
self.
|
|
972
|
+
self._check_active()
|
|
973
973
|
page = _valsets.list(
|
|
974
974
|
self._program_id(program),
|
|
975
975
|
limit=limit,
|
|
@@ -981,12 +981,12 @@ class Client:
|
|
|
981
981
|
|
|
982
982
|
def get_valset(self, valset_id: str) -> dict[str, Any]:
|
|
983
983
|
"""Fetch one valset with its field shape and current version."""
|
|
984
|
-
self.
|
|
984
|
+
self._check_active()
|
|
985
985
|
return _valsets.get(valset_id, api_key=self._config.api_key, endpoint=self._config.endpoint)
|
|
986
986
|
|
|
987
987
|
def list_valset_entries(self, valset_id: str, *, limit: int = 50, offset: int = 0) -> list[dict[str, Any]]:
|
|
988
988
|
"""A valset's active entries (paged by limit/offset)."""
|
|
989
|
-
self.
|
|
989
|
+
self._check_active()
|
|
990
990
|
page = _valsets.list_entries(
|
|
991
991
|
valset_id, limit=limit, offset=offset, api_key=self._config.api_key, endpoint=self._config.endpoint
|
|
992
992
|
)
|
|
@@ -1002,7 +1002,7 @@ class Client:
|
|
|
1002
1002
|
) -> dict[str, Any]:
|
|
1003
1003
|
"""Add one entry. Pass exactly one of ``from_assessment`` (the server
|
|
1004
1004
|
derives inputs from its trace) or ``inputs``."""
|
|
1005
|
-
self.
|
|
1005
|
+
self._check_active()
|
|
1006
1006
|
return _valsets.create_entry(
|
|
1007
1007
|
valset_id,
|
|
1008
1008
|
expected_outputs=expected_outputs,
|
|
@@ -1014,7 +1014,7 @@ class Client:
|
|
|
1014
1014
|
|
|
1015
1015
|
def delete_valset_entry(self, entry_id: str) -> dict[str, Any]:
|
|
1016
1016
|
"""Retire an entry (versioned, not a hard delete)."""
|
|
1017
|
-
self.
|
|
1017
|
+
self._check_active()
|
|
1018
1018
|
return _valsets.delete_entry(entry_id, api_key=self._config.api_key, endpoint=self._config.endpoint)
|
|
1019
1019
|
|
|
1020
1020
|
def _run_gepa(
|
|
@@ -33,6 +33,21 @@ def deployment_run_id(result_or_error: Any) -> str | None:
|
|
|
33
33
|
return getattr(result_or_error, "_cmpnd_deployment_run_id", None)
|
|
34
34
|
|
|
35
35
|
|
|
36
|
+
def get_trace_id(result_or_error: Any) -> str | None:
|
|
37
|
+
"""Return the root trace id serve named for a run's prediction or exception.
|
|
38
|
+
|
|
39
|
+
The id lives outside the prediction's program output fields. A run that
|
|
40
|
+
stored no trace, a server that names none, and a failure before serve
|
|
41
|
+
accepted a run all return ``None``.
|
|
42
|
+
"""
|
|
43
|
+
return getattr(result_or_error, "_cmpnd_deployment_trace_id", None)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _settled_trace_id(settled: dict[str, Any]) -> str | None:
|
|
47
|
+
trace_id = settled.get("trace_id")
|
|
48
|
+
return trace_id if isinstance(trace_id, str) and trace_id else None
|
|
49
|
+
|
|
50
|
+
|
|
36
51
|
def _with_run_id(error: Exception, run_id: str | None) -> Exception:
|
|
37
52
|
error._cmpnd_deployment_run_id = run_id # pyright: ignore[reportAttributeAccessIssue]
|
|
38
53
|
return error
|
|
@@ -247,14 +262,20 @@ def run_deployment(
|
|
|
247
262
|
raise
|
|
248
263
|
|
|
249
264
|
settled_id: str = settled["deployment_run_id"]
|
|
265
|
+
trace_id = _settled_trace_id(settled)
|
|
250
266
|
result = settled["result"]
|
|
251
267
|
if settled["status"] == "failed":
|
|
252
|
-
|
|
268
|
+
try:
|
|
269
|
+
_raise_stored_failure(settled_id, result, config.endpoint)
|
|
270
|
+
except Exception as error:
|
|
271
|
+
error._cmpnd_deployment_trace_id = trace_id # pyright: ignore[reportAttributeAccessIssue]
|
|
272
|
+
raise
|
|
253
273
|
if not isinstance(result, dict) or "output" not in result:
|
|
254
274
|
raise _with_run_id(RuntimeError("Deployment run result has no program output"), settled_id)
|
|
255
275
|
output = result["output"]
|
|
256
276
|
prediction = Prediction(**output) if isinstance(output, dict) else Prediction(**{"output": output})
|
|
257
277
|
setattr(prediction, "_cmpnd_deployment_run_id", settled_id)
|
|
278
|
+
setattr(prediction, "_cmpnd_deployment_trace_id", trace_id)
|
|
258
279
|
return prediction
|
|
259
280
|
|
|
260
281
|
|
|
@@ -228,6 +228,10 @@ seconds, unless `--timeout` sets the budget. The CLI prints the accepted run ID
|
|
|
228
228
|
on stderr as soon as serve replies, which can take up to serve's five-second
|
|
229
229
|
wait. A failed run exits nonzero. Human mode prints the stored error code,
|
|
230
230
|
message and provider status. `--json` prints the whole settled run on stdout.
|
|
231
|
+
When a settled run names its root trace, the CLI prints `Trace: <id>` on
|
|
232
|
+
stderr, completed or failed. `cmpnd traces show <id>` opens that trace. The
|
|
233
|
+
run's `trace_id` field holds the same ID, and serve leaves it out when the run
|
|
234
|
+
stored no trace.
|
|
231
235
|
The CLI retries status reads that time out or answer `408`, `429` or `5xx`
|
|
232
236
|
within the budget.
|
|
233
237
|
|
|
@@ -418,10 +422,7 @@ down or neutral conclusion, an optional prose body and annotations. An
|
|
|
418
422
|
annotation attaches a note to a span or to a piece of the output addressed by
|
|
419
423
|
a JSON pointer.
|
|
420
424
|
|
|
421
|
-
|
|
422
|
-
`CMPND_CLI_DEV=1` is set, so it does not appear in `cmpnd --help`. The
|
|
423
|
-
variable only hides the commands. Serve still checks each action against the
|
|
424
|
-
`assessments:*` scopes.
|
|
425
|
+
Serve checks each action against the `assessments:*` scopes.
|
|
425
426
|
|
|
426
427
|
- `cmpnd assessments create <trace-id> [--up|--down|--neutral] [-m "prose"]
|
|
427
428
|
[--annotate KIND REF NOTE …]` records one judgement.
|
|
@@ -534,9 +535,7 @@ that lookup, so it creates a valset by the program's name. On a server from befo
|
|
|
534
535
|
name fails with an error that says to upgrade the server. Entries live in an
|
|
535
536
|
`entries` subgroup, the same shape as `cmpnd datasets examples`.
|
|
536
537
|
|
|
537
|
-
|
|
538
|
-
`CMPND_CLI_DEV=1` is set. Serve still checks each action against the
|
|
539
|
-
`valsets:*` scopes.
|
|
538
|
+
Serve checks each action against the `valsets:*` scopes.
|
|
540
539
|
|
|
541
540
|
- `cmpnd valsets create <program> [--name <name>]` creates a validation
|
|
542
541
|
set for a program. The valset ID is its identity, and the name is a label
|
|
@@ -10,11 +10,6 @@ client methods too, and have no form outside a client. A client holds its own ta
|
|
|
10
10
|
the global config that `auto_instrument()` reads, so both can run in one
|
|
11
11
|
process.
|
|
12
12
|
|
|
13
|
-
The client's assessment and valset calls are in development. Each one raises
|
|
14
|
-
`RuntimeError` unless `CMPND_CLI_DEV=1` is set. The same variable reveals the
|
|
15
|
-
in-development `cmpnd assessments` and `cmpnd valsets` CLI groups. Tracing
|
|
16
|
-
through a client needs no flag.
|
|
17
|
-
|
|
18
13
|
## Entry point
|
|
19
14
|
|
|
20
15
|
```python
|
|
@@ -152,7 +147,9 @@ endpoint. None of these reads the global config:
|
|
|
152
147
|
- `sdk.submit_deployment_run`, `list_deployment_runs`, `get_deployment_run`,
|
|
153
148
|
`get_deployment_run_result` and `wait_deployment_run` submit, find and resume
|
|
154
149
|
runs without waiting in one call. `sdk.deployment_run_id(result)` reads the run
|
|
155
|
-
id of a prediction or an exception.
|
|
150
|
+
id of a prediction or an exception. `sdk.get_trace_id(result)` reads the
|
|
151
|
+
id of the run's root trace the same way, or returns `None` when serve named no
|
|
152
|
+
trace.
|
|
156
153
|
- `sdk.optimize_deployment(deployment, optimizer="gepa", ...)` runs the
|
|
157
154
|
platform's optimization on a deployment and returns the best
|
|
158
155
|
`DeployedProgram`, with `.score`. It never deploys. The program's model comes
|
|
@@ -218,12 +215,12 @@ methods:
|
|
|
218
215
|
file the deployment stores, or the archive-relative file `path` names.
|
|
219
216
|
`sdk.get_deployment_signature(deployment_id)` returns the selected
|
|
220
217
|
artifact's typed metadata. It reads no worker status or executions.
|
|
221
|
-
- Assessments
|
|
218
|
+
- Assessments:
|
|
222
219
|
`sdk.create_assessment(trace_id, conclusion=..., body=...,
|
|
223
220
|
annotations=...)`, `sdk.list_assessments(program=... | trace_id=...,
|
|
224
221
|
limit=..., offset=...)`, `sdk.get_assessment(assessment_id)` and
|
|
225
222
|
`sdk.delete_assessment(assessment_id)`.
|
|
226
|
-
- Valsets
|
|
223
|
+
- Valsets:
|
|
227
224
|
`sdk.create_valset(program, name=...)`, `sdk.list_valsets(program,
|
|
228
225
|
limit=..., offset=...)`, `sdk.get_valset(valset_id)`,
|
|
229
226
|
`sdk.list_valset_entries(valset_id, limit=..., offset=...)`,
|
|
@@ -432,7 +432,12 @@ command, and re-raises.
|
|
|
432
432
|
`client.deployment_run_id(result)` reads the ID from
|
|
433
433
|
private prediction metadata, so a program can use `output` or
|
|
434
434
|
`deployment_run_id` as an output field. The accessor also accepts a stored
|
|
435
|
-
execution error, a refused read, `RunWaitTimeout` and `RunResultExpired`.
|
|
435
|
+
execution error, a refused read, `RunWaitTimeout` and `RunResultExpired`.
|
|
436
|
+
`client.get_trace_id(result)` reads the id of the run's root trace from
|
|
437
|
+
the same metadata, for a completed run's prediction and a failed run's error.
|
|
438
|
+
`cmpnd traces show` opens that trace. It returns `None` when the run stored no
|
|
439
|
+
trace, when the server names none, and when the run failed before serve
|
|
440
|
+
accepted it. A
|
|
436
441
|
retained provider failure keeps its structured `RetryableProviderError` type but
|
|
437
442
|
does not start another run. Trace delivery can finish after the result is
|
|
438
443
|
available.
|
|
@@ -454,8 +459,10 @@ header readable.
|
|
|
454
459
|
try:
|
|
455
460
|
result = client.run_deployment(deployed, question="What changed?")
|
|
456
461
|
run_id = client.deployment_run_id(result)
|
|
462
|
+
trace_id = client.get_trace_id(result)
|
|
457
463
|
except Exception as error:
|
|
458
464
|
run_id = client.deployment_run_id(error)
|
|
465
|
+
trace_id = client.get_trace_id(error)
|
|
459
466
|
raise
|
|
460
467
|
```
|
|
461
468
|
|
|
@@ -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.72.0"
|
|
9
9
|
description = "DSPy observability and deployment SDK for cmpnd"
|
|
10
10
|
readme = "README.md"
|
|
11
11
|
requires-python = ">=3.11"
|
|
@@ -537,3 +537,37 @@ def test_json_run_commands_do_not_import_dspy(argv: list[str], replies: list):
|
|
|
537
537
|
assert "JSON run command imported dspy" not in result.stderr
|
|
538
538
|
out = json.loads(result.stdout)
|
|
539
539
|
assert RUN_ID in result.stdout or "yes" in json.dumps(out)
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
TRACE_ID = "0b9c6f2e-4f1d-4c3a-9e2b-7a1d5c3e8f00"
|
|
543
|
+
|
|
544
|
+
|
|
545
|
+
def test_failed_run_names_its_trace_on_stderr(monkeypatch: pytest.MonkeyPatch, capsys):
|
|
546
|
+
failure = {"error": {"type": "ProgramError", "message": "bad input"}, "execution_status": 500}
|
|
547
|
+
|
|
548
|
+
def answer(req):
|
|
549
|
+
return httpx.Response(200, json={**_envelope("failed", failure), "trace_id": TRACE_ID}, request=req)
|
|
550
|
+
|
|
551
|
+
with pytest.raises(SystemExit):
|
|
552
|
+
_run_cli(monkeypatch, ["run", DEPLOYMENT_ID, "{}"], answer)
|
|
553
|
+
assert f"Trace: {TRACE_ID}" in capsys.readouterr().err
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
def test_completed_run_names_its_trace_on_stderr_and_keeps_stdout_the_output(monkeypatch: pytest.MonkeyPatch, capsys):
|
|
557
|
+
def answer(req):
|
|
558
|
+
return httpx.Response(
|
|
559
|
+
200, json={**_envelope("completed", {"output": {"answer": "yes"}}), "trace_id": TRACE_ID}, request=req
|
|
560
|
+
)
|
|
561
|
+
|
|
562
|
+
_run_cli(monkeypatch, ["run", DEPLOYMENT_ID, "{}", "--json"], answer)
|
|
563
|
+
out = capsys.readouterr()
|
|
564
|
+
assert json.loads(out.out) == {"answer": "yes"}
|
|
565
|
+
assert f"Trace: {TRACE_ID}" in out.err
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
def test_run_without_a_trace_names_none(monkeypatch: pytest.MonkeyPatch, capsys):
|
|
569
|
+
def answer(req):
|
|
570
|
+
return httpx.Response(200, json=_envelope("completed", {"output": {"answer": "yes"}}), request=req)
|
|
571
|
+
|
|
572
|
+
_run_cli(monkeypatch, ["run", DEPLOYMENT_ID, "{}", "--json"], answer)
|
|
573
|
+
assert "Trace:" not in capsys.readouterr().err
|
|
@@ -169,6 +169,28 @@ class TestDevGate:
|
|
|
169
169
|
output = json.loads(captured.out)
|
|
170
170
|
assert "families" in output
|
|
171
171
|
|
|
172
|
+
def test_assessments_works_without_flag(self, capsys):
|
|
173
|
+
env = {k: v for k, v in os.environ.items() if k != "CMPND_CLI_DEV"}
|
|
174
|
+
env["CMPND_API_KEY"] = "test-key"
|
|
175
|
+
mock_response = {"assessments": [], "total": 0}
|
|
176
|
+
with mock.patch("sys.argv", ["cmpnd", "assessments", "list", "--trace", "t_1"]):
|
|
177
|
+
with mock.patch.dict(os.environ, env, clear=True):
|
|
178
|
+
with mock.patch("cmpnd.cli.api_client.ApiClient.get", autospec=True, return_value=mock_response) as get:
|
|
179
|
+
main()
|
|
180
|
+
assert get.call_args.args[1] == "/api/v1/assessments"
|
|
181
|
+
assert json.loads(capsys.readouterr().out) == mock_response
|
|
182
|
+
|
|
183
|
+
def test_valsets_works_without_flag(self, capsys):
|
|
184
|
+
env = {k: v for k, v in os.environ.items() if k != "CMPND_CLI_DEV"}
|
|
185
|
+
env["CMPND_API_KEY"] = "test-key"
|
|
186
|
+
mock_response = {"id": "v_1", "name": "valset-2026-11-02"}
|
|
187
|
+
with mock.patch("sys.argv", ["cmpnd", "valsets", "show", "v_1"]):
|
|
188
|
+
with mock.patch.dict(os.environ, env, clear=True):
|
|
189
|
+
with mock.patch("cmpnd.cli.api_client.ApiClient.get", autospec=True, return_value=mock_response) as get:
|
|
190
|
+
main()
|
|
191
|
+
assert get.call_args.args[1] == "/api/v1/valsets/v_1"
|
|
192
|
+
assert json.loads(capsys.readouterr().out) == mock_response
|
|
193
|
+
|
|
172
194
|
|
|
173
195
|
class TestAdminGate:
|
|
174
196
|
"""CMP-126: `admin` commands gated behind CMPND_CLI_ADMIN=1; the
|
|
@@ -16,7 +16,6 @@ from __future__ import annotations
|
|
|
16
16
|
|
|
17
17
|
import argparse
|
|
18
18
|
import itertools
|
|
19
|
-
import os
|
|
20
19
|
import re
|
|
21
20
|
from pathlib import Path
|
|
22
21
|
from unittest import mock
|
|
@@ -26,6 +25,9 @@ from cmpnd.cli.api_client import ApiClient
|
|
|
26
25
|
from cmpnd.cli.commands import (
|
|
27
26
|
admin as _admin,
|
|
28
27
|
)
|
|
28
|
+
from cmpnd.cli.commands import (
|
|
29
|
+
assessments as _assessments,
|
|
30
|
+
)
|
|
29
31
|
from cmpnd.cli.commands import (
|
|
30
32
|
auth as _auth,
|
|
31
33
|
)
|
|
@@ -59,6 +61,9 @@ from cmpnd.cli.commands import (
|
|
|
59
61
|
from cmpnd.cli.commands import (
|
|
60
62
|
traces as _traces,
|
|
61
63
|
)
|
|
64
|
+
from cmpnd.cli.commands import (
|
|
65
|
+
valsets as _valsets,
|
|
66
|
+
)
|
|
62
67
|
|
|
63
68
|
#: Every module registering a resource-tier noun group. `login` is excluded
|
|
64
69
|
#: deliberately: `login` / `logout` are task-tier top-level commands with no
|
|
@@ -75,6 +80,8 @@ _RESOURCE_MODULES = (
|
|
|
75
80
|
_evals,
|
|
76
81
|
_datasets,
|
|
77
82
|
_deployments,
|
|
83
|
+
_assessments,
|
|
84
|
+
_valsets,
|
|
78
85
|
)
|
|
79
86
|
|
|
80
87
|
|
|
@@ -281,10 +288,8 @@ class TestOptimizeBinding:
|
|
|
281
288
|
partial revival (CLI but not REPL) is the failure worth catching."""
|
|
282
289
|
|
|
283
290
|
def test_optimize_is_bound_on_both_surfaces(self):
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
assert "optimize" in _argparse_subcommands()
|
|
287
|
-
assert "optimize" in _shell_namespace()
|
|
291
|
+
assert "optimize" in _argparse_subcommands()
|
|
292
|
+
assert "optimize" in _shell_namespace()
|
|
288
293
|
|
|
289
294
|
|
|
290
295
|
class TestResourceVocabulary:
|
|
@@ -327,11 +327,11 @@ class TestMisuseGuard:
|
|
|
327
327
|
sdk5.run_program(a_program(), question="What is the capital of France?")
|
|
328
328
|
|
|
329
329
|
|
|
330
|
-
class
|
|
331
|
-
"""The client's
|
|
332
|
-
|
|
330
|
+
class TestAssessmentsAndValsetsNeedNoFlag:
|
|
331
|
+
"""The client's assessment and valset calls need no environment flag. A closed
|
|
332
|
+
client still refuses each one, as it refuses every other call."""
|
|
333
333
|
|
|
334
|
-
|
|
334
|
+
CALLS = {
|
|
335
335
|
"create_assessment": ("t_1",),
|
|
336
336
|
"list_assessments": ("p_0123456789Ab",),
|
|
337
337
|
"get_assessment": ("a_1",),
|
|
@@ -344,23 +344,19 @@ class TestDevelopmentGate:
|
|
|
344
344
|
"delete_valset_entry": ("e_1",),
|
|
345
345
|
}
|
|
346
346
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
sdk = cmpnd.Client(project_tags=["context-Z"], api_key="k", endpoint="http://x")
|
|
350
|
-
assert sdk._active
|
|
351
|
-
|
|
352
|
-
@pytest.mark.parametrize("method", sorted(GATED))
|
|
353
|
-
def test_an_assessment_or_valset_call_refuses_without_the_flag(self, method, monkeypatch: pytest.MonkeyPatch):
|
|
347
|
+
@pytest.mark.parametrize("method", sorted(CALLS))
|
|
348
|
+
def test_a_closed_client_refuses_an_assessment_or_valset_call(self, method, monkeypatch: pytest.MonkeyPatch):
|
|
354
349
|
monkeypatch.delenv("CMPND_CLI_DEV", raising=False)
|
|
355
350
|
sdk = cmpnd.Client(api_key="k", endpoint="http://x")
|
|
351
|
+
sdk.close()
|
|
356
352
|
kwargs = {"expected_outputs": {}} if method == "create_valset_entry" else {}
|
|
357
|
-
with pytest.raises(RuntimeError, match=r"
|
|
358
|
-
getattr(sdk, method)(*self.
|
|
353
|
+
with pytest.raises(RuntimeError, match=r"client is closed"):
|
|
354
|
+
getattr(sdk, method)(*self.CALLS[method], **kwargs)
|
|
359
355
|
|
|
360
|
-
def
|
|
356
|
+
def test_every_assessment_and_valset_method_is_listed(self):
|
|
361
357
|
public = {name for name in dir(cmpnd.Client) if not name.startswith("_")}
|
|
362
358
|
data = {name for name in public if "assessment" in name or "valset" in name}
|
|
363
|
-
assert data == set(self.
|
|
359
|
+
assert data == set(self.CALLS)
|
|
364
360
|
|
|
365
361
|
|
|
366
362
|
# --- Case 7: exceptions and cleanup --------------------------------------
|
|
@@ -794,7 +790,7 @@ class TestClientDataSurface:
|
|
|
794
790
|
client's own credentials, list_* unwrap to lists, and client.traces warns."""
|
|
795
791
|
|
|
796
792
|
def _client(self, monkeypatch):
|
|
797
|
-
monkeypatch.
|
|
793
|
+
monkeypatch.delenv("CMPND_CLI_DEV", raising=False)
|
|
798
794
|
monkeypatch.setattr(cmpnd.client._exporter_pool, "flush", lambda cfg: None)
|
|
799
795
|
return cmpnd.Client(api_key="k", endpoint="http://x")
|
|
800
796
|
|
|
@@ -811,6 +807,21 @@ class TestClientDataSurface:
|
|
|
811
807
|
assert seen["trace_id"] == "t-1" and seen["conclusion"] == "down"
|
|
812
808
|
assert seen["api_key"] == "k" and seen["endpoint"] == "http://x"
|
|
813
809
|
|
|
810
|
+
@pytest.mark.parametrize(
|
|
811
|
+
("method", "module", "function", "ref"),
|
|
812
|
+
[
|
|
813
|
+
("get_assessment", "_assessments", "get", "as_1"),
|
|
814
|
+
("get_valset", "_valsets", "get", "v_1"),
|
|
815
|
+
("delete_valset_entry", "_valsets", "delete_entry", "e_1"),
|
|
816
|
+
],
|
|
817
|
+
)
|
|
818
|
+
def test_a_one_id_call_delegates_with_client_creds(self, method, module, function, ref, monkeypatch):
|
|
819
|
+
fake = mock.create_autospec(getattr(getattr(cmpnd, module), function), return_value={"id": ref})
|
|
820
|
+
monkeypatch.setattr(getattr(cmpnd, module), function, fake)
|
|
821
|
+
|
|
822
|
+
assert getattr(self._client(monkeypatch), method)(ref) == {"id": ref}
|
|
823
|
+
fake.assert_called_once_with(ref, api_key="k", endpoint="http://x")
|
|
824
|
+
|
|
814
825
|
def test_get_deployment_signature_delegates_with_client_creds(self, monkeypatch):
|
|
815
826
|
seen: dict = {}
|
|
816
827
|
answer = object()
|
|
@@ -126,7 +126,6 @@ def _provider():
|
|
|
126
126
|
|
|
127
127
|
@pytest.fixture(autouse=True)
|
|
128
128
|
def _clean_slate(monkeypatch: pytest.MonkeyPatch):
|
|
129
|
-
monkeypatch.delenv("CMPND_CLI_DEV", raising=False) # a client traces with no dev flag
|
|
130
129
|
monkeypatch.delenv("CMPND_PROGRAM_ID", raising=False)
|
|
131
130
|
configuration._config = None
|
|
132
131
|
saved_callbacks = list(dspy.settings.callbacks or [])
|
|
@@ -328,7 +327,6 @@ def minting_server(monkeypatch: pytest.MonkeyPatch):
|
|
|
328
327
|
def _new_client(**kw: Any) -> httpx.Client:
|
|
329
328
|
return real_new_client(transport=httpx.MockTransport(srv.handler), **kw)
|
|
330
329
|
|
|
331
|
-
monkeypatch.setenv("CMPND_CLI_DEV", "1")
|
|
332
330
|
with (
|
|
333
331
|
mock.patch("cmpnd._http.new_client", autospec=True, side_effect=_new_client),
|
|
334
332
|
mock.patch("cmpnd.exporter_http.BatchExporter", autospec=True, side_effect=_factory),
|
|
@@ -505,3 +505,71 @@ def test_failure_summary_names_code_message_and_provider_status():
|
|
|
505
505
|
f"Deployment run {RUN_ID} failed: EgressFailed: provider failed (provider status 429)"
|
|
506
506
|
)
|
|
507
507
|
assert deployment_runs.failure_summary(_run("failed", {"error": "boom"})) == f"Deployment run {RUN_ID} failed: boom"
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
TRACE_ID = "0b9c6f2e-4f1d-4c3a-9e2b-7a1d5c3e8f00"
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
def test_a_completed_run_names_its_trace_beside_its_run_id(monkeypatch: pytest.MonkeyPatch):
|
|
514
|
+
def answer(req: httpx.Request) -> httpx.Response:
|
|
515
|
+
body = {**_run("completed", {"output": {"answer": "yes"}}, available=True), "trace_id": TRACE_ID}
|
|
516
|
+
return httpx.Response(200, json=body, request=req)
|
|
517
|
+
|
|
518
|
+
_transport(monkeypatch, answer)
|
|
519
|
+
prediction = _client().run_deployment(DEPLOYMENT_ID, question="hi")
|
|
520
|
+
assert prediction.answer == "yes"
|
|
521
|
+
assert _client().get_trace_id(prediction) == TRACE_ID
|
|
522
|
+
assert _client().deployment_run_id(prediction) == RUN_ID
|
|
523
|
+
assert "trace_id" not in prediction.keys()
|
|
524
|
+
|
|
525
|
+
|
|
526
|
+
def test_a_failed_run_names_its_trace_on_the_raised_error(monkeypatch: pytest.MonkeyPatch):
|
|
527
|
+
failure = {"error": {"type": "ProgramError", "message": "bad input"}, "execution_status": 500}
|
|
528
|
+
|
|
529
|
+
def answer(req: httpx.Request) -> httpx.Response:
|
|
530
|
+
return httpx.Response(200, json={**_run("failed", failure, available=True), "trace_id": TRACE_ID}, request=req)
|
|
531
|
+
|
|
532
|
+
_transport(monkeypatch, answer)
|
|
533
|
+
with pytest.raises(httpx.HTTPStatusError) as caught:
|
|
534
|
+
_client().run_deployment(DEPLOYMENT_ID)
|
|
535
|
+
assert _client().get_trace_id(caught.value) == TRACE_ID
|
|
536
|
+
assert _client().deployment_run_id(caught.value) == RUN_ID
|
|
537
|
+
|
|
538
|
+
|
|
539
|
+
def test_a_retryable_provider_failure_names_its_trace(monkeypatch: pytest.MonkeyPatch):
|
|
540
|
+
failure = {
|
|
541
|
+
"error": {"type": "EgressFailed", "message": "provider refused"},
|
|
542
|
+
"execution_status": 503,
|
|
543
|
+
"retryable": True,
|
|
544
|
+
"failure": {"domain": "provider", "upstream_status": 429, "attempts": 3},
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
def answer(req: httpx.Request) -> httpx.Response:
|
|
548
|
+
return httpx.Response(200, json={**_run("failed", failure, available=True), "trace_id": TRACE_ID}, request=req)
|
|
549
|
+
|
|
550
|
+
_transport(monkeypatch, answer)
|
|
551
|
+
with pytest.raises(cmpnd.RetryableProviderError) as caught:
|
|
552
|
+
_client().run_deployment(DEPLOYMENT_ID)
|
|
553
|
+
assert _client().get_trace_id(caught.value) == TRACE_ID
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
@pytest.mark.parametrize("trace_field", [{}, {"trace_id": None}, {"trace_id": ""}, {"trace_id": 7}])
|
|
557
|
+
def test_a_run_serve_names_no_trace_for_has_none(monkeypatch: pytest.MonkeyPatch, trace_field: dict):
|
|
558
|
+
def answer(req: httpx.Request) -> httpx.Response:
|
|
559
|
+
body = {**_run("completed", {"output": {"answer": "yes"}}, available=True), **trace_field}
|
|
560
|
+
return httpx.Response(200, json=body, request=req)
|
|
561
|
+
|
|
562
|
+
_transport(monkeypatch, answer)
|
|
563
|
+
prediction = _client().run_deployment(DEPLOYMENT_ID, question="hi")
|
|
564
|
+
assert _client().get_trace_id(prediction) is None
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
def test_a_failure_before_acceptance_has_no_trace(monkeypatch: pytest.MonkeyPatch):
|
|
568
|
+
def answer(req: httpx.Request) -> httpx.Response:
|
|
569
|
+
return httpx.Response(404, json={"error": "not found"}, request=req)
|
|
570
|
+
|
|
571
|
+
_transport(monkeypatch, answer)
|
|
572
|
+
with pytest.raises(httpx.HTTPStatusError) as caught:
|
|
573
|
+
_client().run_deployment(DEPLOYMENT_ID)
|
|
574
|
+
assert _client().get_trace_id(caught.value) is None
|
|
575
|
+
assert _client().get_trace_id(object()) is None
|
|
@@ -44,7 +44,6 @@ def _clean_configuration(monkeypatch):
|
|
|
44
44
|
monkeypatch.delenv("CMPND_PROGRAM_ID", raising=False)
|
|
45
45
|
monkeypatch.delenv("CMPND_API_KEY", raising=False)
|
|
46
46
|
monkeypatch.delenv("CMPND_ENDPOINT", raising=False)
|
|
47
|
-
monkeypatch.delenv("CMPND_CLI_DEV", raising=False) # a client traces with no dev flag
|
|
48
47
|
dspy.settings.configure(lm=None)
|
|
49
48
|
yield
|
|
50
49
|
configuration._config = None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|